diff --git a/.env.example b/.env.example index 4ca924b..acad8bf 100644 --- a/.env.example +++ b/.env.example @@ -6,9 +6,10 @@ # Get one at: https://platform.openai.com/api-keys OPENAI_API_KEY= -# Database path (defaults work for most users) -# SQLITE_DB_PATH=~/Library/Application Support/RA-H/db/rah.sqlite -SQLITE_VEC_EXTENSION_PATH=./vendor/sqlite-extensions/vec0.dylib +# Database/vector paths are auto-detected for macOS, Windows, and Linux. +# Override only if you intentionally want a custom location. +# SQLITE_DB_PATH=/absolute/path/to/rah.sqlite +# SQLITE_VEC_EXTENSION_PATH=/absolute/path/to/vec0. # App config (no changes needed) NODE_ENV=development diff --git a/apps/mcp-server-standalone/README.md b/apps/mcp-server-standalone/README.md index 91f5330..63e85a4 100644 --- a/apps/mcp-server-standalone/README.md +++ b/apps/mcp-server-standalone/README.md @@ -50,13 +50,13 @@ Restart Claude fully. If you need to freeze behavior for debugging, pin an exact ## Requirements - 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 | 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: diff --git a/apps/mcp-server-standalone/services/sqlite-client.js b/apps/mcp-server-standalone/services/sqlite-client.js index 7fa3c8b..65004f2 100644 --- a/apps/mcp-server-standalone/services/sqlite-client.js +++ b/apps/mcp-server-standalone/services/sqlite-client.js @@ -7,24 +7,32 @@ const os = require('node:os'); /** * 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() { - if (process.env.RAH_DB_PATH) { - return process.env.RAH_DB_PATH; +function getDefaultDbPath() { + const homeDir = os.homedir() || process.env.HOME || '~'; + + 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( - os.homedir(), - 'Library', - 'Application Support', + process.env.XDG_DATA_HOME || path.join(homeDir, '.local', 'share'), 'RA-H', 'db', 'rah.sqlite' ); } +function getDatabasePath() { + return process.env.RAH_DB_PATH || process.env.SQLITE_DB_PATH || getDefaultDbPath(); +} + let db = null; function getExistingColumnNames(db, tableName) { diff --git a/apps/mcp-server-standalone/skills/onboarding.md b/apps/mcp-server-standalone/skills/onboarding.md index ce5b095..0266c1d 100644 --- a/apps/mcp-server-standalone/skills/onboarding.md +++ b/apps/mcp-server-standalone/skills/onboarding.md @@ -24,7 +24,7 @@ Start with product orientation and goal discovery first. 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. -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: - **OpenAI** — powers embeddings, semantic retrieval, and extraction-related AI work. - **Anthropic** — mainly relevant for compatible runtime paths and local/dev setups. diff --git a/scripts/dev/setup-local.mjs b/scripts/dev/setup-local.mjs index 400c7c5..af584cb 100644 --- a/scripts/dev/setup-local.mjs +++ b/scripts/dev/setup-local.mjs @@ -6,8 +6,14 @@ function run(command, args) { const result = spawnSync(command, args, { stdio: 'inherit', 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) { process.exit(result.status || 1); } diff --git a/src/config/skills/onboarding.md b/src/config/skills/onboarding.md index ce5b095..0266c1d 100644 --- a/src/config/skills/onboarding.md +++ b/src/config/skills/onboarding.md @@ -24,7 +24,7 @@ Start with product orientation and goal discovery first. 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. -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: - **OpenAI** — powers embeddings, semantic retrieval, and extraction-related AI work. - **Anthropic** — mainly relevant for compatible runtime paths and local/dev setups. diff --git a/src/services/database/sqlite-client.ts b/src/services/database/sqlite-client.ts index 0026c7b..d966a75 100644 --- a/src/services/database/sqlite-client.ts +++ b/src/services/database/sqlite-client.ts @@ -2,6 +2,7 @@ import Database from 'better-sqlite3'; import fs from 'fs'; import path from 'path'; import { DatabaseError } from '@/types/database'; +import { getDatabasePath, getVecExtensionPath } from '@/services/database/sqlite-runtime'; export interface SQLiteConfig { dbPath: string; @@ -115,17 +116,9 @@ class SQLiteClient { } 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 { - dbPath, - vecExtensionPath + dbPath: getDatabasePath(), + vecExtensionPath: getVecExtensionPath() }; } diff --git a/src/services/typescript/sqlite-vec.ts b/src/services/typescript/sqlite-vec.ts index 8fda92c..92e2243 100644 --- a/src/services/typescript/sqlite-vec.ts +++ b/src/services/typescript/sqlite-vec.ts @@ -4,9 +4,11 @@ */ import Database from 'better-sqlite3'; -import path from 'path'; -import os from 'os'; -import { getDbVectorCapability as getVectorCapability } from '@/services/database/sqlite-runtime'; +import { + getDatabasePath as getRuntimeDatabasePath, + getDbVectorCapability as getVectorCapability, + getVecExtensionPath as getRuntimeVecExtensionPath +} from '@/services/database/sqlite-runtime'; /** * 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 */ export function getDatabasePath(): string { - const envPath = process.env.SQLITE_DB_PATH; - 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'); + return getRuntimeDatabasePath(); } /** * Get vec extension path from environment or default location */ export function getVecExtensionPath(): string { - const envPath = process.env.SQLITE_VEC_EXTENSION_PATH; - if (envPath) { - return envPath; - } - - // Default path relative to project root - return path.join(process.cwd(), 'vendor', 'sqlite-extensions', 'vec0.dylib'); + return getRuntimeVecExtensionPath(); } /** diff --git a/src/tools/other/sqliteQuery.ts b/src/tools/other/sqliteQuery.ts index 4ed6ac3..b0be719 100644 --- a/src/tools/other/sqliteQuery.ts +++ b/src/tools/other/sqliteQuery.ts @@ -2,18 +2,10 @@ import { tool } from 'ai'; import { z } from 'zod'; import { exec } from 'child_process'; import { promisify } from 'util'; -import path from 'path'; +import { getDatabasePath } from '@/services/database/sqlite-runtime'; 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 function isReadOnlyQuery(sql: string): boolean { const normalized = sql.trim().toLowerCase();