@openexpert/opencore 0.1.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/README.md +22 -0
- package/bin/opencore.js +24 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +622 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +25 -0
- package/dist/config.js +65 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +144 -0
- package/dist/index.js.map +1 -0
- package/dist/model-provider.d.ts +18 -0
- package/dist/model-provider.js +44 -0
- package/dist/model-provider.js.map +1 -0
- package/dist/secrets.d.ts +16 -0
- package/dist/secrets.js +9 -0
- package/dist/secrets.js.map +1 -0
- package/dist/storage.d.ts +10 -0
- package/dist/storage.js +17 -0
- package/dist/storage.js.map +1 -0
- package/dist/tools.d.ts +10 -0
- package/dist/tools.js +21 -0
- package/dist/tools.js.map +1 -0
- package/package.json +97 -0
- package/schema/openexpert.schema.json +80 -0
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/model-provider.ts","../src/cli/lib.ts","../src/cli/commands.ts","../src/cli/desktop.ts","../src/cli/wizard.ts","../src/cli.ts"],"names":["p","mkdirSync","existsSync","join","writeFileSync","spawn","homedir","resolve","ollama","config","run"],"mappings":"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","file":"cli.js","sourcesContent":["// SPDX-License-Identifier: MIT\n// OpenCore — which model to use. The harness is stable; the model is configuration.\n//\n// Providers:\n// - google: Gemini via GOOGLE_API_KEY (free API key).\n// - ollama: Local model via Ollama's OpenAI-compatible endpoint.\n// - openai-compatible: Any OpenAI-compatible endpoint with your own key.\n\nexport type ModelProviderId = \"google\" | \"ollama\" | \"openai-compatible\";\n\nexport type ModelSelection = {\n provider: ModelProviderId;\n modelId: string;\n /** Where the key comes from, without exposing the value. */\n keySource: \"GOOGLE_API_KEY\" | \"OPENEXPERT_MODEL_KEY\" | \"none (local)\";\n};\n\nexport function selectModel(env: NodeJS.ProcessEnv = process.env): ModelSelection {\n const raw = env[\"OPENEXPERT_MODEL_PROVIDER\"];\n const provider: ModelProviderId =\n raw === \"ollama\" || raw === \"openai-compatible\" ? raw : \"google\";\n\n if (provider === \"ollama\") {\n return {\n provider,\n modelId: env[\"OPENEXPERT_MODEL_ID\"] || \"llama3.1\",\n keySource: \"none (local)\",\n };\n }\n if (provider === \"openai-compatible\") {\n return {\n provider,\n modelId: env[\"OPENEXPERT_MODEL_ID\"] || \"gpt-4o-mini\",\n keySource: \"OPENEXPERT_MODEL_KEY\",\n };\n }\n return {\n provider: \"google\",\n modelId: env[\"OPENEXPERT_MODEL_ID\"] || \"gemini-2.5-flash\",\n keySource: \"GOOGLE_API_KEY\",\n };\n}\n\n/**\n * Ollama exposes two surfaces: the native API at the server root (`/api/*`)\n * and an OpenAI-compatible API under `/v1`. Callers may configure either\n * shape, so normalise before using it.\n */\nexport function ollamaApiBaseUrl(baseUrl: string): string {\n return baseUrl.trim().replace(/\\/+$/, \"\").replace(/\\/v1$/, \"\");\n}\n\nexport function ollamaChatBaseUrl(baseUrl: string): string {\n return `${ollamaApiBaseUrl(baseUrl)}/v1`;\n}\n\nexport function missingKeyHint(\n sel: ModelSelection,\n env: NodeJS.ProcessEnv = process.env,\n): string | null {\n if (sel.provider === \"ollama\") return null;\n if (sel.provider === \"google\" && !env[\"GOOGLE_API_KEY\"]) {\n return \"Falta GOOGLE_API_KEY (o usa OPENEXPERT_MODEL_PROVIDER=ollama para modelo local).\";\n }\n if (sel.provider === \"openai-compatible\" && !env[\"OPENEXPERT_MODEL_KEY\"]) {\n return \"Falta OPENEXPERT_MODEL_KEY para tu endpoint OpenAI-compatible.\";\n }\n return null;\n}\n","// SPDX-License-Identifier: MIT\n// Shared helpers for the OpenCore CLI: paths, config/secrets I/O, HTTP\n// detection, and release download with checksum verification.\n\nimport { spawn, spawnSync } from \"node:child_process\";\nimport { createHash } from \"node:crypto\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { ollamaApiBaseUrl } from \"../model-provider.js\";\n\nexport type Provider = \"google\" | \"ollama\" | \"openai-compatible\";\n\nexport type FileConfig = {\n modelProvider?: Provider;\n modelId?: string;\n ollamaBaseUrl?: string;\n dataDir?: string;\n};\n\nexport type Secrets = {\n GOOGLE_API_KEY?: string;\n GOOGLE_CLIENT_ID?: string;\n GOOGLE_CLIENT_SECRET?: string;\n OPENEXPERT_MODEL_KEY?: string;\n OPENEXPERT_BASE_URL?: string;\n};\n\nexport const DEFAULT_OLLAMA_URL = \"http://localhost:11434\";\nexport const DEFAULT_DATA_DIR = \"~/.openexpert\";\n\nexport function expandHome(p: string): string {\n if (p === \"~\") return homedir();\n if (p.startsWith(\"~/\")) return join(homedir(), p.slice(2));\n return p;\n}\n\nexport function packageRoot(): string {\n // dist/cli.js -> package root is one level up.\n return resolve(dirname(fileURLToPath(import.meta.url)), \"..\");\n}\n\nexport function packageVersion(): string {\n try {\n const pkg = JSON.parse(readFileSync(join(packageRoot(), \"package.json\"), \"utf8\")) as {\n version?: string;\n };\n return pkg.version ?? \"0.0.0\";\n } catch {\n return \"0.0.0\";\n }\n}\n\n/** Walk up from `start` to find a checkout (package.json + packages/opencore). */\nexport function findRepoRoot(start = process.cwd()): string | null {\n let dir = resolve(start);\n for (let i = 0; i < 8; i++) {\n if (\n existsSync(join(dir, \"package.json\")) &&\n existsSync(join(dir, \"packages\", \"opencore\")) &&\n existsSync(join(dir, \"vite.config.ts\"))\n ) {\n return dir;\n }\n const parent = resolve(dir, \"..\");\n if (parent === dir) break;\n dir = parent;\n }\n return null;\n}\n\nexport function configPath(cwd = process.cwd()): string {\n return join(cwd, \"openexpert.json\");\n}\n\nexport function readConfig(cwd = process.cwd()): FileConfig {\n try {\n const p = configPath(cwd);\n if (!existsSync(p)) return {};\n return JSON.parse(readFileSync(p, \"utf8\")) as FileConfig;\n } catch {\n return {};\n }\n}\n\nexport function writeConfig(cfg: FileConfig, cwd = process.cwd()): void {\n writeFileSync(configPath(cwd), JSON.stringify(cfg, null, 2) + \"\\n\");\n}\n\nexport function resolvedDataDir(cwd = process.cwd()): string {\n const cfg = readConfig(cwd);\n const raw = process.env[\"OPENEXPERT_DATA_DIR\"] || cfg.dataDir || DEFAULT_DATA_DIR;\n return expandHome(raw);\n}\n\nexport function secretsPath(cwd = process.cwd()): string {\n return join(resolvedDataDir(cwd), \"secrets.json\");\n}\n\nexport function readSecrets(cwd = process.cwd()): Secrets {\n try {\n const p = secretsPath(cwd);\n if (!existsSync(p)) return {};\n return JSON.parse(readFileSync(p, \"utf8\")) as Secrets;\n } catch {\n return {};\n }\n}\n\nexport function writeSecrets(secrets: Secrets, cwd = process.cwd()): string {\n const dir = resolvedDataDir(cwd);\n mkdirSync(dir, { recursive: true });\n const p = join(dir, \"secrets.json\");\n writeFileSync(p, JSON.stringify(secrets, null, 2), { mode: 0o600 });\n return p;\n}\n\n/** Merge stored secrets into the current environment for the child server. */\nexport function secretsAsEnv(cwd = process.cwd()): Record<string, string> {\n const s = readSecrets(cwd);\n const out: Record<string, string> = {};\n for (const [k, v] of Object.entries(s)) if (v) out[k] = v;\n return out;\n}\n\nexport async function httpGetJson<T>(\n url: string,\n opts: { headers?: Record<string, string>; timeoutMs?: number } = {},\n): Promise<T | null> {\n try {\n const res = await fetch(url, {\n ...(opts.headers ? { headers: opts.headers } : {}),\n signal: AbortSignal.timeout(opts.timeoutMs ?? 2500),\n });\n if (!res.ok) return null;\n return (await res.json()) as T;\n } catch {\n return null;\n }\n}\n\nexport async function detectOllama(\n baseUrl = DEFAULT_OLLAMA_URL,\n timeoutMs = 1500,\n): Promise<{ up: boolean; models: string[] }> {\n const root = ollamaApiBaseUrl(baseUrl);\n const data = await httpGetJson<{ models?: { name: string }[] }>(`${root}/api/tags`, {\n timeoutMs,\n });\n if (!data) return { up: false, models: [] };\n return { up: true, models: (data.models ?? []).map((m) => m.name) };\n}\n\nexport function appCacheDir(version: string): string {\n return join(expandHome(DEFAULT_DATA_DIR), \"app\", version);\n}\n\n/**\n * Ensure a standalone server build exists for `version`. Downloads the\n * release tarball published by the CI workflow and verifies its checksum.\n * Returns the directory containing `.output/server/index.mjs`, or null.\n */\nexport async function ensureStandaloneApp(\n version: string,\n opts: { repo?: string; log?: (m: string) => void } = {},\n): Promise<string | null> {\n const dir = appCacheDir(version);\n const entry = join(dir, \".output\", \"server\", \"index.mjs\");\n if (existsSync(entry)) return dir;\n\n const repo = opts.repo ?? \"OpenExpert-ai/OpenExpert\";\n const log = opts.log ?? (() => {});\n const tarball = `openexpert-server-${version}.tar.gz`;\n // Different tools tag releases differently; try the common shapes.\n const tags = [`v${version}`, `@openexpert/opencore@${version}`, version];\n\n for (const tag of tags) {\n const base = `https://github.com/${repo}/releases/download/${tag}`;\n const url = `${base}/${tarball}`;\n log(`downloading ${url}`);\n try {\n const res = await fetch(url, { signal: AbortSignal.timeout(60_000) });\n if (!res.ok) continue;\n const buf = Buffer.from(await res.arrayBuffer());\n\n // Verify checksum when the .sha256 asset is available.\n try {\n const shaRes = await fetch(`${base}/${tarball}.sha256`, {\n signal: AbortSignal.timeout(15_000),\n });\n if (shaRes.ok) {\n const expected = (await shaRes.text()).trim().split(/\\s+/)[0];\n const actual = createHash(\"sha256\").update(buf).digest(\"hex\");\n if (expected && expected !== actual) {\n log(\"checksum mismatch, aborting\");\n return null;\n }\n }\n } catch {\n // No checksum asset: continue (release is fetched over HTTPS).\n }\n\n mkdirSync(dir, { recursive: true });\n const tmp = join(dir, tarball);\n writeFileSync(tmp, buf);\n const r = spawnSync(\"tar\", [\"-xzf\", tmp, \"-C\", dir], { stdio: \"ignore\" });\n if (r.status !== 0) return null;\n return existsSync(entry) ? dir : null;\n } catch {\n // try the next tag\n }\n }\n return null;\n}\n\nexport function run(\n cmd: string,\n args: string[],\n opts: { cwd?: string; env?: NodeJS.ProcessEnv } = {},\n): Promise<number> {\n return new Promise((res) => {\n const child = spawn(cmd, args, { stdio: \"inherit\", cwd: opts.cwd, env: opts.env });\n const forward = (sig: NodeJS.Signals) => () => child.kill(sig);\n process.on(\"SIGINT\", forward(\"SIGINT\"));\n process.on(\"SIGTERM\", forward(\"SIGTERM\"));\n child.on(\"exit\", (code) => res(code ?? 0));\n });\n}\n","// SPDX-License-Identifier: MIT\n// Non-interactive CLI commands: doctor, fix, models, serve, version, update.\n\nimport { existsSync, mkdirSync, rmSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { ollamaApiBaseUrl } from \"../model-provider.js\";\nimport {\n DEFAULT_OLLAMA_URL,\n appCacheDir,\n detectOllama,\n ensureStandaloneApp,\n findRepoRoot,\n httpGetJson,\n packageVersion,\n readConfig,\n readSecrets,\n resolvedDataDir,\n run,\n secretsAsEnv,\n writeConfig,\n type Provider,\n} from \"./lib.js\";\n\nexport function cmdVersion(): number {\n console.log(`@openexpert/opencore ${packageVersion()}`);\n return 0;\n}\n\nfunction configuredProvider(): Provider {\n const raw = process.env[\"OPENEXPERT_MODEL_PROVIDER\"] || readConfig().modelProvider;\n if (raw === \"ollama\" || raw === \"openai-compatible\") return raw;\n return \"google\";\n}\n\nexport function cmdDoctor(cwd = process.cwd()): number {\n const provider = configuredProvider();\n const dataDir = resolvedDataDir(cwd);\n const secrets = readSecrets(cwd);\n\n console.log(\"OpenCore doctor\");\n console.log(` provider: ${provider}`);\n console.log(` data dir: ${dataDir}`);\n\n const problems: string[] = [];\n\n if (provider === \"google\" && !process.env[\"GOOGLE_API_KEY\"] && !secrets.GOOGLE_API_KEY) {\n problems.push(\"Falta GOOGLE_API_KEY. Ejecuta `opencore init` o usa Ollama.\");\n }\n if (provider === \"openai-compatible\") {\n if (!process.env[\"OPENEXPERT_MODEL_KEY\"] && !secrets.OPENEXPERT_MODEL_KEY) {\n problems.push(\"Falta OPENEXPERT_MODEL_KEY.\");\n }\n if (!process.env[\"OPENEXPERT_BASE_URL\"] && !secrets.OPENEXPERT_BASE_URL) {\n problems.push(\"Falta OPENEXPERT_BASE_URL.\");\n }\n }\n if (provider === \"ollama\") {\n console.log(` ollama: ${process.env[\"OLLAMA_BASE_URL\"] || DEFAULT_OLLAMA_URL}`);\n }\n if (!process.env[\"GOOGLE_CLIENT_ID\"] && !secrets.GOOGLE_CLIENT_ID) {\n console.log(\" note: sin Google OAuth el chat funciona; Drive queda desconectado.\");\n }\n try {\n mkdirSync(dataDir, { recursive: true });\n } catch {\n problems.push(`No se puede escribir en ${dataDir}.`);\n }\n\n if (!problems.length) {\n console.log(\" OK: listo para arrancar.\");\n return 0;\n }\n console.log(\" pendiente:\");\n for (const x of problems) console.log(` - ${x}`);\n return 1;\n}\n\nexport async function cmdFix(cwd = process.cwd()): Promise<number> {\n const dataDir = resolvedDataDir(cwd);\n mkdirSync(dataDir, { recursive: true });\n\n if (!existsSync(join(cwd, \"openexpert.json\"))) {\n const ollama = await detectOllama();\n writeConfig(\n {\n modelProvider: \"ollama\",\n modelId: ollama.models[0] ?? \"llama3.1\",\n ollamaBaseUrl: DEFAULT_OLLAMA_URL,\n dataDir: \"~/.openexpert\",\n },\n cwd,\n );\n console.log(\"✓ openexpert.json creado (Ollama).\");\n } else {\n console.log(\"• openexpert.json ya existe.\");\n }\n\n const secrets = readSecrets(cwd);\n if (Object.keys(secrets).length) {\n const p = join(dataDir, \"secrets.json\");\n writeFileSync(p, JSON.stringify(secrets, null, 2), { mode: 0o600 });\n console.log(`✓ permisos de ${p} normalizados (0600).`);\n }\n\n console.log(\"✓ directorio de datos listo:\", dataDir);\n cmdDoctor(cwd);\n console.log(\"\\nSiguiente paso: `opencore serve` (o `opencore init` para elegir modelo).\");\n return 0;\n}\n\nexport async function cmdModels(cwd = process.cwd()): Promise<number> {\n const provider = configuredProvider();\n const secrets = readSecrets(cwd);\n const cfg = readConfig(cwd);\n\n if (provider === \"ollama\") {\n const base = ollamaApiBaseUrl(\n process.env[\"OLLAMA_BASE_URL\"] || cfg.ollamaBaseUrl || DEFAULT_OLLAMA_URL,\n );\n const { up, models } = await detectOllama(base);\n if (!up) {\n console.log(`No se puede contactar con Ollama en ${base}.`);\n console.log(\"Instálalo con: curl -fsSL https://ollama.com/install.sh | sh\");\n return 1;\n }\n console.log(`Modelos en Ollama (${base}):`);\n for (const m of models) console.log(` ${m === cfg.modelId ? \"*\" : \" \"} ${m}`);\n if (!models.length) console.log(\" (ninguno; prueba `ollama pull llama3.1`)\");\n return 0;\n }\n\n if (provider === \"openai-compatible\") {\n const base = process.env[\"OPENEXPERT_BASE_URL\"] || secrets.OPENEXPERT_BASE_URL;\n const key = process.env[\"OPENEXPERT_MODEL_KEY\"] || secrets.OPENEXPERT_MODEL_KEY;\n if (!base || !key) {\n console.log(\"Configura OPENEXPERT_BASE_URL y OPENEXPERT_MODEL_KEY (opencore init).\");\n return 1;\n }\n const data = await httpGetJson<{ data?: { id: string }[] }>(\n `${base.replace(/\\/+$/, \"\")}/models`,\n { headers: { Authorization: `Bearer ${key}` } },\n );\n if (!data) {\n console.log(\"No se pudo listar modelos del endpoint.\");\n return 1;\n }\n console.log(\"Modelos disponibles:\");\n for (const m of data.data ?? []) console.log(` ${m.id === cfg.modelId ? \"*\" : \" \"} ${m.id}`);\n return 0;\n }\n\n console.log(\"Proveedor google: usa `gemini-2.5-flash` o consulta Google AI Studio.\");\n return 0;\n}\n\nexport async function cmdServe(cwd = process.cwd()): Promise<number> {\n const env = { ...process.env, ...secretsAsEnv(cwd) } as NodeJS.ProcessEnv;\n\n const repo = findRepoRoot(cwd);\n if (repo) {\n console.log(\"Arrancando OpenExpert (desde el código fuente)…\");\n return run(\"npm\", [\"run\", \"dev\"], { cwd: repo, env });\n }\n\n const version = packageVersion();\n const app = await ensureStandaloneApp(version, { log: (m) => console.log(` ${m}`) });\n if (!app) {\n console.error(\n \"No hay un servidor preconstruido disponible y no se pudo descargar.\\n\" +\n \"Opciones:\\n\" +\n \" • Usa Docker: docker run -p 3000:3000 -v openexpert-data:/data ghcr.io/openexpert-ai/openexpert:local\\n\" +\n \" • O clona el repositorio y ejecuta `npm ci && npm run dev`.\",\n );\n return 1;\n }\n console.log(\"Arrancando OpenCore en http://localhost:3000 …\");\n return run(process.execPath, [join(app, \".output\", \"server\", \"index.mjs\")], {\n cwd: app,\n env: { ...env, PORT: process.env[\"PORT\"] || \"3000\" },\n });\n}\n\nexport function cmdUpdate(): number {\n const dir = appCacheDir(packageVersion());\n if (existsSync(dir)) {\n rmSync(dir, { recursive: true, force: true });\n console.log(`✓ caché del servidor eliminada (${dir}).`);\n } else {\n console.log(\"No hay servidor descargado que actualizar.\");\n }\n return 0;\n}\n","// SPDX-License-Identifier: MIT\n// `opencore desktop` — start the local server (unless it is already running)\n// and open the native OpenExpert window (the Tauri shell). This command owns\n// the server lifecycle so it can stop the server when the window closes.\n//\n// The repository is located from the CLI installation itself (not the current\n// directory), so `OpenExpert` works from anywhere.\n\nimport { spawn, type ChildProcess } from \"node:child_process\";\nimport { existsSync, readdirSync, statSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport {\n ensureStandaloneApp,\n findRepoRoot,\n packageRoot,\n packageVersion,\n secretsAsEnv,\n} from \"./lib.js\";\n\nfunction port(): string {\n return process.env[\"PORT\"] || \"3000\";\n}\n\nfunction appUrl(): string {\n return `http://localhost:${port()}`;\n}\n\nasync function isServerUp(timeoutMs = 1500): Promise<boolean> {\n try {\n const res = await fetch(appUrl(), { signal: AbortSignal.timeout(timeoutMs) });\n return res.status < 500;\n } catch {\n return false;\n }\n}\n\nasync function waitForServer(timeoutMs = 120_000): Promise<boolean> {\n const start = Date.now();\n while (Date.now() - start < timeoutMs) {\n if (await isServerUp()) return true;\n await new Promise((r) => setTimeout(r, 400));\n }\n return false;\n}\n\n/**\n * Find the source checkout, in order of confidence:\n * 1. OPENEXPERT_DESKTOP_REPO (baked by the installer),\n * 2. relative to the CLI installation (packages/opencore → repo root),\n * 3. walking up from the current directory.\n */\nfunction resolveRepo(cwd: string): string | null {\n const fromEnv = process.env[\"OPENEXPERT_DESKTOP_REPO\"];\n if (fromEnv) {\n const r = findRepoRoot(fromEnv);\n if (r) return r;\n }\n return findRepoRoot(packageRoot()) ?? findRepoRoot(cwd);\n}\n\n/** Newest modification time (ms) under a directory, or 0 if unreadable. */\nfunction newestMtime(dir: string): number {\n let newest = 0;\n try {\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n const full = join(dir, entry.name);\n if (entry.isDirectory()) newest = Math.max(newest, newestMtime(full));\n else if (entry.isFile()) newest = Math.max(newest, statSync(full).mtimeMs);\n }\n } catch {\n // ignore unreadable paths\n }\n return newest;\n}\n\n/** True when the production build exists and is not older than src/. */\nfunction buildIsFresh(repo: string): boolean {\n const built = join(repo, \".output\", \"server\", \"index.mjs\");\n if (!existsSync(built)) return false;\n try {\n return statSync(built).mtimeMs >= newestMtime(join(repo, \"src\"));\n } catch {\n return true;\n }\n}\n\n/** Start the local server, reusing the source checkout when available. */\nasync function spawnServer(cwd: string, env: NodeJS.ProcessEnv): Promise<ChildProcess | null> {\n const repo = resolveRepo(cwd);\n if (repo) {\n const built = join(repo, \".output\", \"server\", \"index.mjs\");\n if (existsSync(built) && buildIsFresh(repo)) {\n return spawn(process.execPath, [built], {\n cwd: repo,\n env: { ...env, NODE_ENV: \"production\", PORT: port() },\n stdio: \"inherit\",\n });\n }\n console.log(\n existsSync(built)\n ? \"La build está desactualizada; arrancando en modo desarrollo…\"\n : \"Arrancando el servidor en modo desarrollo (no hay build)…\",\n );\n return spawn(\"npm\", [\"run\", \"dev\"], { cwd: repo, env, stdio: \"inherit\" });\n }\n\n const app = await ensureStandaloneApp(packageVersion(), { log: (m) => console.log(` ${m}`) });\n if (!app) return null;\n return spawn(process.execPath, [join(app, \".output\", \"server\", \"index.mjs\")], {\n cwd: app,\n env: { ...env, NODE_ENV: \"production\", PORT: port() },\n stdio: \"inherit\",\n });\n}\n\nfunction findDesktopBinary(cwd: string): string | null {\n const fromEnv = process.env[\"OPENEXPERT_DESKTOP_BIN\"];\n if (fromEnv && existsSync(fromEnv)) return fromEnv;\n\n const candidates = [join(homedir(), \".local\", \"bin\", \"openexpert-desktop\")];\n const repo = resolveRepo(cwd);\n if (repo) {\n candidates.push(\n join(repo, \"src-tauri\", \"target\", \"release\", \"openexpert-desktop\"),\n join(repo, \"src-tauri\", \"target\", \"debug\", \"openexpert-desktop\"),\n );\n }\n return candidates.find((c) => existsSync(c)) ?? null;\n}\n\nexport async function cmdDesktop(cwd = process.cwd()): Promise<number> {\n const env = { ...process.env, ...secretsAsEnv(cwd) } as NodeJS.ProcessEnv;\n\n const bin = findDesktopBinary(cwd);\n if (!bin) {\n console.error(\n \"No se encontró la ventana de escritorio (openexpert-desktop).\\n\" +\n \"Compílala con `npx tauri build` o usa `npm run desktop:install`.\",\n );\n return 1;\n }\n\n let server: ChildProcess | null = null;\n let startedServer = false;\n\n if (await isServerUp()) {\n console.log(`• Usando el servidor ya activo en ${appUrl()}`);\n } else {\n console.log(\"Arrancando el servidor local…\");\n server = await spawnServer(cwd, env);\n if (!server) {\n console.error(\n \"No se pudo arrancar el servidor.\\n\" +\n \"Si usas el código fuente, entra en el repositorio y ejecuta:\\n\" +\n \" npm ci && npm run build && npm run desktop:install\",\n );\n return 1;\n }\n startedServer = true;\n if (!(await waitForServer())) {\n console.error(\"El servidor no respondió a tiempo.\");\n server.kill(\"SIGTERM\");\n return 1;\n }\n }\n\n const stopServer = (): void => {\n if (startedServer && server && !server.killed) {\n try {\n server.kill(\"SIGTERM\");\n } catch {\n // already gone\n }\n }\n };\n\n const onSignal = (): void => {\n stopServer();\n process.exit(0);\n };\n process.once(\"SIGINT\", onSignal);\n process.once(\"SIGTERM\", onSignal);\n\n console.log(\"Abriendo la ventana de OpenExpert…\");\n const code = await new Promise<number>((resolve) => {\n const win = spawn(bin, [], { stdio: \"inherit\", env });\n win.on(\"exit\", (c) => resolve(c ?? 0));\n });\n\n stopServer();\n return code;\n}\n","// SPDX-License-Identifier: MIT\n// Interactive setup wizard: pick a model provider, write config + secrets.\n\nimport * as p from \"@clack/prompts\";\nimport {\n DEFAULT_OLLAMA_URL,\n detectOllama,\n readConfig,\n writeConfig,\n writeSecrets,\n type FileConfig,\n type Provider,\n type Secrets,\n} from \"./lib.js\";\n\nexport type WizardResult = {\n config: FileConfig;\n secrets: Secrets;\n provider: Provider;\n modelId: string;\n started: boolean;\n};\n\nfunction bail(): never {\n p.cancel(\"Configuración cancelada.\");\n process.exit(1);\n}\n\nexport async function runWizard(\n opts: { cwd?: string; assumeYes?: boolean } = {},\n): Promise<WizardResult> {\n const cwd = opts.cwd ?? process.cwd();\n const existing = readConfig(cwd);\n const nonInteractive = opts.assumeYes || !process.stdin.isTTY;\n\n if (nonInteractive) {\n const ollama = await detectOllama();\n const config: FileConfig = {\n modelProvider: \"ollama\",\n modelId: ollama.models[0] ?? \"llama3.1\",\n ollamaBaseUrl: DEFAULT_OLLAMA_URL,\n dataDir: \"~/.openexpert\",\n };\n writeConfig(config, cwd);\n return { config, secrets: {}, provider: \"ollama\", modelId: config.modelId!, started: false };\n }\n\n p.intro(\"OpenCore — configuración\");\n\n const spin = p.spinner();\n spin.start(\"Buscando Ollama local…\");\n const ollama = await detectOllama();\n spin.stop(\n ollama.up\n ? `Ollama detectado (${ollama.models.length} modelo(s))`\n : \"No se ha detectado Ollama\",\n );\n\n const choice = await p.select({\n message: \"¿Qué modelo quieres usar?\",\n options: [\n ...(ollama.up\n ? [\n {\n value: \"ollama\" as const,\n label: \"Modelo local (Ollama)\",\n hint: \"sin claves, datos en tu equipo\",\n },\n ]\n : []),\n { value: \"google\" as const, label: \"Google Gemini (clave gratuita)\", hint: \"AI Studio\" },\n { value: \"openai-compatible\" as const, label: \"Otro endpoint compatible\", hint: \"BYOK\" },\n ...(!ollama.up\n ? [{ value: \"install-ollama\" as const, label: \"Instalar Ollama\", hint: \"te muestro cómo\" }]\n : []),\n ],\n });\n if (p.isCancel(choice)) bail();\n\n if (choice === \"install-ollama\") {\n p.note(\n \"Instala Ollama y descarga un modelo:\\n\\n\" +\n \" curl -fsSL https://ollama.com/install.sh | sh\\n\" +\n \" ollama pull llama3.1\\n\\n\" +\n \"Vuelve a ejecutar `opencore init` cuando esté listo.\",\n \"Instalar Ollama\",\n );\n p.outro(\"Sin cambios.\");\n process.exit(0);\n }\n\n const config: FileConfig = { dataDir: \"~/.openexpert\" };\n const secrets: Secrets = {};\n let modelId = \"llama3.1\";\n\n if (choice === \"ollama\") {\n const models = ollama.models.length ? ollama.models : [\"llama3.1\"];\n const picked = await p.select({\n message: \"Modelo de Ollama\",\n options: models.map((m) => ({ value: m, label: m })),\n });\n if (p.isCancel(picked)) bail();\n modelId = String(picked);\n config.modelProvider = \"ollama\";\n config.modelId = modelId;\n config.ollamaBaseUrl = DEFAULT_OLLAMA_URL;\n } else if (choice === \"google\") {\n const apiKey = await p.password({ message: \"GOOGLE_API_KEY (AI Studio)\" });\n if (p.isCancel(apiKey)) bail();\n const id = await p.text({ message: \"Modelo\", initialValue: \"gemini-2.5-flash\" });\n if (p.isCancel(id)) bail();\n modelId = String(id) || \"gemini-2.5-flash\";\n config.modelProvider = \"google\";\n config.modelId = modelId;\n secrets.GOOGLE_API_KEY = String(apiKey);\n } else if (choice === \"openai-compatible\") {\n const baseURL = await p.text({ message: \"Base URL (…/v1)\", initialValue: \"\" });\n if (p.isCancel(baseURL)) bail();\n const apiKey = await p.password({ message: \"API key\" });\n if (p.isCancel(apiKey)) bail();\n const id = await p.text({ message: \"Modelo\", initialValue: \"gpt-4o-mini\" });\n if (p.isCancel(id)) bail();\n modelId = String(id) || \"gpt-4o-mini\";\n config.modelProvider = \"openai-compatible\";\n config.modelId = modelId;\n secrets.OPENEXPERT_BASE_URL = String(baseURL);\n secrets.OPENEXPERT_MODEL_KEY = String(apiKey);\n }\n\n writeConfig({ ...existing, ...config }, cwd);\n if (Object.keys(secrets).length) writeSecrets({ ...secrets }, cwd);\n\n p.outro(\n `Configuración guardada en openexpert.json (modelo: ${config.modelProvider}:${modelId}).`,\n );\n\n const go = await p.confirm({ message: \"¿Arrancar ahora?\", initialValue: true });\n if (p.isCancel(go)) bail();\n\n return {\n config: { ...existing, ...config },\n secrets,\n provider: config.modelProvider as Provider,\n modelId,\n started: Boolean(go),\n };\n}\n","// SPDX-License-Identifier: MIT\n// OpenCore CLI entry point. Dispatches subcommands. See `run`.\n\nimport { cmdDoctor, cmdFix, cmdModels, cmdServe, cmdUpdate, cmdVersion } from \"./cli/commands.js\";\nimport { cmdDesktop } from \"./cli/desktop.js\";\nimport { runWizard } from \"./cli/wizard.js\";\n\nfunction help(): void {\n console.log(`opencore — motor abierto de OpenExpert\n\nUso:\n opencore asistente de configuración y arranque\n opencore init igual que sin argumentos\n opencore serve arranca la edición local en http://localhost:3000\n opencore desktop arranca el servidor y abre la ventana de escritorio\n opencore doctor revisa tu configuración\n opencore fix auto-configura lo que falte\n opencore models lista los modelos del proveedor actual\n opencore update limpia la caché del servidor descargado\n opencore version muestra la versión\n\nEjemplos:\n npx @openexpert/opencore\n npx @openexpert/opencore serve\n\nDocker (sin Node):\n docker run -p 3000:3000 -v openexpert-data:/data ghcr.io/openexpert-ai/openexpert`);\n}\n\nexport async function run(argv: string[]): Promise<void> {\n const cmd = argv[0] ?? \"\";\n switch (cmd) {\n case \"\":\n case \"init\":\n case \"setup\": {\n const res = await runWizard({});\n if (res.started) process.exit(await cmdServe());\n return;\n }\n case \"doctor\":\n return process.exit(cmdDoctor());\n case \"fix\":\n return process.exit(await cmdFix());\n case \"models\":\n return process.exit(await cmdModels());\n case \"serve\":\n case \"dev\":\n return process.exit(await cmdServe());\n case \"desktop\":\n case \"app\": {\n const code = await cmdDesktop();\n return process.exit(code);\n }\n case \"update\":\n return process.exit(cmdUpdate());\n case \"version\":\n case \"--version\":\n case \"-v\":\n return process.exit(cmdVersion());\n case \"help\":\n case \"--help\":\n case \"-h\":\n help();\n return;\n default:\n console.error(`Comando desconocido: ${cmd}\\n`);\n help();\n return process.exit(1);\n }\n}\n"]}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { ModelProviderId } from './model-provider.js';
|
|
2
|
+
|
|
3
|
+
type AiConfig = {
|
|
4
|
+
temperature: number;
|
|
5
|
+
topP: number;
|
|
6
|
+
maxOutputTokens: number;
|
|
7
|
+
};
|
|
8
|
+
type ChatConfig = {
|
|
9
|
+
maxSteps: number;
|
|
10
|
+
injectionGuard: boolean;
|
|
11
|
+
injectionExtraPatterns: string[];
|
|
12
|
+
retentionDays: number;
|
|
13
|
+
};
|
|
14
|
+
type OpenExpertConfig = {
|
|
15
|
+
modelProvider: ModelProviderId;
|
|
16
|
+
modelId: string;
|
|
17
|
+
ollamaBaseUrl: string;
|
|
18
|
+
dataDir: string;
|
|
19
|
+
ai: AiConfig;
|
|
20
|
+
chat: ChatConfig;
|
|
21
|
+
};
|
|
22
|
+
declare const DEFAULTS: OpenExpertConfig;
|
|
23
|
+
declare function loadConfig(cwd?: string): OpenExpertConfig;
|
|
24
|
+
|
|
25
|
+
export { type AiConfig, type ChatConfig, DEFAULTS, type OpenExpertConfig, loadConfig };
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'fs';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
|
|
4
|
+
// src/config.ts
|
|
5
|
+
var DEFAULTS = {
|
|
6
|
+
modelProvider: "google",
|
|
7
|
+
modelId: "gemini-2.5-flash",
|
|
8
|
+
ollamaBaseUrl: "http://localhost:11434",
|
|
9
|
+
dataDir: "~/.openexpert",
|
|
10
|
+
ai: { temperature: 0.2, topP: 1, maxOutputTokens: 4096 },
|
|
11
|
+
chat: {
|
|
12
|
+
maxSteps: 50,
|
|
13
|
+
injectionGuard: true,
|
|
14
|
+
injectionExtraPatterns: [],
|
|
15
|
+
retentionDays: 30
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
function expandHome(p) {
|
|
19
|
+
if (p.startsWith("~/")) {
|
|
20
|
+
const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
|
|
21
|
+
return join(home, p.slice(2));
|
|
22
|
+
}
|
|
23
|
+
return p;
|
|
24
|
+
}
|
|
25
|
+
function num(value, fallback) {
|
|
26
|
+
const n = typeof value === "string" ? Number(value) : value;
|
|
27
|
+
return typeof n === "number" && Number.isFinite(n) ? n : fallback;
|
|
28
|
+
}
|
|
29
|
+
function loadConfig(cwd = process.cwd()) {
|
|
30
|
+
let file = {};
|
|
31
|
+
const path = join(cwd, "openexpert.json");
|
|
32
|
+
if (existsSync(path)) {
|
|
33
|
+
try {
|
|
34
|
+
file = JSON.parse(readFileSync(path, "utf8"));
|
|
35
|
+
} catch {
|
|
36
|
+
file = {};
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
const env = process.env;
|
|
40
|
+
const providerEnv = env["OPENEXPERT_MODEL_PROVIDER"];
|
|
41
|
+
const providerFromEnv = providerEnv === "google" || providerEnv === "ollama" || providerEnv === "openai-compatible" ? providerEnv : void 0;
|
|
42
|
+
const fileAi = file.ai ?? {};
|
|
43
|
+
const fileChat = file.chat ?? {};
|
|
44
|
+
return {
|
|
45
|
+
modelProvider: providerFromEnv ?? file.modelProvider ?? DEFAULTS.modelProvider,
|
|
46
|
+
modelId: env["OPENEXPERT_MODEL_ID"] ?? file.modelId ?? DEFAULTS.modelId,
|
|
47
|
+
ollamaBaseUrl: env["OLLAMA_BASE_URL"] ?? file.ollamaBaseUrl ?? DEFAULTS.ollamaBaseUrl,
|
|
48
|
+
dataDir: expandHome(env["OPENEXPERT_DATA_DIR"] ?? file.dataDir ?? DEFAULTS.dataDir),
|
|
49
|
+
ai: {
|
|
50
|
+
temperature: num(fileAi.temperature, DEFAULTS.ai.temperature),
|
|
51
|
+
topP: num(fileAi.topP, DEFAULTS.ai.topP),
|
|
52
|
+
maxOutputTokens: num(fileAi.maxOutputTokens, DEFAULTS.ai.maxOutputTokens)
|
|
53
|
+
},
|
|
54
|
+
chat: {
|
|
55
|
+
maxSteps: num(fileChat.maxSteps, DEFAULTS.chat.maxSteps),
|
|
56
|
+
injectionGuard: fileChat.injectionGuard ?? DEFAULTS.chat.injectionGuard,
|
|
57
|
+
injectionExtraPatterns: Array.isArray(fileChat.injectionExtraPatterns) ? fileChat.injectionExtraPatterns.filter((p) => typeof p === "string") : DEFAULTS.chat.injectionExtraPatterns,
|
|
58
|
+
retentionDays: num(fileChat.retentionDays, DEFAULTS.chat.retentionDays)
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export { DEFAULTS, loadConfig };
|
|
64
|
+
//# sourceMappingURL=config.js.map
|
|
65
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/config.ts"],"names":[],"mappings":";;;;AA8BO,IAAM,QAAA,GAA6B;AAAA,EACxC,aAAA,EAAe,QAAA;AAAA,EACf,OAAA,EAAS,kBAAA;AAAA,EACT,aAAA,EAAe,wBAAA;AAAA,EACf,OAAA,EAAS,eAAA;AAAA,EACT,IAAI,EAAE,WAAA,EAAa,KAAK,IAAA,EAAM,CAAA,EAAG,iBAAiB,IAAA,EAAK;AAAA,EACvD,IAAA,EAAM;AAAA,IACJ,QAAA,EAAU,EAAA;AAAA,IACV,cAAA,EAAgB,IAAA;AAAA,IAChB,wBAAwB,EAAC;AAAA,IACzB,aAAA,EAAe;AAAA;AAEnB;AAEA,SAAS,WAAW,CAAA,EAAmB;AACrC,EAAA,IAAI,CAAA,CAAE,UAAA,CAAW,IAAI,CAAA,EAAG;AACtB,IAAA,MAAM,IAAA,GAAO,QAAQ,GAAA,CAAI,MAAM,KAAK,OAAA,CAAQ,GAAA,CAAI,aAAa,CAAA,IAAK,GAAA;AAClE,IAAA,OAAO,IAAA,CAAK,IAAA,EAAM,CAAA,CAAE,KAAA,CAAM,CAAC,CAAC,CAAA;AAAA,EAC9B;AACA,EAAA,OAAO,CAAA;AACT;AAEA,SAAS,GAAA,CAAI,OAAgB,QAAA,EAA0B;AACrD,EAAA,MAAM,IAAI,OAAO,KAAA,KAAU,QAAA,GAAW,MAAA,CAAO,KAAK,CAAA,GAAI,KAAA;AACtD,EAAA,OAAO,OAAO,CAAA,KAAM,QAAA,IAAY,OAAO,QAAA,CAAS,CAAC,IAAI,CAAA,GAAI,QAAA;AAC3D;AAEO,SAAS,UAAA,CAAW,GAAA,GAAc,OAAA,CAAQ,GAAA,EAAI,EAAqB;AACxE,EAAA,IAAI,OAAkC,EAAC;AACvC,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,GAAA,EAAK,iBAAiB,CAAA;AACxC,EAAA,IAAI,UAAA,CAAW,IAAI,CAAA,EAAG;AACpB,IAAA,IAAI;AACF,MAAA,IAAA,GAAO,IAAA,CAAK,KAAA,CAAM,YAAA,CAAa,IAAA,EAAM,MAAM,CAAC,CAAA;AAAA,IAC9C,CAAA,CAAA,MAAQ;AAEN,MAAA,IAAA,GAAO,EAAC;AAAA,IACV;AAAA,EACF;AACA,EAAA,MAAM,MAAM,OAAA,CAAQ,GAAA;AACpB,EAAA,MAAM,WAAA,GAAc,IAAI,2BAA2B,CAAA;AACnD,EAAA,MAAM,kBACJ,WAAA,KAAgB,QAAA,IAAY,gBAAgB,QAAA,IAAY,WAAA,KAAgB,sBACpE,WAAA,GACA,MAAA;AAEN,EAAA,MAAM,MAAA,GAA4B,IAAA,CAAK,EAAA,IAAM,EAAC;AAC9C,EAAA,MAAM,QAAA,GAAgC,IAAA,CAAK,IAAA,IAAQ,EAAC;AAEpD,EAAA,OAAO;AAAA,IACL,aAAA,EAAe,eAAA,IAAmB,IAAA,CAAK,aAAA,IAAiB,QAAA,CAAS,aAAA;AAAA,IACjE,SAAS,GAAA,CAAI,qBAAqB,CAAA,IAAK,IAAA,CAAK,WAAW,QAAA,CAAS,OAAA;AAAA,IAChE,eAAe,GAAA,CAAI,iBAAiB,CAAA,IAAK,IAAA,CAAK,iBAAiB,QAAA,CAAS,aAAA;AAAA,IACxE,OAAA,EAAS,WAAW,GAAA,CAAI,qBAAqB,KAAK,IAAA,CAAK,OAAA,IAAW,SAAS,OAAO,CAAA;AAAA,IAClF,EAAA,EAAI;AAAA,MACF,aAAa,GAAA,CAAI,MAAA,CAAO,WAAA,EAAa,QAAA,CAAS,GAAG,WAAW,CAAA;AAAA,MAC5D,MAAM,GAAA,CAAI,MAAA,CAAO,IAAA,EAAM,QAAA,CAAS,GAAG,IAAI,CAAA;AAAA,MACvC,iBAAiB,GAAA,CAAI,MAAA,CAAO,eAAA,EAAiB,QAAA,CAAS,GAAG,eAAe;AAAA,KAC1E;AAAA,IACA,IAAA,EAAM;AAAA,MACJ,UAAU,GAAA,CAAI,QAAA,CAAS,QAAA,EAAU,QAAA,CAAS,KAAK,QAAQ,CAAA;AAAA,MACvD,cAAA,EAAgB,QAAA,CAAS,cAAA,IAAkB,QAAA,CAAS,IAAA,CAAK,cAAA;AAAA,MACzD,wBAAwB,KAAA,CAAM,OAAA,CAAQ,QAAA,CAAS,sBAAsB,IACjE,QAAA,CAAS,sBAAA,CAAuB,MAAA,CAAO,CAAC,MAAmB,OAAO,CAAA,KAAM,QAAQ,CAAA,GAChF,SAAS,IAAA,CAAK,sBAAA;AAAA,MAClB,eAAe,GAAA,CAAI,QAAA,CAAS,aAAA,EAAe,QAAA,CAAS,KAAK,aAAa;AAAA;AACxE,GACF;AACF","file":"config.js","sourcesContent":["// SPDX-License-Identifier: MIT\n// OpenCore — local configuration.\n// Precedence: OPENEXPERT_* env vars > openexpert.json > defaults.\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { ModelProviderId } from \"./model-provider.js\";\n\nexport type AiConfig = {\n temperature: number;\n topP: number;\n maxOutputTokens: number;\n};\n\nexport type ChatConfig = {\n maxSteps: number;\n injectionGuard: boolean;\n injectionExtraPatterns: string[];\n retentionDays: number;\n};\n\nexport type OpenExpertConfig = {\n modelProvider: ModelProviderId;\n modelId: string;\n ollamaBaseUrl: string;\n dataDir: string;\n ai: AiConfig;\n chat: ChatConfig;\n};\n\nexport const DEFAULTS: OpenExpertConfig = {\n modelProvider: \"google\",\n modelId: \"gemini-2.5-flash\",\n ollamaBaseUrl: \"http://localhost:11434\",\n dataDir: \"~/.openexpert\",\n ai: { temperature: 0.2, topP: 1, maxOutputTokens: 4096 },\n chat: {\n maxSteps: 50,\n injectionGuard: true,\n injectionExtraPatterns: [],\n retentionDays: 30,\n },\n};\n\nfunction expandHome(p: string): string {\n if (p.startsWith(\"~/\")) {\n const home = process.env[\"HOME\"] || process.env[\"USERPROFILE\"] || \"~\";\n return join(home, p.slice(2));\n }\n return p;\n}\n\nfunction num(value: unknown, fallback: number): number {\n const n = typeof value === \"string\" ? Number(value) : value;\n return typeof n === \"number\" && Number.isFinite(n) ? n : fallback;\n}\n\nexport function loadConfig(cwd: string = process.cwd()): OpenExpertConfig {\n let file: Partial<OpenExpertConfig> = {};\n const path = join(cwd, \"openexpert.json\");\n if (existsSync(path)) {\n try {\n file = JSON.parse(readFileSync(path, \"utf8\")) as Partial<OpenExpertConfig>;\n } catch {\n // Broken file: ignore it, env/defaults win.\n file = {};\n }\n }\n const env = process.env;\n const providerEnv = env[\"OPENEXPERT_MODEL_PROVIDER\"];\n const providerFromEnv: ModelProviderId | undefined =\n providerEnv === \"google\" || providerEnv === \"ollama\" || providerEnv === \"openai-compatible\"\n ? providerEnv\n : undefined;\n\n const fileAi: Partial<AiConfig> = file.ai ?? {};\n const fileChat: Partial<ChatConfig> = file.chat ?? {};\n\n return {\n modelProvider: providerFromEnv ?? file.modelProvider ?? DEFAULTS.modelProvider,\n modelId: env[\"OPENEXPERT_MODEL_ID\"] ?? file.modelId ?? DEFAULTS.modelId,\n ollamaBaseUrl: env[\"OLLAMA_BASE_URL\"] ?? file.ollamaBaseUrl ?? DEFAULTS.ollamaBaseUrl,\n dataDir: expandHome(env[\"OPENEXPERT_DATA_DIR\"] ?? file.dataDir ?? DEFAULTS.dataDir),\n ai: {\n temperature: num(fileAi.temperature, DEFAULTS.ai.temperature),\n topP: num(fileAi.topP, DEFAULTS.ai.topP),\n maxOutputTokens: num(fileAi.maxOutputTokens, DEFAULTS.ai.maxOutputTokens),\n },\n chat: {\n maxSteps: num(fileChat.maxSteps, DEFAULTS.chat.maxSteps),\n injectionGuard: fileChat.injectionGuard ?? DEFAULTS.chat.injectionGuard,\n injectionExtraPatterns: Array.isArray(fileChat.injectionExtraPatterns)\n ? fileChat.injectionExtraPatterns.filter((p): p is string => typeof p === \"string\")\n : DEFAULTS.chat.injectionExtraPatterns,\n retentionDays: num(fileChat.retentionDays, DEFAULTS.chat.retentionDays),\n },\n };\n}\n"]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { AiConfig, ChatConfig, DEFAULTS, OpenExpertConfig, loadConfig } from './config.js';
|
|
2
|
+
export { ModelProviderId, ModelSelection, missingKeyHint, ollamaApiBaseUrl, ollamaChatBaseUrl, selectModel } from './model-provider.js';
|
|
3
|
+
export { LOCAL_TABLES, Row, Storage, TableName } from './storage.js';
|
|
4
|
+
export { DriveTokenRow, TokenStore, credentialsPath } from './secrets.js';
|
|
5
|
+
export { TOOL_CATALOG, ToolDef, ToolDomain } from './tools.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'fs';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
|
|
4
|
+
// src/config.ts
|
|
5
|
+
var DEFAULTS = {
|
|
6
|
+
modelProvider: "google",
|
|
7
|
+
modelId: "gemini-2.5-flash",
|
|
8
|
+
ollamaBaseUrl: "http://localhost:11434",
|
|
9
|
+
dataDir: "~/.openexpert",
|
|
10
|
+
ai: { temperature: 0.2, topP: 1, maxOutputTokens: 4096 },
|
|
11
|
+
chat: {
|
|
12
|
+
maxSteps: 50,
|
|
13
|
+
injectionGuard: true,
|
|
14
|
+
injectionExtraPatterns: [],
|
|
15
|
+
retentionDays: 30
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
function expandHome(p) {
|
|
19
|
+
if (p.startsWith("~/")) {
|
|
20
|
+
const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
|
|
21
|
+
return join(home, p.slice(2));
|
|
22
|
+
}
|
|
23
|
+
return p;
|
|
24
|
+
}
|
|
25
|
+
function num(value, fallback) {
|
|
26
|
+
const n = typeof value === "string" ? Number(value) : value;
|
|
27
|
+
return typeof n === "number" && Number.isFinite(n) ? n : fallback;
|
|
28
|
+
}
|
|
29
|
+
function loadConfig(cwd = process.cwd()) {
|
|
30
|
+
let file = {};
|
|
31
|
+
const path = join(cwd, "openexpert.json");
|
|
32
|
+
if (existsSync(path)) {
|
|
33
|
+
try {
|
|
34
|
+
file = JSON.parse(readFileSync(path, "utf8"));
|
|
35
|
+
} catch {
|
|
36
|
+
file = {};
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
const env = process.env;
|
|
40
|
+
const providerEnv = env["OPENEXPERT_MODEL_PROVIDER"];
|
|
41
|
+
const providerFromEnv = providerEnv === "google" || providerEnv === "ollama" || providerEnv === "openai-compatible" ? providerEnv : void 0;
|
|
42
|
+
const fileAi = file.ai ?? {};
|
|
43
|
+
const fileChat = file.chat ?? {};
|
|
44
|
+
return {
|
|
45
|
+
modelProvider: providerFromEnv ?? file.modelProvider ?? DEFAULTS.modelProvider,
|
|
46
|
+
modelId: env["OPENEXPERT_MODEL_ID"] ?? file.modelId ?? DEFAULTS.modelId,
|
|
47
|
+
ollamaBaseUrl: env["OLLAMA_BASE_URL"] ?? file.ollamaBaseUrl ?? DEFAULTS.ollamaBaseUrl,
|
|
48
|
+
dataDir: expandHome(env["OPENEXPERT_DATA_DIR"] ?? file.dataDir ?? DEFAULTS.dataDir),
|
|
49
|
+
ai: {
|
|
50
|
+
temperature: num(fileAi.temperature, DEFAULTS.ai.temperature),
|
|
51
|
+
topP: num(fileAi.topP, DEFAULTS.ai.topP),
|
|
52
|
+
maxOutputTokens: num(fileAi.maxOutputTokens, DEFAULTS.ai.maxOutputTokens)
|
|
53
|
+
},
|
|
54
|
+
chat: {
|
|
55
|
+
maxSteps: num(fileChat.maxSteps, DEFAULTS.chat.maxSteps),
|
|
56
|
+
injectionGuard: fileChat.injectionGuard ?? DEFAULTS.chat.injectionGuard,
|
|
57
|
+
injectionExtraPatterns: Array.isArray(fileChat.injectionExtraPatterns) ? fileChat.injectionExtraPatterns.filter((p) => typeof p === "string") : DEFAULTS.chat.injectionExtraPatterns,
|
|
58
|
+
retentionDays: num(fileChat.retentionDays, DEFAULTS.chat.retentionDays)
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// src/model-provider.ts
|
|
64
|
+
function selectModel(env = process.env) {
|
|
65
|
+
const raw = env["OPENEXPERT_MODEL_PROVIDER"];
|
|
66
|
+
const provider = raw === "ollama" || raw === "openai-compatible" ? raw : "google";
|
|
67
|
+
if (provider === "ollama") {
|
|
68
|
+
return {
|
|
69
|
+
provider,
|
|
70
|
+
modelId: env["OPENEXPERT_MODEL_ID"] || "llama3.1",
|
|
71
|
+
keySource: "none (local)"
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
if (provider === "openai-compatible") {
|
|
75
|
+
return {
|
|
76
|
+
provider,
|
|
77
|
+
modelId: env["OPENEXPERT_MODEL_ID"] || "gpt-4o-mini",
|
|
78
|
+
keySource: "OPENEXPERT_MODEL_KEY"
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
provider: "google",
|
|
83
|
+
modelId: env["OPENEXPERT_MODEL_ID"] || "gemini-2.5-flash",
|
|
84
|
+
keySource: "GOOGLE_API_KEY"
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
function ollamaApiBaseUrl(baseUrl) {
|
|
88
|
+
return baseUrl.trim().replace(/\/+$/, "").replace(/\/v1$/, "");
|
|
89
|
+
}
|
|
90
|
+
function ollamaChatBaseUrl(baseUrl) {
|
|
91
|
+
return `${ollamaApiBaseUrl(baseUrl)}/v1`;
|
|
92
|
+
}
|
|
93
|
+
function missingKeyHint(sel, env = process.env) {
|
|
94
|
+
if (sel.provider === "ollama") return null;
|
|
95
|
+
if (sel.provider === "google" && !env["GOOGLE_API_KEY"]) {
|
|
96
|
+
return "Falta GOOGLE_API_KEY (o usa OPENEXPERT_MODEL_PROVIDER=ollama para modelo local).";
|
|
97
|
+
}
|
|
98
|
+
if (sel.provider === "openai-compatible" && !env["OPENEXPERT_MODEL_KEY"]) {
|
|
99
|
+
return "Falta OPENEXPERT_MODEL_KEY para tu endpoint OpenAI-compatible.";
|
|
100
|
+
}
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// src/storage.ts
|
|
105
|
+
var LOCAL_TABLES = [
|
|
106
|
+
"experts",
|
|
107
|
+
"integrations",
|
|
108
|
+
"processes",
|
|
109
|
+
"activity",
|
|
110
|
+
"chat_messages",
|
|
111
|
+
"deals",
|
|
112
|
+
"invoices",
|
|
113
|
+
"campaigns",
|
|
114
|
+
"accounts",
|
|
115
|
+
"settings"
|
|
116
|
+
];
|
|
117
|
+
|
|
118
|
+
// src/secrets.ts
|
|
119
|
+
function credentialsPath(dataDir) {
|
|
120
|
+
const home = dataDir.startsWith("~/") ? `${process.env["HOME"] || "~"}/${dataDir.slice(2)}` : dataDir;
|
|
121
|
+
return `${home.replace(/\/$/, "")}/credentials.json`;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// src/tools.ts
|
|
125
|
+
var TOOL_CATALOG = [
|
|
126
|
+
{ name: "get_pipeline_summary", domain: "ventas", needs: "read", proposesOnly: false },
|
|
127
|
+
{ name: "list_deals", domain: "ventas", needs: "read", proposesOnly: false },
|
|
128
|
+
{ name: "list_overdue_invoices", domain: "finanzas", needs: "read", proposesOnly: false },
|
|
129
|
+
{ name: "get_campaign_performance", domain: "marketing", needs: "read", proposesOnly: false },
|
|
130
|
+
{ name: "get_churn_risk", domain: "general", needs: "read", proposesOnly: false },
|
|
131
|
+
{ name: "list_processes", domain: "transversal", needs: "read", proposesOnly: false },
|
|
132
|
+
{ name: "search_drive", domain: "drive", needs: "read", proposesOnly: false },
|
|
133
|
+
{ name: "read_drive_file", domain: "drive", needs: "read", proposesOnly: false },
|
|
134
|
+
{ name: "create_drive_file", domain: "drive", needs: "exec", proposesOnly: false },
|
|
135
|
+
{ name: "update_drive_file", domain: "drive", needs: "exec", proposesOnly: false },
|
|
136
|
+
{ name: "propose_invoice_reminders", domain: "finanzas", needs: "exec", proposesOnly: true },
|
|
137
|
+
{ name: "propose_pause_campaigns", domain: "marketing", needs: "exec", proposesOnly: true },
|
|
138
|
+
{ name: "request_process_run", domain: "transversal", needs: "exec", proposesOnly: true },
|
|
139
|
+
{ name: "open_expert_form", domain: "transversal", needs: "exec", proposesOnly: false }
|
|
140
|
+
];
|
|
141
|
+
|
|
142
|
+
export { DEFAULTS, LOCAL_TABLES, TOOL_CATALOG, credentialsPath, loadConfig, missingKeyHint, ollamaApiBaseUrl, ollamaChatBaseUrl, selectModel };
|
|
143
|
+
//# sourceMappingURL=index.js.map
|
|
144
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/config.ts","../src/model-provider.ts","../src/storage.ts","../src/secrets.ts","../src/tools.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["// SPDX-License-Identifier: MIT\n// OpenCore — local configuration.\n// Precedence: OPENEXPERT_* env vars > openexpert.json > defaults.\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { ModelProviderId } from \"./model-provider.js\";\n\nexport type AiConfig = {\n temperature: number;\n topP: number;\n maxOutputTokens: number;\n};\n\nexport type ChatConfig = {\n maxSteps: number;\n injectionGuard: boolean;\n injectionExtraPatterns: string[];\n retentionDays: number;\n};\n\nexport type OpenExpertConfig = {\n modelProvider: ModelProviderId;\n modelId: string;\n ollamaBaseUrl: string;\n dataDir: string;\n ai: AiConfig;\n chat: ChatConfig;\n};\n\nexport const DEFAULTS: OpenExpertConfig = {\n modelProvider: \"google\",\n modelId: \"gemini-2.5-flash\",\n ollamaBaseUrl: \"http://localhost:11434\",\n dataDir: \"~/.openexpert\",\n ai: { temperature: 0.2, topP: 1, maxOutputTokens: 4096 },\n chat: {\n maxSteps: 50,\n injectionGuard: true,\n injectionExtraPatterns: [],\n retentionDays: 30,\n },\n};\n\nfunction expandHome(p: string): string {\n if (p.startsWith(\"~/\")) {\n const home = process.env[\"HOME\"] || process.env[\"USERPROFILE\"] || \"~\";\n return join(home, p.slice(2));\n }\n return p;\n}\n\nfunction num(value: unknown, fallback: number): number {\n const n = typeof value === \"string\" ? Number(value) : value;\n return typeof n === \"number\" && Number.isFinite(n) ? n : fallback;\n}\n\nexport function loadConfig(cwd: string = process.cwd()): OpenExpertConfig {\n let file: Partial<OpenExpertConfig> = {};\n const path = join(cwd, \"openexpert.json\");\n if (existsSync(path)) {\n try {\n file = JSON.parse(readFileSync(path, \"utf8\")) as Partial<OpenExpertConfig>;\n } catch {\n // Broken file: ignore it, env/defaults win.\n file = {};\n }\n }\n const env = process.env;\n const providerEnv = env[\"OPENEXPERT_MODEL_PROVIDER\"];\n const providerFromEnv: ModelProviderId | undefined =\n providerEnv === \"google\" || providerEnv === \"ollama\" || providerEnv === \"openai-compatible\"\n ? providerEnv\n : undefined;\n\n const fileAi: Partial<AiConfig> = file.ai ?? {};\n const fileChat: Partial<ChatConfig> = file.chat ?? {};\n\n return {\n modelProvider: providerFromEnv ?? file.modelProvider ?? DEFAULTS.modelProvider,\n modelId: env[\"OPENEXPERT_MODEL_ID\"] ?? file.modelId ?? DEFAULTS.modelId,\n ollamaBaseUrl: env[\"OLLAMA_BASE_URL\"] ?? file.ollamaBaseUrl ?? DEFAULTS.ollamaBaseUrl,\n dataDir: expandHome(env[\"OPENEXPERT_DATA_DIR\"] ?? file.dataDir ?? DEFAULTS.dataDir),\n ai: {\n temperature: num(fileAi.temperature, DEFAULTS.ai.temperature),\n topP: num(fileAi.topP, DEFAULTS.ai.topP),\n maxOutputTokens: num(fileAi.maxOutputTokens, DEFAULTS.ai.maxOutputTokens),\n },\n chat: {\n maxSteps: num(fileChat.maxSteps, DEFAULTS.chat.maxSteps),\n injectionGuard: fileChat.injectionGuard ?? DEFAULTS.chat.injectionGuard,\n injectionExtraPatterns: Array.isArray(fileChat.injectionExtraPatterns)\n ? fileChat.injectionExtraPatterns.filter((p): p is string => typeof p === \"string\")\n : DEFAULTS.chat.injectionExtraPatterns,\n retentionDays: num(fileChat.retentionDays, DEFAULTS.chat.retentionDays),\n },\n };\n}\n","// SPDX-License-Identifier: MIT\n// OpenCore — which model to use. The harness is stable; the model is configuration.\n//\n// Providers:\n// - google: Gemini via GOOGLE_API_KEY (free API key).\n// - ollama: Local model via Ollama's OpenAI-compatible endpoint.\n// - openai-compatible: Any OpenAI-compatible endpoint with your own key.\n\nexport type ModelProviderId = \"google\" | \"ollama\" | \"openai-compatible\";\n\nexport type ModelSelection = {\n provider: ModelProviderId;\n modelId: string;\n /** Where the key comes from, without exposing the value. */\n keySource: \"GOOGLE_API_KEY\" | \"OPENEXPERT_MODEL_KEY\" | \"none (local)\";\n};\n\nexport function selectModel(env: NodeJS.ProcessEnv = process.env): ModelSelection {\n const raw = env[\"OPENEXPERT_MODEL_PROVIDER\"];\n const provider: ModelProviderId =\n raw === \"ollama\" || raw === \"openai-compatible\" ? raw : \"google\";\n\n if (provider === \"ollama\") {\n return {\n provider,\n modelId: env[\"OPENEXPERT_MODEL_ID\"] || \"llama3.1\",\n keySource: \"none (local)\",\n };\n }\n if (provider === \"openai-compatible\") {\n return {\n provider,\n modelId: env[\"OPENEXPERT_MODEL_ID\"] || \"gpt-4o-mini\",\n keySource: \"OPENEXPERT_MODEL_KEY\",\n };\n }\n return {\n provider: \"google\",\n modelId: env[\"OPENEXPERT_MODEL_ID\"] || \"gemini-2.5-flash\",\n keySource: \"GOOGLE_API_KEY\",\n };\n}\n\n/**\n * Ollama exposes two surfaces: the native API at the server root (`/api/*`)\n * and an OpenAI-compatible API under `/v1`. Callers may configure either\n * shape, so normalise before using it.\n */\nexport function ollamaApiBaseUrl(baseUrl: string): string {\n return baseUrl.trim().replace(/\\/+$/, \"\").replace(/\\/v1$/, \"\");\n}\n\nexport function ollamaChatBaseUrl(baseUrl: string): string {\n return `${ollamaApiBaseUrl(baseUrl)}/v1`;\n}\n\nexport function missingKeyHint(\n sel: ModelSelection,\n env: NodeJS.ProcessEnv = process.env,\n): string | null {\n if (sel.provider === \"ollama\") return null;\n if (sel.provider === \"google\" && !env[\"GOOGLE_API_KEY\"]) {\n return \"Falta GOOGLE_API_KEY (o usa OPENEXPERT_MODEL_PROVIDER=ollama para modelo local).\";\n }\n if (sel.provider === \"openai-compatible\" && !env[\"OPENEXPERT_MODEL_KEY\"]) {\n return \"Falta OPENEXPERT_MODEL_KEY para tu endpoint OpenAI-compatible.\";\n }\n return null;\n}\n","// SPDX-License-Identifier: MIT\n// OpenCore — storage interface. OpenExpert is local-first: implementations\n// are backed by the local data directory (SQLite / files).\n\nexport type TableName =\n | \"experts\"\n | \"integrations\"\n | \"processes\"\n | \"activity\"\n | \"chat_messages\"\n | \"deals\"\n | \"invoices\"\n | \"campaigns\"\n | \"accounts\"\n | \"settings\";\n\nexport type Row = Record<string, unknown>;\n\nexport interface Storage {\n readonly kind: \"file\";\n list(table: TableName): Promise<Row[]>;\n insert(table: TableName, rows: Row | Row[]): Promise<void>;\n}\n\nexport const LOCAL_TABLES: TableName[] = [\n \"experts\",\n \"integrations\",\n \"processes\",\n \"activity\",\n \"chat_messages\",\n \"deals\",\n \"invoices\",\n \"campaigns\",\n \"accounts\",\n \"settings\",\n];\n","// SPDX-License-Identifier: MIT\n// OpenCore — where Google Drive tokens live.\n// Cloud: google_tokens table (only the server touches it).\n// Local: a file on your machine (~/.openexpert/credentials.json by\n// default), never uploaded to Git.\n\nexport type DriveTokenRow = {\n access_token: string;\n refresh_token: string | null;\n expires_at: string;\n scopes: string;\n updated_at: string;\n};\n\nexport interface TokenStore {\n readonly kind: \"file\";\n load(userId: string): Promise<DriveTokenRow | null>;\n save(userId: string, row: DriveTokenRow): Promise<void>;\n remove(userId: string): Promise<void>;\n}\n\nexport function credentialsPath(dataDir: string): string {\n const home = dataDir.startsWith(\"~/\")\n ? `${process.env[\"HOME\"] || \"~\"}/${dataDir.slice(2)}`\n : dataDir;\n return `${home.replace(/\\/$/, \"\")}/credentials.json`;\n}\n","// SPDX-License-Identifier: MIT\n// OpenCore — tool catalog (the current 14).\n// The model never touches the database directly: it only calls these\n// functions, and each one checks your permission before answering.\n\nexport type ToolDomain = \"ventas\" | \"finanzas\" | \"marketing\" | \"general\" | \"transversal\" | \"drive\";\n\nexport type ToolDef = {\n name: string;\n domain: ToolDomain;\n needs: \"read\" | \"exec\";\n proposesOnly: boolean;\n};\n\nexport const TOOL_CATALOG: ToolDef[] = [\n { name: \"get_pipeline_summary\", domain: \"ventas\", needs: \"read\", proposesOnly: false },\n { name: \"list_deals\", domain: \"ventas\", needs: \"read\", proposesOnly: false },\n { name: \"list_overdue_invoices\", domain: \"finanzas\", needs: \"read\", proposesOnly: false },\n { name: \"get_campaign_performance\", domain: \"marketing\", needs: \"read\", proposesOnly: false },\n { name: \"get_churn_risk\", domain: \"general\", needs: \"read\", proposesOnly: false },\n { name: \"list_processes\", domain: \"transversal\", needs: \"read\", proposesOnly: false },\n { name: \"search_drive\", domain: \"drive\", needs: \"read\", proposesOnly: false },\n { name: \"read_drive_file\", domain: \"drive\", needs: \"read\", proposesOnly: false },\n { name: \"create_drive_file\", domain: \"drive\", needs: \"exec\", proposesOnly: false },\n { name: \"update_drive_file\", domain: \"drive\", needs: \"exec\", proposesOnly: false },\n { name: \"propose_invoice_reminders\", domain: \"finanzas\", needs: \"exec\", proposesOnly: true },\n { name: \"propose_pause_campaigns\", domain: \"marketing\", needs: \"exec\", proposesOnly: true },\n { name: \"request_process_run\", domain: \"transversal\", needs: \"exec\", proposesOnly: true },\n { name: \"open_expert_form\", domain: \"transversal\", needs: \"exec\", proposesOnly: false },\n];\n"]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
type ModelProviderId = "google" | "ollama" | "openai-compatible";
|
|
2
|
+
type ModelSelection = {
|
|
3
|
+
provider: ModelProviderId;
|
|
4
|
+
modelId: string;
|
|
5
|
+
/** Where the key comes from, without exposing the value. */
|
|
6
|
+
keySource: "GOOGLE_API_KEY" | "OPENEXPERT_MODEL_KEY" | "none (local)";
|
|
7
|
+
};
|
|
8
|
+
declare function selectModel(env?: NodeJS.ProcessEnv): ModelSelection;
|
|
9
|
+
/**
|
|
10
|
+
* Ollama exposes two surfaces: the native API at the server root (`/api/*`)
|
|
11
|
+
* and an OpenAI-compatible API under `/v1`. Callers may configure either
|
|
12
|
+
* shape, so normalise before using it.
|
|
13
|
+
*/
|
|
14
|
+
declare function ollamaApiBaseUrl(baseUrl: string): string;
|
|
15
|
+
declare function ollamaChatBaseUrl(baseUrl: string): string;
|
|
16
|
+
declare function missingKeyHint(sel: ModelSelection, env?: NodeJS.ProcessEnv): string | null;
|
|
17
|
+
|
|
18
|
+
export { type ModelProviderId, type ModelSelection, missingKeyHint, ollamaApiBaseUrl, ollamaChatBaseUrl, selectModel };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// src/model-provider.ts
|
|
2
|
+
function selectModel(env = process.env) {
|
|
3
|
+
const raw = env["OPENEXPERT_MODEL_PROVIDER"];
|
|
4
|
+
const provider = raw === "ollama" || raw === "openai-compatible" ? raw : "google";
|
|
5
|
+
if (provider === "ollama") {
|
|
6
|
+
return {
|
|
7
|
+
provider,
|
|
8
|
+
modelId: env["OPENEXPERT_MODEL_ID"] || "llama3.1",
|
|
9
|
+
keySource: "none (local)"
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
if (provider === "openai-compatible") {
|
|
13
|
+
return {
|
|
14
|
+
provider,
|
|
15
|
+
modelId: env["OPENEXPERT_MODEL_ID"] || "gpt-4o-mini",
|
|
16
|
+
keySource: "OPENEXPERT_MODEL_KEY"
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
return {
|
|
20
|
+
provider: "google",
|
|
21
|
+
modelId: env["OPENEXPERT_MODEL_ID"] || "gemini-2.5-flash",
|
|
22
|
+
keySource: "GOOGLE_API_KEY"
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
function ollamaApiBaseUrl(baseUrl) {
|
|
26
|
+
return baseUrl.trim().replace(/\/+$/, "").replace(/\/v1$/, "");
|
|
27
|
+
}
|
|
28
|
+
function ollamaChatBaseUrl(baseUrl) {
|
|
29
|
+
return `${ollamaApiBaseUrl(baseUrl)}/v1`;
|
|
30
|
+
}
|
|
31
|
+
function missingKeyHint(sel, env = process.env) {
|
|
32
|
+
if (sel.provider === "ollama") return null;
|
|
33
|
+
if (sel.provider === "google" && !env["GOOGLE_API_KEY"]) {
|
|
34
|
+
return "Falta GOOGLE_API_KEY (o usa OPENEXPERT_MODEL_PROVIDER=ollama para modelo local).";
|
|
35
|
+
}
|
|
36
|
+
if (sel.provider === "openai-compatible" && !env["OPENEXPERT_MODEL_KEY"]) {
|
|
37
|
+
return "Falta OPENEXPERT_MODEL_KEY para tu endpoint OpenAI-compatible.";
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export { missingKeyHint, ollamaApiBaseUrl, ollamaChatBaseUrl, selectModel };
|
|
43
|
+
//# sourceMappingURL=model-provider.js.map
|
|
44
|
+
//# sourceMappingURL=model-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/model-provider.ts"],"names":[],"mappings":";AAiBO,SAAS,WAAA,CAAY,GAAA,GAAyB,OAAA,CAAQ,GAAA,EAAqB;AAChF,EAAA,MAAM,GAAA,GAAM,IAAI,2BAA2B,CAAA;AAC3C,EAAA,MAAM,QAAA,GACJ,GAAA,KAAQ,QAAA,IAAY,GAAA,KAAQ,sBAAsB,GAAA,GAAM,QAAA;AAE1D,EAAA,IAAI,aAAa,QAAA,EAAU;AACzB,IAAA,OAAO;AAAA,MACL,QAAA;AAAA,MACA,OAAA,EAAS,GAAA,CAAI,qBAAqB,CAAA,IAAK,UAAA;AAAA,MACvC,SAAA,EAAW;AAAA,KACb;AAAA,EACF;AACA,EAAA,IAAI,aAAa,mBAAA,EAAqB;AACpC,IAAA,OAAO;AAAA,MACL,QAAA;AAAA,MACA,OAAA,EAAS,GAAA,CAAI,qBAAqB,CAAA,IAAK,aAAA;AAAA,MACvC,SAAA,EAAW;AAAA,KACb;AAAA,EACF;AACA,EAAA,OAAO;AAAA,IACL,QAAA,EAAU,QAAA;AAAA,IACV,OAAA,EAAS,GAAA,CAAI,qBAAqB,CAAA,IAAK,kBAAA;AAAA,IACvC,SAAA,EAAW;AAAA,GACb;AACF;AAOO,SAAS,iBAAiB,OAAA,EAAyB;AACxD,EAAA,OAAO,OAAA,CAAQ,MAAK,CAAE,OAAA,CAAQ,QAAQ,EAAE,CAAA,CAAE,OAAA,CAAQ,OAAA,EAAS,EAAE,CAAA;AAC/D;AAEO,SAAS,kBAAkB,OAAA,EAAyB;AACzD,EAAA,OAAO,CAAA,EAAG,gBAAA,CAAiB,OAAO,CAAC,CAAA,GAAA,CAAA;AACrC;AAEO,SAAS,cAAA,CACd,GAAA,EACA,GAAA,GAAyB,OAAA,CAAQ,GAAA,EAClB;AACf,EAAA,IAAI,GAAA,CAAI,QAAA,KAAa,QAAA,EAAU,OAAO,IAAA;AACtC,EAAA,IAAI,IAAI,QAAA,KAAa,QAAA,IAAY,CAAC,GAAA,CAAI,gBAAgB,CAAA,EAAG;AACvD,IAAA,OAAO,kFAAA;AAAA,EACT;AACA,EAAA,IAAI,IAAI,QAAA,KAAa,mBAAA,IAAuB,CAAC,GAAA,CAAI,sBAAsB,CAAA,EAAG;AACxE,IAAA,OAAO,gEAAA;AAAA,EACT;AACA,EAAA,OAAO,IAAA;AACT","file":"model-provider.js","sourcesContent":["// SPDX-License-Identifier: MIT\n// OpenCore — which model to use. The harness is stable; the model is configuration.\n//\n// Providers:\n// - google: Gemini via GOOGLE_API_KEY (free API key).\n// - ollama: Local model via Ollama's OpenAI-compatible endpoint.\n// - openai-compatible: Any OpenAI-compatible endpoint with your own key.\n\nexport type ModelProviderId = \"google\" | \"ollama\" | \"openai-compatible\";\n\nexport type ModelSelection = {\n provider: ModelProviderId;\n modelId: string;\n /** Where the key comes from, without exposing the value. */\n keySource: \"GOOGLE_API_KEY\" | \"OPENEXPERT_MODEL_KEY\" | \"none (local)\";\n};\n\nexport function selectModel(env: NodeJS.ProcessEnv = process.env): ModelSelection {\n const raw = env[\"OPENEXPERT_MODEL_PROVIDER\"];\n const provider: ModelProviderId =\n raw === \"ollama\" || raw === \"openai-compatible\" ? raw : \"google\";\n\n if (provider === \"ollama\") {\n return {\n provider,\n modelId: env[\"OPENEXPERT_MODEL_ID\"] || \"llama3.1\",\n keySource: \"none (local)\",\n };\n }\n if (provider === \"openai-compatible\") {\n return {\n provider,\n modelId: env[\"OPENEXPERT_MODEL_ID\"] || \"gpt-4o-mini\",\n keySource: \"OPENEXPERT_MODEL_KEY\",\n };\n }\n return {\n provider: \"google\",\n modelId: env[\"OPENEXPERT_MODEL_ID\"] || \"gemini-2.5-flash\",\n keySource: \"GOOGLE_API_KEY\",\n };\n}\n\n/**\n * Ollama exposes two surfaces: the native API at the server root (`/api/*`)\n * and an OpenAI-compatible API under `/v1`. Callers may configure either\n * shape, so normalise before using it.\n */\nexport function ollamaApiBaseUrl(baseUrl: string): string {\n return baseUrl.trim().replace(/\\/+$/, \"\").replace(/\\/v1$/, \"\");\n}\n\nexport function ollamaChatBaseUrl(baseUrl: string): string {\n return `${ollamaApiBaseUrl(baseUrl)}/v1`;\n}\n\nexport function missingKeyHint(\n sel: ModelSelection,\n env: NodeJS.ProcessEnv = process.env,\n): string | null {\n if (sel.provider === \"ollama\") return null;\n if (sel.provider === \"google\" && !env[\"GOOGLE_API_KEY\"]) {\n return \"Falta GOOGLE_API_KEY (o usa OPENEXPERT_MODEL_PROVIDER=ollama para modelo local).\";\n }\n if (sel.provider === \"openai-compatible\" && !env[\"OPENEXPERT_MODEL_KEY\"]) {\n return \"Falta OPENEXPERT_MODEL_KEY para tu endpoint OpenAI-compatible.\";\n }\n return null;\n}\n"]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
type DriveTokenRow = {
|
|
2
|
+
access_token: string;
|
|
3
|
+
refresh_token: string | null;
|
|
4
|
+
expires_at: string;
|
|
5
|
+
scopes: string;
|
|
6
|
+
updated_at: string;
|
|
7
|
+
};
|
|
8
|
+
interface TokenStore {
|
|
9
|
+
readonly kind: "file";
|
|
10
|
+
load(userId: string): Promise<DriveTokenRow | null>;
|
|
11
|
+
save(userId: string, row: DriveTokenRow): Promise<void>;
|
|
12
|
+
remove(userId: string): Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
declare function credentialsPath(dataDir: string): string;
|
|
15
|
+
|
|
16
|
+
export { type DriveTokenRow, type TokenStore, credentialsPath };
|
package/dist/secrets.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// src/secrets.ts
|
|
2
|
+
function credentialsPath(dataDir) {
|
|
3
|
+
const home = dataDir.startsWith("~/") ? `${process.env["HOME"] || "~"}/${dataDir.slice(2)}` : dataDir;
|
|
4
|
+
return `${home.replace(/\/$/, "")}/credentials.json`;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export { credentialsPath };
|
|
8
|
+
//# sourceMappingURL=secrets.js.map
|
|
9
|
+
//# sourceMappingURL=secrets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/secrets.ts"],"names":[],"mappings":";AAqBO,SAAS,gBAAgB,OAAA,EAAyB;AACvD,EAAA,MAAM,OAAO,OAAA,CAAQ,UAAA,CAAW,IAAI,CAAA,GAChC,GAAG,OAAA,CAAQ,GAAA,CAAI,MAAM,CAAA,IAAK,GAAG,CAAA,CAAA,EAAI,OAAA,CAAQ,KAAA,CAAM,CAAC,CAAC,CAAA,CAAA,GACjD,OAAA;AACJ,EAAA,OAAO,CAAA,EAAG,IAAA,CAAK,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAC,CAAA,iBAAA,CAAA;AACnC","file":"secrets.js","sourcesContent":["// SPDX-License-Identifier: MIT\n// OpenCore — where Google Drive tokens live.\n// Cloud: google_tokens table (only the server touches it).\n// Local: a file on your machine (~/.openexpert/credentials.json by\n// default), never uploaded to Git.\n\nexport type DriveTokenRow = {\n access_token: string;\n refresh_token: string | null;\n expires_at: string;\n scopes: string;\n updated_at: string;\n};\n\nexport interface TokenStore {\n readonly kind: \"file\";\n load(userId: string): Promise<DriveTokenRow | null>;\n save(userId: string, row: DriveTokenRow): Promise<void>;\n remove(userId: string): Promise<void>;\n}\n\nexport function credentialsPath(dataDir: string): string {\n const home = dataDir.startsWith(\"~/\")\n ? `${process.env[\"HOME\"] || \"~\"}/${dataDir.slice(2)}`\n : dataDir;\n return `${home.replace(/\\/$/, \"\")}/credentials.json`;\n}\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
type TableName = "experts" | "integrations" | "processes" | "activity" | "chat_messages" | "deals" | "invoices" | "campaigns" | "accounts" | "settings";
|
|
2
|
+
type Row = Record<string, unknown>;
|
|
3
|
+
interface Storage {
|
|
4
|
+
readonly kind: "file";
|
|
5
|
+
list(table: TableName): Promise<Row[]>;
|
|
6
|
+
insert(table: TableName, rows: Row | Row[]): Promise<void>;
|
|
7
|
+
}
|
|
8
|
+
declare const LOCAL_TABLES: TableName[];
|
|
9
|
+
|
|
10
|
+
export { LOCAL_TABLES, type Row, type Storage, type TableName };
|
package/dist/storage.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// src/storage.ts
|
|
2
|
+
var LOCAL_TABLES = [
|
|
3
|
+
"experts",
|
|
4
|
+
"integrations",
|
|
5
|
+
"processes",
|
|
6
|
+
"activity",
|
|
7
|
+
"chat_messages",
|
|
8
|
+
"deals",
|
|
9
|
+
"invoices",
|
|
10
|
+
"campaigns",
|
|
11
|
+
"accounts",
|
|
12
|
+
"settings"
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
export { LOCAL_TABLES };
|
|
16
|
+
//# sourceMappingURL=storage.js.map
|
|
17
|
+
//# sourceMappingURL=storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/storage.ts"],"names":[],"mappings":";AAwBO,IAAM,YAAA,GAA4B;AAAA,EACvC,SAAA;AAAA,EACA,cAAA;AAAA,EACA,WAAA;AAAA,EACA,UAAA;AAAA,EACA,eAAA;AAAA,EACA,OAAA;AAAA,EACA,UAAA;AAAA,EACA,WAAA;AAAA,EACA,UAAA;AAAA,EACA;AACF","file":"storage.js","sourcesContent":["// SPDX-License-Identifier: MIT\n// OpenCore — storage interface. OpenExpert is local-first: implementations\n// are backed by the local data directory (SQLite / files).\n\nexport type TableName =\n | \"experts\"\n | \"integrations\"\n | \"processes\"\n | \"activity\"\n | \"chat_messages\"\n | \"deals\"\n | \"invoices\"\n | \"campaigns\"\n | \"accounts\"\n | \"settings\";\n\nexport type Row = Record<string, unknown>;\n\nexport interface Storage {\n readonly kind: \"file\";\n list(table: TableName): Promise<Row[]>;\n insert(table: TableName, rows: Row | Row[]): Promise<void>;\n}\n\nexport const LOCAL_TABLES: TableName[] = [\n \"experts\",\n \"integrations\",\n \"processes\",\n \"activity\",\n \"chat_messages\",\n \"deals\",\n \"invoices\",\n \"campaigns\",\n \"accounts\",\n \"settings\",\n];\n"]}
|
package/dist/tools.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
type ToolDomain = "ventas" | "finanzas" | "marketing" | "general" | "transversal" | "drive";
|
|
2
|
+
type ToolDef = {
|
|
3
|
+
name: string;
|
|
4
|
+
domain: ToolDomain;
|
|
5
|
+
needs: "read" | "exec";
|
|
6
|
+
proposesOnly: boolean;
|
|
7
|
+
};
|
|
8
|
+
declare const TOOL_CATALOG: ToolDef[];
|
|
9
|
+
|
|
10
|
+
export { TOOL_CATALOG, type ToolDef, type ToolDomain };
|
package/dist/tools.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// src/tools.ts
|
|
2
|
+
var TOOL_CATALOG = [
|
|
3
|
+
{ name: "get_pipeline_summary", domain: "ventas", needs: "read", proposesOnly: false },
|
|
4
|
+
{ name: "list_deals", domain: "ventas", needs: "read", proposesOnly: false },
|
|
5
|
+
{ name: "list_overdue_invoices", domain: "finanzas", needs: "read", proposesOnly: false },
|
|
6
|
+
{ name: "get_campaign_performance", domain: "marketing", needs: "read", proposesOnly: false },
|
|
7
|
+
{ name: "get_churn_risk", domain: "general", needs: "read", proposesOnly: false },
|
|
8
|
+
{ name: "list_processes", domain: "transversal", needs: "read", proposesOnly: false },
|
|
9
|
+
{ name: "search_drive", domain: "drive", needs: "read", proposesOnly: false },
|
|
10
|
+
{ name: "read_drive_file", domain: "drive", needs: "read", proposesOnly: false },
|
|
11
|
+
{ name: "create_drive_file", domain: "drive", needs: "exec", proposesOnly: false },
|
|
12
|
+
{ name: "update_drive_file", domain: "drive", needs: "exec", proposesOnly: false },
|
|
13
|
+
{ name: "propose_invoice_reminders", domain: "finanzas", needs: "exec", proposesOnly: true },
|
|
14
|
+
{ name: "propose_pause_campaigns", domain: "marketing", needs: "exec", proposesOnly: true },
|
|
15
|
+
{ name: "request_process_run", domain: "transversal", needs: "exec", proposesOnly: true },
|
|
16
|
+
{ name: "open_expert_form", domain: "transversal", needs: "exec", proposesOnly: false }
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
export { TOOL_CATALOG };
|
|
20
|
+
//# sourceMappingURL=tools.js.map
|
|
21
|
+
//# sourceMappingURL=tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/tools.ts"],"names":[],"mappings":";AAcO,IAAM,YAAA,GAA0B;AAAA,EACrC,EAAE,MAAM,sBAAA,EAAwB,MAAA,EAAQ,UAAU,KAAA,EAAO,MAAA,EAAQ,cAAc,KAAA,EAAM;AAAA,EACrF,EAAE,MAAM,YAAA,EAAc,MAAA,EAAQ,UAAU,KAAA,EAAO,MAAA,EAAQ,cAAc,KAAA,EAAM;AAAA,EAC3E,EAAE,MAAM,uBAAA,EAAyB,MAAA,EAAQ,YAAY,KAAA,EAAO,MAAA,EAAQ,cAAc,KAAA,EAAM;AAAA,EACxF,EAAE,MAAM,0BAAA,EAA4B,MAAA,EAAQ,aAAa,KAAA,EAAO,MAAA,EAAQ,cAAc,KAAA,EAAM;AAAA,EAC5F,EAAE,MAAM,gBAAA,EAAkB,MAAA,EAAQ,WAAW,KAAA,EAAO,MAAA,EAAQ,cAAc,KAAA,EAAM;AAAA,EAChF,EAAE,MAAM,gBAAA,EAAkB,MAAA,EAAQ,eAAe,KAAA,EAAO,MAAA,EAAQ,cAAc,KAAA,EAAM;AAAA,EACpF,EAAE,MAAM,cAAA,EAAgB,MAAA,EAAQ,SAAS,KAAA,EAAO,MAAA,EAAQ,cAAc,KAAA,EAAM;AAAA,EAC5E,EAAE,MAAM,iBAAA,EAAmB,MAAA,EAAQ,SAAS,KAAA,EAAO,MAAA,EAAQ,cAAc,KAAA,EAAM;AAAA,EAC/E,EAAE,MAAM,mBAAA,EAAqB,MAAA,EAAQ,SAAS,KAAA,EAAO,MAAA,EAAQ,cAAc,KAAA,EAAM;AAAA,EACjF,EAAE,MAAM,mBAAA,EAAqB,MAAA,EAAQ,SAAS,KAAA,EAAO,MAAA,EAAQ,cAAc,KAAA,EAAM;AAAA,EACjF,EAAE,MAAM,2BAAA,EAA6B,MAAA,EAAQ,YAAY,KAAA,EAAO,MAAA,EAAQ,cAAc,IAAA,EAAK;AAAA,EAC3F,EAAE,MAAM,yBAAA,EAA2B,MAAA,EAAQ,aAAa,KAAA,EAAO,MAAA,EAAQ,cAAc,IAAA,EAAK;AAAA,EAC1F,EAAE,MAAM,qBAAA,EAAuB,MAAA,EAAQ,eAAe,KAAA,EAAO,MAAA,EAAQ,cAAc,IAAA,EAAK;AAAA,EACxF,EAAE,MAAM,kBAAA,EAAoB,MAAA,EAAQ,eAAe,KAAA,EAAO,MAAA,EAAQ,cAAc,KAAA;AAClF","file":"tools.js","sourcesContent":["// SPDX-License-Identifier: MIT\n// OpenCore — tool catalog (the current 14).\n// The model never touches the database directly: it only calls these\n// functions, and each one checks your permission before answering.\n\nexport type ToolDomain = \"ventas\" | \"finanzas\" | \"marketing\" | \"general\" | \"transversal\" | \"drive\";\n\nexport type ToolDef = {\n name: string;\n domain: ToolDomain;\n needs: \"read\" | \"exec\";\n proposesOnly: boolean;\n};\n\nexport const TOOL_CATALOG: ToolDef[] = [\n { name: \"get_pipeline_summary\", domain: \"ventas\", needs: \"read\", proposesOnly: false },\n { name: \"list_deals\", domain: \"ventas\", needs: \"read\", proposesOnly: false },\n { name: \"list_overdue_invoices\", domain: \"finanzas\", needs: \"read\", proposesOnly: false },\n { name: \"get_campaign_performance\", domain: \"marketing\", needs: \"read\", proposesOnly: false },\n { name: \"get_churn_risk\", domain: \"general\", needs: \"read\", proposesOnly: false },\n { name: \"list_processes\", domain: \"transversal\", needs: \"read\", proposesOnly: false },\n { name: \"search_drive\", domain: \"drive\", needs: \"read\", proposesOnly: false },\n { name: \"read_drive_file\", domain: \"drive\", needs: \"read\", proposesOnly: false },\n { name: \"create_drive_file\", domain: \"drive\", needs: \"exec\", proposesOnly: false },\n { name: \"update_drive_file\", domain: \"drive\", needs: \"exec\", proposesOnly: false },\n { name: \"propose_invoice_reminders\", domain: \"finanzas\", needs: \"exec\", proposesOnly: true },\n { name: \"propose_pause_campaigns\", domain: \"marketing\", needs: \"exec\", proposesOnly: true },\n { name: \"request_process_run\", domain: \"transversal\", needs: \"exec\", proposesOnly: true },\n { name: \"open_expert_form\", domain: \"transversal\", needs: \"exec\", proposesOnly: false },\n];\n"]}
|