fix: use platform-aware local defaults

- Route app DB and sqlite-vec defaults through shared platform helpers
- Mirror platform DB defaults in the standalone MCP package
- Fix Windows setup npm spawning and remove macOS-only env defaults
This commit is contained in:
“BeeRad”
2026-04-27 14:46:10 +10:00
parent c9fb623e02
commit 1019a2b846
9 changed files with 41 additions and 52 deletions
+4 -3
View File
@@ -6,9 +6,10 @@
# Get one at: https://platform.openai.com/api-keys # Get one at: https://platform.openai.com/api-keys
OPENAI_API_KEY= OPENAI_API_KEY=
# Database path (defaults work for most users) # Database/vector paths are auto-detected for macOS, Windows, and Linux.
# SQLITE_DB_PATH=~/Library/Application Support/RA-H/db/rah.sqlite # Override only if you intentionally want a custom location.
SQLITE_VEC_EXTENSION_PATH=./vendor/sqlite-extensions/vec0.dylib # SQLITE_DB_PATH=/absolute/path/to/rah.sqlite
# SQLITE_VEC_EXTENSION_PATH=/absolute/path/to/vec0.<dylib|dll|so>
# App config (no changes needed) # App config (no changes needed)
NODE_ENV=development NODE_ENV=development
+2 -2
View File
@@ -50,13 +50,13 @@ Restart Claude fully. If you need to freeze behavior for debugging, pin an exact
## Requirements ## Requirements
- Node.js 18-22 LTS recommended - Node.js 18-22 LTS recommended
- a RA-H database at `~/Library/Application Support/RA-H/db/rah.sqlite`, created by `setup`, `init-db`, or the app - a RA-H database at the platform default path, created by `setup`, `init-db`, or the app
## Environment Variables ## Environment Variables
| Variable | Default | Description | | Variable | Default | Description |
|----------|---------|-------------| |----------|---------|-------------|
| `RAH_DB_PATH` | `~/Library/Application Support/RA-H/db/rah.sqlite` | Database path | | `RAH_DB_PATH` | Platform default app-data path | Database path |
For demos or isolated installs: For demos or isolated installs:
@@ -7,24 +7,32 @@ const os = require('node:os');
/** /**
* Get the database path. * Get the database path.
* Priority: RAH_DB_PATH env var > default app data location * Priority: RAH_DB_PATH env var > SQLITE_DB_PATH env var > platform app data location
*/ */
function getDatabasePath() { function getDefaultDbPath() {
if (process.env.RAH_DB_PATH) { const homeDir = os.homedir() || process.env.HOME || '~';
return process.env.RAH_DB_PATH;
if (process.platform === 'win32') {
const appData = process.env.APPDATA || path.join(homeDir, 'AppData', 'Roaming');
return path.join(appData, 'RA-H', 'db', 'rah.sqlite');
}
if (process.platform === 'darwin') {
return path.join(homeDir, 'Library', 'Application Support', 'RA-H', 'db', 'rah.sqlite');
} }
// Default: ~/Library/Application Support/RA-H/db/rah.sqlite
return path.join( return path.join(
os.homedir(), process.env.XDG_DATA_HOME || path.join(homeDir, '.local', 'share'),
'Library',
'Application Support',
'RA-H', 'RA-H',
'db', 'db',
'rah.sqlite' 'rah.sqlite'
); );
} }
function getDatabasePath() {
return process.env.RAH_DB_PATH || process.env.SQLITE_DB_PATH || getDefaultDbPath();
}
let db = null; let db = null;
function getExistingColumnNames(db, tableName) { function getExistingColumnNames(db, tableName) {
@@ -24,7 +24,7 @@ Start with product orientation and goal discovery first.
Only bring up setup details if the user actually needs them: Only bring up setup details if the user actually needs them:
1. If they are on local/BYO-key mode, point them to Settings → API Keys. 1. If they are on local/BYO-key mode, point them to Settings → API Keys.
2. If they ask about the database location, tell them the default macOS path is `~/Library/Application Support/RA-H/db/rah.sqlite`. 2. If they ask about the database location, tell them RA-H uses the platform default: macOS `~/Library/Application Support/RA-H/db/rah.sqlite`, Windows `%APPDATA%/RA-H/db/rah.sqlite`, Linux `~/.local/share/RA-H/db/rah.sqlite`.
3. If API keys are relevant, explain them plainly: 3. If API keys are relevant, explain them plainly:
- **OpenAI** — powers embeddings, semantic retrieval, and extraction-related AI work. - **OpenAI** — powers embeddings, semantic retrieval, and extraction-related AI work.
- **Anthropic** — mainly relevant for compatible runtime paths and local/dev setups. - **Anthropic** — mainly relevant for compatible runtime paths and local/dev setups.
+6
View File
@@ -6,8 +6,14 @@ function run(command, args) {
const result = spawnSync(command, args, { const result = spawnSync(command, args, {
stdio: 'inherit', stdio: 'inherit',
env: process.env, env: process.env,
shell: process.platform === 'win32',
}); });
if (result.error) {
console.error(`[setup-local] Failed to run ${command}: ${result.error.message}`);
process.exit(1);
}
if (result.status !== 0) { if (result.status !== 0) {
process.exit(result.status || 1); process.exit(result.status || 1);
} }
+1 -1
View File
@@ -24,7 +24,7 @@ Start with product orientation and goal discovery first.
Only bring up setup details if the user actually needs them: Only bring up setup details if the user actually needs them:
1. If they are on local/BYO-key mode, point them to Settings → API Keys. 1. If they are on local/BYO-key mode, point them to Settings → API Keys.
2. If they ask about the database location, tell them the default macOS path is `~/Library/Application Support/RA-H/db/rah.sqlite`. 2. If they ask about the database location, tell them RA-H uses the platform default: macOS `~/Library/Application Support/RA-H/db/rah.sqlite`, Windows `%APPDATA%/RA-H/db/rah.sqlite`, Linux `~/.local/share/RA-H/db/rah.sqlite`.
3. If API keys are relevant, explain them plainly: 3. If API keys are relevant, explain them plainly:
- **OpenAI** — powers embeddings, semantic retrieval, and extraction-related AI work. - **OpenAI** — powers embeddings, semantic retrieval, and extraction-related AI work.
- **Anthropic** — mainly relevant for compatible runtime paths and local/dev setups. - **Anthropic** — mainly relevant for compatible runtime paths and local/dev setups.
+3 -10
View File
@@ -2,6 +2,7 @@ import Database from 'better-sqlite3';
import fs from 'fs'; import fs from 'fs';
import path from 'path'; import path from 'path';
import { DatabaseError } from '@/types/database'; import { DatabaseError } from '@/types/database';
import { getDatabasePath, getVecExtensionPath } from '@/services/database/sqlite-runtime';
export interface SQLiteConfig { export interface SQLiteConfig {
dbPath: string; dbPath: string;
@@ -115,17 +116,9 @@ class SQLiteClient {
} }
private getSQLiteConfig(): SQLiteConfig { private getSQLiteConfig(): SQLiteConfig {
const dbPath = process.env.SQLITE_DB_PATH || path.join(
process.env.HOME || '~',
'Library/Application Support/RA-H/db/rah.sqlite'
);
const vecExtensionPath = process.env.SQLITE_VEC_EXTENSION_PATH ||
'./vendor/sqlite-extensions/vec0.dylib';
return { return {
dbPath, dbPath: getDatabasePath(),
vecExtensionPath vecExtensionPath: getVecExtensionPath()
}; };
} }
+7 -18
View File
@@ -4,9 +4,11 @@
*/ */
import Database from 'better-sqlite3'; import Database from 'better-sqlite3';
import path from 'path'; import {
import os from 'os'; getDatabasePath as getRuntimeDatabasePath,
import { getDbVectorCapability as getVectorCapability } from '@/services/database/sqlite-runtime'; getDbVectorCapability as getVectorCapability,
getVecExtensionPath as getRuntimeVecExtensionPath
} from '@/services/database/sqlite-runtime';
/** /**
* Serialize a float array to binary format for vec0 storage * Serialize a float array to binary format for vec0 storage
@@ -35,27 +37,14 @@ export function deserializeFloat32Vector(blob: Buffer): number[] {
* Get SQLite database path from environment or default location * Get SQLite database path from environment or default location
*/ */
export function getDatabasePath(): string { export function getDatabasePath(): string {
const envPath = process.env.SQLITE_DB_PATH; return getRuntimeDatabasePath();
if (envPath) {
return envPath;
}
// Default path: ~/Library/Application Support/RA-H/db/rah.sqlite
const homeDir = os.homedir();
return path.join(homeDir, 'Library', 'Application Support', 'RA-H', 'db', 'rah.sqlite');
} }
/** /**
* Get vec extension path from environment or default location * Get vec extension path from environment or default location
*/ */
export function getVecExtensionPath(): string { export function getVecExtensionPath(): string {
const envPath = process.env.SQLITE_VEC_EXTENSION_PATH; return getRuntimeVecExtensionPath();
if (envPath) {
return envPath;
}
// Default path relative to project root
return path.join(process.cwd(), 'vendor', 'sqlite-extensions', 'vec0.dylib');
} }
/** /**
+1 -9
View File
@@ -2,18 +2,10 @@ import { tool } from 'ai';
import { z } from 'zod'; import { z } from 'zod';
import { exec } from 'child_process'; import { exec } from 'child_process';
import { promisify } from 'util'; import { promisify } from 'util';
import path from 'path'; import { getDatabasePath } from '@/services/database/sqlite-runtime';
const execAsync = promisify(exec); const execAsync = promisify(exec);
// Get database path (same logic as sqlite-client.ts)
function getDatabasePath(): string {
return process.env.SQLITE_DB_PATH || path.join(
process.env.HOME || '~',
'Library/Application Support/RA-H/db/rah.sqlite'
);
}
// Security: Only allow SELECT statements // Security: Only allow SELECT statements
function isReadOnlyQuery(sql: string): boolean { function isReadOnlyQuery(sql: string): boolean {
const normalized = sql.trim().toLowerCase(); const normalized = sql.trim().toLowerCase();