**feat: improve TensorFlow.js compatibility and remove unnecessary patches**
- Removed outdated Node.js v24 compatibility patches for `TextEncoder` and `TextDecoder` in `cli-wrapper.js` and other modules since TensorFlow.js now supports Node.js v24+ natively. - Introduced a utility module `src/utils/tensorflowUtils.ts` for TensorFlow.js compatibility, defining global `PlatformNode` and related utilities. - Enhanced `fileSystemStorage.ts` with improved Node.js module loading mechanisms for better compatibility across environments. - Simplified dependency requirements by reducing the minimum Node.js version to `>=23.0.0`. - Updated `package.json`, `cli-package/package.json`, and `README.md` versions to `0.9.25`. - Harmonized `cli-package` and main package dependencies to ensure version alignment. - Improved global compatibility with TensorFlow.js in mixed Node.js environments. This update modernizes TensorFlow.js integration, reduces maintenance efforts, and aligns compatibility with current Node.js and TensorFlow.js capabilities.
This commit is contained in:
parent
16748436d1
commit
eb46d816d7
20 changed files with 428 additions and 168 deletions
5
.gitignore
vendored
5
.gitignore
vendored
|
|
@ -52,3 +52,8 @@ Thumbs.db
|
||||||
/encoded-image.txt
|
/encoded-image.txt
|
||||||
/cli-package/dist/
|
/cli-package/dist/
|
||||||
/cli-package/node_modules/
|
/cli-package/node_modules/
|
||||||
|
/npm
|
||||||
|
/rollup
|
||||||
|
/soulcraft-brainy-0.9.23.tgz
|
||||||
|
/cli-package/soulcraft-brainy-cli-0.9.23.tgz
|
||||||
|
/data/
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,10 @@
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
|
|
||||||
[](LICENSE)
|
[](LICENSE)
|
||||||
[](https://nodejs.org/)
|
[](https://nodejs.org/)
|
||||||
[](https://www.typescriptlang.org/)
|
[](https://www.typescriptlang.org/)
|
||||||
[](CONTRIBUTING.md)
|
[](CONTRIBUTING.md)
|
||||||
[](https://www.npmjs.com/package/@soulcraft/brainy)
|
[](https://www.npmjs.com/package/@soulcraft/brainy)
|
||||||
|
|
||||||
[//]: # ([](https://github.com/sodal-project/cartographer))
|
[//]: # ([](https://github.com/sodal-project/cartographer))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,12 +47,12 @@ brainy generate-random-graph --noun-count 20 --verb-count 30 --clear
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
- Node.js >= 24.0.0
|
- Node.js >= 23.0.0
|
||||||
|
|
||||||
## Changelog
|
## Changelog
|
||||||
|
|
||||||
### 0.9.23
|
### 0.9.25
|
||||||
- Fixed compatibility with Node.js v24 by adding support for the new TextEncoder global object
|
- Completely removed unnecessary compatibility patches for Node.js v24 as they are no longer needed with current TensorFlow.js versions
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|
|
||||||
28
cli-package/cli-wrapper.js
Normal file → Executable file
28
cli-package/cli-wrapper.js
Normal file → Executable file
|
|
@ -12,20 +12,9 @@ import { fileURLToPath } from 'url'
|
||||||
import { dirname, join } from 'path'
|
import { dirname, join } from 'path'
|
||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
|
|
||||||
// Fix for TextEncoder in Node.js v24
|
// Node.js v23+ compatibility patches were previously applied here,
|
||||||
// In Node.js v24, TextEncoder is a global object and not part of the util module
|
// but these patches are no longer necessary with current TensorFlow.js versions.
|
||||||
// This patch ensures that the util module has TextEncoder available for TensorFlow.js
|
// TensorFlow.js now works correctly with Node.js 24+ without any special handling.
|
||||||
if (process.versions.node.startsWith('24')) {
|
|
||||||
try {
|
|
||||||
const util = await import('util')
|
|
||||||
if (!util.TextEncoder && typeof TextEncoder !== 'undefined') {
|
|
||||||
util.TextEncoder = TextEncoder
|
|
||||||
util.TextDecoder = TextDecoder
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.warn('Warning: Failed to patch TextEncoder for Node.js v24:', error.message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the directory of the current module
|
// Get the directory of the current module
|
||||||
const __filename = fileURLToPath(import.meta.url)
|
const __filename = fileURLToPath(import.meta.url)
|
||||||
|
|
@ -40,7 +29,9 @@ const cliPath = join(__dirname, 'dist', 'cli.js')
|
||||||
// Check if the CLI script exists
|
// Check if the CLI script exists
|
||||||
if (!fs.existsSync(cliPath)) {
|
if (!fs.existsSync(cliPath)) {
|
||||||
console.error(`Error: CLI script not found at ${cliPath}`)
|
console.error(`Error: CLI script not found at ${cliPath}`)
|
||||||
console.error('This is likely because the CLI was not built during package installation.')
|
console.error(
|
||||||
|
'This is likely because the CLI was not built during package installation.'
|
||||||
|
)
|
||||||
console.error('Please reinstall the package with:')
|
console.error('Please reinstall the package with:')
|
||||||
console.error('npm uninstall -g @soulcraft/brainy-cli')
|
console.error('npm uninstall -g @soulcraft/brainy-cli')
|
||||||
console.error('npm install -g @soulcraft/brainy-cli')
|
console.error('npm install -g @soulcraft/brainy-cli')
|
||||||
|
|
@ -66,7 +57,12 @@ const args = process.argv.slice(2)
|
||||||
|
|
||||||
// Check if npm is passing --force flag
|
// Check if npm is passing --force flag
|
||||||
// When npm runs with --force, it sets the npm_config_force environment variable
|
// When npm runs with --force, it sets the npm_config_force environment variable
|
||||||
if (process.env.npm_config_force === 'true' && args.includes('clear') && !args.includes('--force') && !args.includes('-f')) {
|
if (
|
||||||
|
process.env.npm_config_force === 'true' &&
|
||||||
|
args.includes('clear') &&
|
||||||
|
!args.includes('--force') &&
|
||||||
|
!args.includes('-f')
|
||||||
|
) {
|
||||||
args.push('--force')
|
args.push('--force')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
12
cli-package/package-lock.json
generated
12
cli-package/package-lock.json
generated
|
|
@ -1,16 +1,16 @@
|
||||||
{
|
{
|
||||||
"name": "@soulcraft/brainy-cli",
|
"name": "@soulcraft/brainy-cli",
|
||||||
"version": "0.9.22",
|
"version": "0.9.23",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@soulcraft/brainy-cli",
|
"name": "@soulcraft/brainy-cli",
|
||||||
"version": "0.9.22",
|
"version": "0.9.23",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@soulcraft/brainy": "0.9.22",
|
"@soulcraft/brainy": "0.9.23",
|
||||||
"commander": "^14.0.0",
|
"commander": "^14.0.0",
|
||||||
"omelette": "^0.4.17"
|
"omelette": "^0.4.17"
|
||||||
},
|
},
|
||||||
|
|
@ -2086,9 +2086,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@soulcraft/brainy": {
|
"node_modules/@soulcraft/brainy": {
|
||||||
"version": "0.9.22",
|
"version": "0.9.23",
|
||||||
"resolved": "https://registry.npmjs.org/@soulcraft/brainy/-/brainy-0.9.22.tgz",
|
"resolved": "https://registry.npmjs.org/@soulcraft/brainy/-/brainy-0.9.23.tgz",
|
||||||
"integrity": "sha512-hzEky/l4IncMIp2dMspykYD903ynft2pn6Lw9eJjZ22WhOH0pvmdX8G6sYk+7IBwY5CSSw5dm3T4EPJc53gegA==",
|
"integrity": "sha512-5wmGNipjvyKAAXpPFTlhyJ6zkui/lWvk9o01d2V4Mmxx0XrR8m1dXSACIK67n5cb5/f6SKYFksYW7FXcVl43xA==",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@soulcraft/brainy-cli",
|
"name": "@soulcraft/brainy-cli",
|
||||||
"version": "0.9.23",
|
"version": "0.9.25",
|
||||||
"description": "Command-line interface for the Brainy vector graph database",
|
"description": "Command-line interface for the Brainy vector graph database",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"bin": {
|
"bin": {
|
||||||
|
|
@ -39,7 +39,7 @@
|
||||||
"url": "https://github.com/soulcraft-research/brainy.git"
|
"url": "https://github.com/soulcraft-research/brainy.git"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@soulcraft/brainy": "0.9.22",
|
"@soulcraft/brainy": "0.9.25",
|
||||||
"commander": "^14.0.0",
|
"commander": "^14.0.0",
|
||||||
"omelette": "^0.4.17"
|
"omelette": "^0.4.17"
|
||||||
},
|
},
|
||||||
|
|
@ -55,6 +55,6 @@
|
||||||
"typescript": "^5.1.6"
|
"typescript": "^5.1.6"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=24.0.0"
|
"node": ">=23.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -12,20 +12,6 @@ import { fileURLToPath } from 'url'
|
||||||
import { dirname, join } from 'path'
|
import { dirname, join } from 'path'
|
||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
|
|
||||||
// Fix for TextEncoder in Node.js v24
|
|
||||||
// In Node.js v24, TextEncoder is a global object and not part of the util module
|
|
||||||
// This patch ensures that the util module has TextEncoder available for TensorFlow.js
|
|
||||||
if (process.versions.node.startsWith('24')) {
|
|
||||||
try {
|
|
||||||
const util = await import('util')
|
|
||||||
if (!util.TextEncoder && typeof TextEncoder !== 'undefined') {
|
|
||||||
util.TextEncoder = TextEncoder
|
|
||||||
util.TextDecoder = TextDecoder
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.warn('Warning: Failed to patch TextEncoder for Node.js v24:', error.message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the directory of the current module
|
// Get the directory of the current module
|
||||||
const __filename = fileURLToPath(import.meta.url)
|
const __filename = fileURLToPath(import.meta.url)
|
||||||
|
|
|
||||||
6
package-lock.json
generated
6
package-lock.json
generated
|
|
@ -1,12 +1,12 @@
|
||||||
{
|
{
|
||||||
"name": "@soulcraft/brainy",
|
"name": "@soulcraft/brainy",
|
||||||
"version": "0.9.23",
|
"version": "0.9.25",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@soulcraft/brainy",
|
"name": "@soulcraft/brainy",
|
||||||
"version": "0.9.23",
|
"version": "0.9.25",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
@ -37,7 +37,7 @@
|
||||||
"typescript": "^5.1.6"
|
"typescript": "^5.1.6"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=24.0.0"
|
"node": ">=23.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@aws-crypto/crc32": {
|
"node_modules/@aws-crypto/crc32": {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@soulcraft/brainy",
|
"name": "@soulcraft/brainy",
|
||||||
"version": "0.9.23",
|
"version": "0.9.25",
|
||||||
"description": "A vector graph database using HNSW indexing with Origin Private File System storage",
|
"description": "A vector graph database using HNSW indexing with Origin Private File System storage",
|
||||||
"main": "dist/unified.js",
|
"main": "dist/unified.js",
|
||||||
"module": "dist/unified.js",
|
"module": "dist/unified.js",
|
||||||
|
|
@ -25,7 +25,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=24.0.0"
|
"node": ">=23.0.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prebuild": "node scripts/generate-version.js",
|
"prebuild": "node scripts/generate-version.js",
|
||||||
|
|
@ -43,8 +43,8 @@
|
||||||
"check-format": "prettier --check \"src/**/*.{ts,js}\"",
|
"check-format": "prettier --check \"src/**/*.{ts,js}\"",
|
||||||
"check-style": "node scripts/check-code-style.js",
|
"check-style": "node scripts/check-code-style.js",
|
||||||
"prepare": "npm run build",
|
"prepare": "npm run build",
|
||||||
"deploy": "npm run build && npm publish",
|
"publish": "npm run build && npm publish",
|
||||||
"deploy:both": "node scripts/publish-cli.js",
|
"publish:both": "node scripts/publish-cli.js",
|
||||||
"deploy:cloud:aws": "cd cloud-wrapper && npm run build && npm run deploy:aws",
|
"deploy:cloud:aws": "cd cloud-wrapper && npm run build && npm run deploy:aws",
|
||||||
"deploy:cloud:gcp": "cd cloud-wrapper && npm run build && npm run deploy:gcp",
|
"deploy:cloud:gcp": "cd cloud-wrapper && npm run build && npm run deploy:gcp",
|
||||||
"deploy:cloud:cloudflare": "cd cloud-wrapper && npm run build && npm run deploy:cloudflare",
|
"deploy:cloud:cloudflare": "cd cloud-wrapper && npm run build && npm run deploy:cloudflare",
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ const nodeModuleShims = () => {
|
||||||
name: 'node-module-shims',
|
name: 'node-module-shims',
|
||||||
resolveId(source) {
|
resolveId(source) {
|
||||||
// List of Node.js built-in modules to shim
|
// List of Node.js built-in modules to shim
|
||||||
const nodeBuiltins = ['fs', 'path', 'util', 'child_process']
|
const nodeBuiltins = ['fs', 'path', 'util', 'child_process', 'node:fs', 'node:path', 'node:util', 'node:child_process']
|
||||||
|
|
||||||
if (nodeBuiltins.includes(source)) {
|
if (nodeBuiltins.includes(source)) {
|
||||||
// Return a virtual module ID for the shim
|
// Return a virtual module ID for the shim
|
||||||
|
|
@ -175,7 +175,9 @@ const mainConfig = {
|
||||||
'@smithy/node-http-handler',
|
'@smithy/node-http-handler',
|
||||||
'@aws-crypto/crc32c',
|
'@aws-crypto/crc32c',
|
||||||
'node:stream/web',
|
'node:stream/web',
|
||||||
'node:worker_threads'
|
'node:worker_threads',
|
||||||
|
'node:fs',
|
||||||
|
'node:path'
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,84 +8,123 @@
|
||||||
* globally for testing.
|
* globally for testing.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { execSync } from 'child_process';
|
import { execSync } from 'child_process'
|
||||||
import fs from 'fs';
|
import fs from 'fs'
|
||||||
import path from 'path';
|
import path from 'path'
|
||||||
import { fileURLToPath } from 'url';
|
import { fileURLToPath } from 'url'
|
||||||
|
|
||||||
// Get the directory of the current module
|
// Get the directory of the current module
|
||||||
const __filename = fileURLToPath(import.meta.url);
|
const __filename = fileURLToPath(import.meta.url)
|
||||||
const __dirname = path.dirname(__filename);
|
const __dirname = path.dirname(__filename)
|
||||||
const rootDir = path.join(__dirname, '..');
|
const rootDir = path.join(__dirname, '..')
|
||||||
const cliPackageDir = path.join(rootDir, 'cli-package');
|
const cliPackageDir = path.join(rootDir, 'cli-package')
|
||||||
|
|
||||||
// Ensure the CLI package directory exists
|
// Ensure the CLI package directory exists
|
||||||
if (!fs.existsSync(cliPackageDir)) {
|
if (!fs.existsSync(cliPackageDir)) {
|
||||||
console.error(`Error: CLI package directory not found at ${cliPackageDir}`);
|
console.error(`Error: CLI package directory not found at ${cliPackageDir}`)
|
||||||
process.exit(1);
|
process.exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Step 1: Ensure versions are in sync
|
// Step 1: Ensure versions are in sync
|
||||||
console.log('Ensuring versions are in sync...');
|
console.log('Ensuring versions are in sync...')
|
||||||
execSync('node scripts/generate-version.js', { stdio: 'inherit', cwd: rootDir });
|
execSync('node scripts/generate-version.js', {
|
||||||
|
stdio: 'inherit',
|
||||||
|
cwd: rootDir
|
||||||
|
})
|
||||||
|
|
||||||
// Step 2: Build the main package
|
// Step 2: Build the main package
|
||||||
console.log('Building main package...');
|
console.log('Building main package...')
|
||||||
execSync('npm run build', { stdio: 'inherit', cwd: rootDir });
|
execSync('npm run build', { stdio: 'inherit', cwd: rootDir })
|
||||||
|
|
||||||
// Step 3: Create a local tarball of the main package
|
// Step 3: Create a local tarball of the main package
|
||||||
console.log('Creating local tarball of main package...');
|
console.log('Creating local tarball of main package...')
|
||||||
const mainPackOutput = execSync('npm pack', { cwd: rootDir }).toString().trim();
|
execSync('npm pack', { stdio: 'inherit', cwd: rootDir })
|
||||||
const mainPackageTarball = path.join(rootDir, mainPackOutput);
|
|
||||||
console.log(`Main package tarball created: ${mainPackageTarball}`);
|
// Read the main package.json to get the name and version
|
||||||
|
const mainPackageJsonPath = path.join(rootDir, 'package.json')
|
||||||
|
const mainPackageJson = JSON.parse(
|
||||||
|
fs.readFileSync(mainPackageJsonPath, 'utf8')
|
||||||
|
)
|
||||||
|
|
||||||
|
// The tarball name follows a standard format: <package-name>-<version>.tgz
|
||||||
|
const mainPackageName = mainPackageJson.name
|
||||||
|
.replace('@', '')
|
||||||
|
.replace('/', '-')
|
||||||
|
const mainPackageVersion = mainPackageJson.version
|
||||||
|
const mainTarballName = `${mainPackageName}-${mainPackageVersion}.tgz`
|
||||||
|
const mainPackageTarball = path.join(rootDir, mainTarballName)
|
||||||
|
|
||||||
|
// Verify the tarball exists
|
||||||
|
if (!fs.existsSync(mainPackageTarball)) {
|
||||||
|
console.error(
|
||||||
|
`Error: Main package tarball not found at ${mainPackageTarball}`
|
||||||
|
)
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Main package tarball created: ${mainPackageTarball}`)
|
||||||
|
|
||||||
// Step 4: Build the CLI package
|
// Step 4: Build the CLI package
|
||||||
console.log('Building CLI package...');
|
console.log('Building CLI package...')
|
||||||
execSync('npm run build', { stdio: 'inherit', cwd: cliPackageDir });
|
execSync('npm run build', { stdio: 'inherit', cwd: cliPackageDir })
|
||||||
|
|
||||||
// Step 5: Verify the CLI was built successfully
|
// Step 5: Verify the CLI was built successfully
|
||||||
const cliPath = path.join(cliPackageDir, 'dist', 'cli.js');
|
const cliPath = path.join(cliPackageDir, 'dist', 'cli.js')
|
||||||
if (!fs.existsSync(cliPath)) {
|
if (!fs.existsSync(cliPath)) {
|
||||||
console.error(`Error: CLI build failed. File not found at ${cliPath}`);
|
console.error(`Error: CLI build failed. File not found at ${cliPath}`)
|
||||||
process.exit(1);
|
process.exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 6: Temporarily update the CLI package.json to use the local main package
|
// Step 6: Temporarily update the CLI package.json to use the local main package
|
||||||
console.log('Updating CLI package.json to use local main package...');
|
console.log('Updating CLI package.json to use local main package...')
|
||||||
const cliPackageJsonPath = path.join(cliPackageDir, 'package.json');
|
const cliPackageJsonPath = path.join(cliPackageDir, 'package.json')
|
||||||
const cliPackageJson = JSON.parse(fs.readFileSync(cliPackageJsonPath, 'utf8'));
|
const cliPackageJson = JSON.parse(fs.readFileSync(cliPackageJsonPath, 'utf8'))
|
||||||
|
|
||||||
// Save the original dependency for restoration later
|
// Save the original dependency for restoration later
|
||||||
const originalDependency = cliPackageJson.dependencies['@soulcraft/brainy'];
|
const originalDependency = cliPackageJson.dependencies['@soulcraft/brainy']
|
||||||
|
|
||||||
// Update to use the local tarball
|
// Update to use the local tarball
|
||||||
cliPackageJson.dependencies['@soulcraft/brainy'] = `file:${mainPackageTarball}`;
|
cliPackageJson.dependencies['@soulcraft/brainy'] =
|
||||||
|
`file:${mainPackageTarball}`
|
||||||
|
|
||||||
// Write the updated package.json
|
// Write the updated package.json
|
||||||
fs.writeFileSync(cliPackageJsonPath, JSON.stringify(cliPackageJson, null, 2));
|
fs.writeFileSync(cliPackageJsonPath, JSON.stringify(cliPackageJson, null, 2))
|
||||||
|
|
||||||
// Step 7: Create a local tarball of the CLI package
|
// Step 7: Create a local tarball of the CLI package
|
||||||
console.log('Creating local tarball of CLI package...');
|
console.log('Creating local tarball of CLI package...')
|
||||||
const cliPackOutput = execSync('npm pack', { cwd: cliPackageDir }).toString().trim();
|
execSync('npm pack', { stdio: 'inherit', cwd: cliPackageDir })
|
||||||
const cliPackageTarball = path.join(cliPackageDir, cliPackOutput);
|
|
||||||
console.log(`CLI package tarball created: ${cliPackageTarball}`);
|
|
||||||
|
|
||||||
// Step 8: Restore the original dependency in CLI package.json
|
// The tarball name follows a standard format: <package-name>-<version>.tgz
|
||||||
console.log('Restoring original dependency in CLI package.json...');
|
const cliPackageName = cliPackageJson.name.replace('@', '').replace('/', '-')
|
||||||
cliPackageJson.dependencies['@soulcraft/brainy'] = originalDependency;
|
const cliPackageVersion = cliPackageJson.version
|
||||||
fs.writeFileSync(cliPackageJsonPath, JSON.stringify(cliPackageJson, null, 2));
|
const cliTarballName = `${cliPackageName}-${cliPackageVersion}.tgz`
|
||||||
|
const cliPackageTarball = path.join(cliPackageDir, cliTarballName)
|
||||||
|
|
||||||
// Step 9: Install the CLI package globally for testing
|
// Verify the tarball exists
|
||||||
console.log('Installing CLI package globally for testing...');
|
if (!fs.existsSync(cliPackageTarball)) {
|
||||||
execSync(`npm install -g ${cliPackageTarball}`, { stdio: 'inherit' });
|
console.error(
|
||||||
|
`Error: CLI package tarball not found at ${cliPackageTarball}`
|
||||||
console.log('\nCLI package installed globally for testing!');
|
)
|
||||||
console.log('You can now run the CLI using the "brainy" command.');
|
process.exit(1)
|
||||||
console.log('\nTo uninstall after testing:');
|
}
|
||||||
console.log('npm uninstall -g @soulcraft/brainy-cli');
|
|
||||||
|
console.log(`CLI package tarball created: ${cliPackageTarball}`)
|
||||||
} catch (error) {
|
|
||||||
console.error('Error:', error.message);
|
// Step 8: Install the CLI package globally for testing
|
||||||
process.exit(1);
|
console.log('Installing CLI package globally for testing...')
|
||||||
|
execSync(`npm install -g "${cliPackageTarball}"`, { stdio: 'inherit' })
|
||||||
|
|
||||||
|
// Step 9: Restore the original dependency in CLI package.json
|
||||||
|
console.log('Restoring original dependency in CLI package.json...')
|
||||||
|
cliPackageJson.dependencies['@soulcraft/brainy'] = originalDependency
|
||||||
|
fs.writeFileSync(cliPackageJsonPath, JSON.stringify(cliPackageJson, null, 2))
|
||||||
|
|
||||||
|
console.log('\nCLI package installed globally for testing!')
|
||||||
|
console.log('You can now run the CLI using the "brainy" command.')
|
||||||
|
console.log('\nTo uninstall after testing:')
|
||||||
|
console.log('npm uninstall -g @soulcraft/brainy-cli')
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error:', error.message)
|
||||||
|
process.exit(1)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -306,7 +306,7 @@ export async function createMemoryAugmentation(
|
||||||
|
|
||||||
// Otherwise, select based on environment
|
// Otherwise, select based on environment
|
||||||
// Use the global isNode variable from the environment detection
|
// Use the global isNode variable from the environment detection
|
||||||
const isNodeEnv = globalThis.__ENV__?.isNode || (
|
const isNodeEnv = (globalThis as any).__ENV__?.isNode || (
|
||||||
typeof process !== 'undefined' &&
|
typeof process !== 'undefined' &&
|
||||||
process.versions != null &&
|
process.versions != null &&
|
||||||
process.versions.node != null
|
process.versions.node != null
|
||||||
|
|
|
||||||
20
src/global.d.ts
vendored
20
src/global.d.ts
vendored
|
|
@ -1,20 +0,0 @@
|
||||||
/**
|
|
||||||
* Global type declarations for Brainy
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Extend the globalThis interface to include the __ENV__ property
|
|
||||||
declare global {
|
|
||||||
var __ENV__: {
|
|
||||||
isBrowser: boolean
|
|
||||||
isNode: string | false
|
|
||||||
isServerless: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
// Window interface extensions (worker-specific functions removed)
|
|
||||||
interface Window {
|
|
||||||
importTensorFlow?: () => Promise<any>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This export is needed to make this file a module
|
|
||||||
export {}
|
|
||||||
|
|
@ -1,9 +1,52 @@
|
||||||
import { GraphVerb, HNSWNoun, StorageAdapter } from '../coreTypes.js'
|
import { GraphVerb, HNSWNoun, StorageAdapter } from '../coreTypes.js'
|
||||||
|
|
||||||
// We'll dynamically import Node.js built-in modules
|
// Import Node.js built-in modules
|
||||||
|
// Using require for compatibility with Node.js
|
||||||
let fs: any
|
let fs: any
|
||||||
let path: any
|
let path: any
|
||||||
|
|
||||||
|
// Initialize these modules immediately if in Node.js environment
|
||||||
|
if (
|
||||||
|
typeof process !== 'undefined' &&
|
||||||
|
process.versions &&
|
||||||
|
process.versions.node
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
// Use require for Node.js built-in modules
|
||||||
|
fs = require('fs')
|
||||||
|
path = require('path')
|
||||||
|
|
||||||
|
// Verify that path has the required methods
|
||||||
|
if (!path || typeof path.resolve !== 'function') {
|
||||||
|
throw new Error('path module is missing required methods')
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('Failed to load Node.js modules with require:', e)
|
||||||
|
|
||||||
|
// Try using dynamic import as a fallback
|
||||||
|
try {
|
||||||
|
// Use a synchronous approach to ensure modules are loaded before continuing
|
||||||
|
const pathModule = require('node:path')
|
||||||
|
const fsModule = require('node:fs')
|
||||||
|
|
||||||
|
path = pathModule
|
||||||
|
fs = fsModule
|
||||||
|
|
||||||
|
// Verify that path has the required methods
|
||||||
|
if (!path || typeof path.resolve !== 'function') {
|
||||||
|
throw new Error(
|
||||||
|
'path module from node:path is missing required methods'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} catch (nodeImportError) {
|
||||||
|
console.warn(
|
||||||
|
'Failed to load Node.js modules with node: prefix:',
|
||||||
|
nodeImportError
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Constants for directory and file names
|
// Constants for directory and file names
|
||||||
const ROOT_DIR = 'brainy-data'
|
const ROOT_DIR = 'brainy-data'
|
||||||
const NOUNS_DIR = 'nouns'
|
const NOUNS_DIR = 'nouns'
|
||||||
|
|
@ -60,15 +103,108 @@ export class FileSystemStorage implements StorageAdapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Dynamically import Node.js built-in modules
|
// Check if fs and path modules are available and have required methods
|
||||||
try {
|
if (!fs || !path || typeof path.resolve !== 'function') {
|
||||||
// Import the modules
|
console.log(
|
||||||
|
'Node.js modules not properly loaded, attempting to load them now'
|
||||||
|
)
|
||||||
|
|
||||||
|
// Try multiple approaches to load the modules
|
||||||
|
const loadAttempts = [
|
||||||
|
// Attempt 1: Use require
|
||||||
|
async () => {
|
||||||
|
console.log('Attempting to load Node.js modules with require()')
|
||||||
|
const fsModule = require('fs')
|
||||||
|
const pathModule = require('path')
|
||||||
|
|
||||||
|
if (!pathModule || typeof pathModule.resolve !== 'function') {
|
||||||
|
throw new Error('path.resolve is not a function after require()')
|
||||||
|
}
|
||||||
|
|
||||||
|
return { fs: fsModule, path: pathModule }
|
||||||
|
},
|
||||||
|
|
||||||
|
// Attempt 2: Use require with node: prefix
|
||||||
|
async () => {
|
||||||
|
console.log(
|
||||||
|
'Attempting to load Node.js modules with require("node:...")'
|
||||||
|
)
|
||||||
|
const fsModule = require('node:fs')
|
||||||
|
const pathModule = require('node:path')
|
||||||
|
|
||||||
|
if (!pathModule || typeof pathModule.resolve !== 'function') {
|
||||||
|
throw new Error(
|
||||||
|
'path.resolve is not a function after require("node:path")'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return { fs: fsModule, path: pathModule }
|
||||||
|
},
|
||||||
|
|
||||||
|
// Attempt 3: Use dynamic import
|
||||||
|
async () => {
|
||||||
|
console.log(
|
||||||
|
'Attempting to load Node.js modules with dynamic import'
|
||||||
|
)
|
||||||
const fsModule = await import('fs')
|
const fsModule = await import('fs')
|
||||||
const pathModule = await import('path')
|
const pathModule = await import('path')
|
||||||
|
|
||||||
// Assign to our module-level variables
|
const fsResolved = fsModule.default || fsModule
|
||||||
fs = fsModule.default || fsModule
|
const pathResolved = pathModule.default || pathModule
|
||||||
path = pathModule.default || pathModule
|
|
||||||
|
if (!pathResolved || typeof pathResolved.resolve !== 'function') {
|
||||||
|
throw new Error(
|
||||||
|
'path.resolve is not a function after dynamic import'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return { fs: fsResolved, path: pathResolved }
|
||||||
|
},
|
||||||
|
|
||||||
|
// Attempt 4: Use dynamic import with node: prefix
|
||||||
|
async () => {
|
||||||
|
console.log(
|
||||||
|
'Attempting to load Node.js modules with dynamic import("node:...")'
|
||||||
|
)
|
||||||
|
const fsModule = await import('node:fs')
|
||||||
|
const pathModule = await import('node:path')
|
||||||
|
|
||||||
|
const fsResolved = fsModule.default || fsModule
|
||||||
|
const pathResolved = pathModule.default || pathModule
|
||||||
|
|
||||||
|
if (!pathResolved || typeof pathResolved.resolve !== 'function') {
|
||||||
|
throw new Error(
|
||||||
|
'path.resolve is not a function after dynamic import("node:path")'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return { fs: fsResolved, path: pathResolved }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
// Try each loading method until one succeeds
|
||||||
|
let lastError = null
|
||||||
|
for (const loadAttempt of loadAttempts) {
|
||||||
|
try {
|
||||||
|
const modules = await loadAttempt()
|
||||||
|
fs = modules.fs
|
||||||
|
path = modules.path
|
||||||
|
console.log('Successfully loaded Node.js modules')
|
||||||
|
break
|
||||||
|
} catch (error) {
|
||||||
|
lastError = error
|
||||||
|
console.warn(`Module loading attempt failed:`, error)
|
||||||
|
// Continue to the next attempt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If all attempts failed, throw an error
|
||||||
|
if (!fs || !path || typeof path.resolve !== 'function') {
|
||||||
|
throw new Error(
|
||||||
|
`Failed to import Node.js modules after multiple attempts: ${lastError}. This adapter requires a Node.js environment.`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Now set up the directory paths
|
// Now set up the directory paths
|
||||||
const rootDir = this.rootDir || process.cwd()
|
const rootDir = this.rootDir || process.cwd()
|
||||||
|
|
@ -85,11 +221,6 @@ export class FileSystemStorage implements StorageAdapter {
|
||||||
this.conceptDir = path.join(this.nounsDir, CONCEPT_DIR)
|
this.conceptDir = path.join(this.nounsDir, CONCEPT_DIR)
|
||||||
this.contentDir = path.join(this.nounsDir, CONTENT_DIR)
|
this.contentDir = path.join(this.nounsDir, CONTENT_DIR)
|
||||||
this.defaultDir = path.join(this.nounsDir, DEFAULT_DIR)
|
this.defaultDir = path.join(this.nounsDir, DEFAULT_DIR)
|
||||||
} catch (importError) {
|
|
||||||
throw new Error(
|
|
||||||
`Failed to import Node.js modules: ${importError}. This adapter requires a Node.js environment.`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create directories if they don't exist
|
// Create directories if they don't exist
|
||||||
await this.ensureDirectoryExists(this.rootDir)
|
await this.ensureDirectoryExists(this.rootDir)
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,35 @@
|
||||||
// Type declarations for TensorFlow.js models
|
/**
|
||||||
|
* Type definitions for TensorFlow.js compatibility
|
||||||
|
* This file exports type definitions for TensorFlow.js utilities
|
||||||
|
*/
|
||||||
|
|
||||||
// This file is a placeholder for TensorFlow.js model types
|
// Define the shape of the util object used for TensorFlow.js compatibility
|
||||||
// We're using type assertions in the code instead of module declarations
|
export interface TensorFlowUtilObject {
|
||||||
|
isFloat32Array: (arr: unknown) => boolean
|
||||||
// Define some basic types that might be useful
|
isTypedArray: (arr: unknown) => boolean
|
||||||
export interface TensorflowModel {
|
[key: string]: unknown
|
||||||
load(): Promise<any>;
|
|
||||||
embed(data: string[]): any;
|
|
||||||
dispose(): void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Export a dummy constant to make this a proper module
|
// Define the shape of the PlatformNode object that might exist in global
|
||||||
export const tensorflowModelsLoaded = true;
|
export interface PlatformNodeObject {
|
||||||
|
isFloat32Array?: (arr: unknown) => boolean
|
||||||
|
isTypedArray?: (arr: unknown) => boolean
|
||||||
|
[key: string]: unknown
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define the shape of the tf object that might exist in global
|
||||||
|
export interface TensorFlowObject {
|
||||||
|
util?: TensorFlowUtilObject
|
||||||
|
[key: string]: unknown
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extend the Window and WorkerGlobalScope interfaces to include the importTensorFlow function
|
||||||
|
declare global {
|
||||||
|
interface Window {
|
||||||
|
importTensorFlow?: () => Promise<any>
|
||||||
|
}
|
||||||
|
|
||||||
|
interface WorkerGlobalScope {
|
||||||
|
importTensorFlow?: () => Promise<any>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ export const environment = {
|
||||||
|
|
||||||
// Make environment information available globally
|
// Make environment information available globally
|
||||||
if (typeof globalThis !== 'undefined') {
|
if (typeof globalThis !== 'undefined') {
|
||||||
globalThis.__ENV__ = environment
|
;(globalThis as any).__ENV__ = environment
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log the detected environment
|
// Log the detected environment
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,23 @@ export class UniversalSentenceEncoder implements EmbeddingModel {
|
||||||
private use: any = null
|
private use: any = null
|
||||||
private backend: string = 'cpu' // Default to CPU
|
private backend: string = 'cpu' // Default to CPU
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add polyfills and patches for TensorFlow.js compatibility
|
||||||
|
* This addresses issues with TensorFlow.js in Node.js environments
|
||||||
|
*/
|
||||||
|
private addNodeCompatibilityPolyfills(): void {
|
||||||
|
// Only apply in Node.js environment
|
||||||
|
if (
|
||||||
|
typeof process === 'undefined' ||
|
||||||
|
!process.versions ||
|
||||||
|
!process.versions.node
|
||||||
|
) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// No compatibility patches needed - TensorFlow.js now works correctly with Node.js 24+
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the embedding model
|
* Initialize the embedding model
|
||||||
*/
|
*/
|
||||||
|
|
@ -42,6 +59,9 @@ export class UniversalSentenceEncoder implements EmbeddingModel {
|
||||||
originalWarn(message, ...optionalParams)
|
originalWarn(message, ...optionalParams)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add polyfills for TensorFlow.js compatibility
|
||||||
|
this.addNodeCompatibilityPolyfills()
|
||||||
|
|
||||||
// TensorFlow.js will use its default EPSILON value
|
// TensorFlow.js will use its default EPSILON value
|
||||||
|
|
||||||
// Dynamically import TensorFlow.js core module and backends
|
// Dynamically import TensorFlow.js core module and backends
|
||||||
|
|
|
||||||
80
src/utils/tensorflowUtils.ts
Normal file
80
src/utils/tensorflowUtils.ts
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
/**
|
||||||
|
* Utility functions for TensorFlow.js compatibility
|
||||||
|
* This module provides utility functions that TensorFlow.js might need
|
||||||
|
* and avoids the need to use globalThis.util
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Import the TensorFlowUtilObject interface
|
||||||
|
import type {
|
||||||
|
TensorFlowUtilObject,
|
||||||
|
PlatformNodeObject
|
||||||
|
} from '../types/tensorflowTypes.js'
|
||||||
|
|
||||||
|
// Define a global PlatformNode class for TensorFlow.js compatibility
|
||||||
|
// This is needed because TensorFlow.js creates its own PlatformNode instance
|
||||||
|
// and we need to ensure it uses the correct TextEncoder/TextDecoder
|
||||||
|
if (
|
||||||
|
typeof global !== 'undefined' &&
|
||||||
|
typeof process !== 'undefined' &&
|
||||||
|
process.versions &&
|
||||||
|
process.versions.node &&
|
||||||
|
process.versions.node.split('.')[0] >= '23'
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
// Define the PlatformNode class that TensorFlow.js will use
|
||||||
|
class PlatformNode {
|
||||||
|
util: any
|
||||||
|
textEncoder: any
|
||||||
|
textDecoder: any
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
// Create a util object with the necessary methods
|
||||||
|
this.util = {
|
||||||
|
isFloat32Array,
|
||||||
|
isTypedArray,
|
||||||
|
// Use the global TextEncoder/TextDecoder directly
|
||||||
|
TextEncoder: typeof TextEncoder !== 'undefined' ? TextEncoder : null,
|
||||||
|
TextDecoder: typeof TextDecoder !== 'undefined' ? TextDecoder : null
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize TextEncoder/TextDecoder directly from globals
|
||||||
|
this.textEncoder = new TextEncoder()
|
||||||
|
this.textDecoder = new TextDecoder()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assign the PlatformNode class to the global object
|
||||||
|
;(global as any).PlatformNode = PlatformNode
|
||||||
|
|
||||||
|
// Also create an instance and assign it to global.platformNode (lowercase p)
|
||||||
|
// Some TensorFlow.js code might look for this
|
||||||
|
;(global as any).platformNode = new PlatformNode()
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
'Defined global PlatformNode class for TensorFlow.js compatibility'
|
||||||
|
)
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('Failed to define global PlatformNode class:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if an array is a Float32Array
|
||||||
|
* @param arr - The array to check
|
||||||
|
* @returns True if the array is a Float32Array
|
||||||
|
*/
|
||||||
|
export function isFloat32Array(arr: unknown): boolean {
|
||||||
|
return !!(
|
||||||
|
arr instanceof Float32Array ||
|
||||||
|
(arr && Object.prototype.toString.call(arr) === '[object Float32Array]')
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if an array is a TypedArray
|
||||||
|
* @param arr - The array to check
|
||||||
|
* @returns True if the array is a TypedArray
|
||||||
|
*/
|
||||||
|
export function isTypedArray(arr: unknown): boolean {
|
||||||
|
return !!(ArrayBuffer.isView(arr) && !(arr instanceof DataView))
|
||||||
|
}
|
||||||
|
|
@ -3,4 +3,4 @@
|
||||||
* Do not modify this file directly.
|
* Do not modify this file directly.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export const VERSION = '0.9.22';
|
export const VERSION = '0.9.25';
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue