@openexpert/opencore 0.2.1 → 0.3.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 +1 -1
- package/bin/opencore.js +1 -1
- package/dist/cli.js +25 -19
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +10 -0
- package/dist/config.js +5 -1
- package/dist/config.js.map +1 -1
- package/dist/index.js +12 -5
- package/dist/index.js.map +1 -1
- package/dist/model-provider.d.ts +0 -5
- package/dist/model-provider.js +7 -1
- package/dist/model-provider.js.map +1 -1
- package/dist/storage.d.ts +1 -1
- package/dist/storage.js +0 -1
- package/dist/storage.js.map +1 -1
- package/dist/tools.js +0 -2
- package/dist/tools.js.map +1 -1
- package/package.json +4 -4
- package/schema/openexpert.schema.json +10 -0
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ edición cloud.
|
|
|
10
10
|
- `src/config.ts` — lee `openexpert.json` + `OPENEXPERT_*`.
|
|
11
11
|
- `src/storage.ts` — interfaz de guardado local.
|
|
12
12
|
- `src/secrets.ts` — interfaz de tokens de Drive (fichero local, `0600`).
|
|
13
|
-
- `src/tools.ts` — catálogo de las
|
|
13
|
+
- `src/tools.ts` — catálogo de las 12 herramientas y sus dominios.
|
|
14
14
|
- `src/cli/` — el CLI `opencore` (asistente, doctor, fix, models, serve, update).
|
|
15
15
|
|
|
16
16
|
## Uso
|
package/bin/opencore.js
CHANGED
|
@@ -13,7 +13,7 @@ const dist = join(here, "..", "dist", "cli.js");
|
|
|
13
13
|
|
|
14
14
|
if (!existsSync(dist)) {
|
|
15
15
|
console.error(
|
|
16
|
-
"
|
|
16
|
+
"OpenExpert CLI is not built yet.\n" +
|
|
17
17
|
"Run: npm run build --workspace @openexpert/opencore\n" +
|
|
18
18
|
"(or use `npm run opencore:doctor` from the repository root).",
|
|
19
19
|
);
|
package/dist/cli.js
CHANGED
|
@@ -9,8 +9,14 @@ import * as p from '@clack/prompts';
|
|
|
9
9
|
// src/cli/commands.ts
|
|
10
10
|
|
|
11
11
|
// src/model-provider.ts
|
|
12
|
+
function stripTrailingSlashes(value) {
|
|
13
|
+
let end = value.length;
|
|
14
|
+
while (end > 0 && value[end - 1] === "/") end -= 1;
|
|
15
|
+
return value.slice(0, end);
|
|
16
|
+
}
|
|
12
17
|
function ollamaApiBaseUrl(baseUrl) {
|
|
13
|
-
|
|
18
|
+
const base = stripTrailingSlashes(baseUrl.trim());
|
|
19
|
+
return base.endsWith("/v1") ? base.slice(0, -3) : base;
|
|
14
20
|
}
|
|
15
21
|
var DEFAULT_OLLAMA_URL = "http://localhost:11434";
|
|
16
22
|
var DEFAULT_DATA_DIR = "~/.openexpert";
|
|
@@ -164,7 +170,7 @@ function run(cmd, args, opts = {}) {
|
|
|
164
170
|
|
|
165
171
|
// src/cli/commands.ts
|
|
166
172
|
function cmdVersion() {
|
|
167
|
-
console.log(
|
|
173
|
+
console.log(`OpenExpert ${packageVersion()}`);
|
|
168
174
|
return 0;
|
|
169
175
|
}
|
|
170
176
|
function configuredProvider() {
|
|
@@ -176,12 +182,12 @@ function cmdDoctor(cwd = process.cwd()) {
|
|
|
176
182
|
const provider = configuredProvider();
|
|
177
183
|
const dataDir = resolvedDataDir(cwd);
|
|
178
184
|
const secrets = readSecrets(cwd);
|
|
179
|
-
console.log("
|
|
185
|
+
console.log("OpenExpert doctor");
|
|
180
186
|
console.log(` provider: ${provider}`);
|
|
181
187
|
console.log(` data dir: ${dataDir}`);
|
|
182
188
|
const problems = [];
|
|
183
189
|
if (provider === "google" && !process.env["GOOGLE_API_KEY"] && !secrets.GOOGLE_API_KEY) {
|
|
184
|
-
problems.push("Falta GOOGLE_API_KEY. Ejecuta `
|
|
190
|
+
problems.push("Falta GOOGLE_API_KEY. Ejecuta `openexpert init` o usa Ollama.");
|
|
185
191
|
}
|
|
186
192
|
if (provider === "openai-compatible") {
|
|
187
193
|
if (!process.env["OPENEXPERT_MODEL_KEY"] && !secrets.OPENEXPERT_MODEL_KEY) {
|
|
@@ -236,7 +242,7 @@ async function cmdFix(cwd = process.cwd()) {
|
|
|
236
242
|
}
|
|
237
243
|
console.log("\u2713 directorio de datos listo:", dataDir);
|
|
238
244
|
cmdDoctor(cwd);
|
|
239
|
-
console.log("\nSiguiente paso: `
|
|
245
|
+
console.log("\nSiguiente paso: `openexpert serve` (o `openexpert init` para elegir modelo).");
|
|
240
246
|
return 0;
|
|
241
247
|
}
|
|
242
248
|
async function cmdModels(cwd = process.cwd()) {
|
|
@@ -262,7 +268,7 @@ async function cmdModels(cwd = process.cwd()) {
|
|
|
262
268
|
const base = process.env["OPENEXPERT_BASE_URL"] || secrets.OPENEXPERT_BASE_URL;
|
|
263
269
|
const key = process.env["OPENEXPERT_MODEL_KEY"] || secrets.OPENEXPERT_MODEL_KEY;
|
|
264
270
|
if (!base || !key) {
|
|
265
|
-
console.log("Configura OPENEXPERT_BASE_URL y OPENEXPERT_MODEL_KEY (
|
|
271
|
+
console.log("Configura OPENEXPERT_BASE_URL y OPENEXPERT_MODEL_KEY (openexpert init).");
|
|
266
272
|
return 1;
|
|
267
273
|
}
|
|
268
274
|
const data = await httpGetJson(
|
|
@@ -295,7 +301,7 @@ async function cmdServe(cwd = process.cwd()) {
|
|
|
295
301
|
);
|
|
296
302
|
return 1;
|
|
297
303
|
}
|
|
298
|
-
console.log("Arrancando
|
|
304
|
+
console.log("Arrancando OpenExpert en http://localhost:3000 \u2026");
|
|
299
305
|
return run(process.execPath, [join(app, ".output", "server", "index.mjs")], {
|
|
300
306
|
cwd: app,
|
|
301
307
|
env: { ...env, PORT: process.env["PORT"] || "3000" }
|
|
@@ -469,7 +475,7 @@ async function runWizard(opts = {}) {
|
|
|
469
475
|
writeConfig(config2, cwd);
|
|
470
476
|
return { config: config2, secrets: {}, provider: "ollama", modelId: config2.modelId, started: false };
|
|
471
477
|
}
|
|
472
|
-
p.intro("
|
|
478
|
+
p.intro("OpenExpert \u2014 configuraci\xF3n");
|
|
473
479
|
const spin = p.spinner();
|
|
474
480
|
spin.start("Buscando Ollama local\u2026");
|
|
475
481
|
const ollama = await detectOllama();
|
|
@@ -494,7 +500,7 @@ async function runWizard(opts = {}) {
|
|
|
494
500
|
if (p.isCancel(choice)) bail();
|
|
495
501
|
if (choice === "install-ollama") {
|
|
496
502
|
p.note(
|
|
497
|
-
"Instala Ollama y descarga un modelo:\n\n curl -fsSL https://ollama.com/install.sh | sh\n ollama pull llama3.1\n\nVuelve a ejecutar `
|
|
503
|
+
"Instala Ollama y descarga un modelo:\n\n curl -fsSL https://ollama.com/install.sh | sh\n ollama pull llama3.1\n\nVuelve a ejecutar `openexpert init` cuando est\xE9 listo.",
|
|
498
504
|
"Instalar Ollama"
|
|
499
505
|
);
|
|
500
506
|
p.outro("Sin cambios.");
|
|
@@ -554,18 +560,18 @@ async function runWizard(opts = {}) {
|
|
|
554
560
|
|
|
555
561
|
// src/cli.ts
|
|
556
562
|
function help() {
|
|
557
|
-
console.log(`
|
|
563
|
+
console.log(`OpenExpert \u2014 motor local
|
|
558
564
|
|
|
559
565
|
Uso:
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
566
|
+
openexpert asistente de configuraci\xF3n y arranque
|
|
567
|
+
openexpert init igual que sin argumentos
|
|
568
|
+
openexpert serve arranca la edici\xF3n local en http://localhost:3000
|
|
569
|
+
openexpert desktop arranca el servidor y abre la ventana de escritorio
|
|
570
|
+
openexpert doctor revisa tu configuraci\xF3n
|
|
571
|
+
openexpert fix auto-configura lo que falte
|
|
572
|
+
openexpert models lista los modelos del proveedor actual
|
|
573
|
+
openexpert update limpia la cach\xE9 del servidor descargado
|
|
574
|
+
openexpert version muestra la versi\xF3n
|
|
569
575
|
|
|
570
576
|
Ejemplos:
|
|
571
577
|
npx @openexpert/opencore
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +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"]}
|
|
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 *\n * Trailing slashes are removed with a loop, not with `/\\/+$/`: a regex has to\n * retry at every position of a long run of slashes, which is what CodeQL\n * reports as a polynomial ReDoS on `baseUrl`.\n */\nfunction stripTrailingSlashes(value: string): string {\n let end = value.length;\n while (end > 0 && value[end - 1] === \"/\") end -= 1;\n return value.slice(0, end);\n}\n\nexport function ollamaApiBaseUrl(baseUrl: string): string {\n const base = stripTrailingSlashes(baseUrl.trim());\n return base.endsWith(\"/v1\") ? base.slice(0, -3) : base;\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 ${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(\"OpenExpert 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 `openexpert 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: `openexpert serve` (o `openexpert 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 (openexpert 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 OpenExpert 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(\"OpenExpert — 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 `openexpert 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(`OpenExpert — motor local\n\nUso:\n openexpert asistente de configuración y arranque\n openexpert init igual que sin argumentos\n openexpert serve arranca la edición local en http://localhost:3000\n openexpert desktop arranca el servidor y abre la ventana de escritorio\n openexpert doctor revisa tu configuración\n openexpert fix auto-configura lo que falte\n openexpert models lista los modelos del proveedor actual\n openexpert update limpia la caché del servidor descargado\n openexpert 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
CHANGED
|
@@ -16,6 +16,16 @@ type OpenExpertConfig = {
|
|
|
16
16
|
modelId: string;
|
|
17
17
|
ollamaBaseUrl: string;
|
|
18
18
|
dataDir: string;
|
|
19
|
+
/**
|
|
20
|
+
* Google OAuth client ID (non-secret public identifier) for the Drive
|
|
21
|
+
* integration. The secret lives in env or ~/.openexpert/secrets.json.
|
|
22
|
+
*/
|
|
23
|
+
googleClientId: string;
|
|
24
|
+
/**
|
|
25
|
+
* Notion OAuth client ID (non-secret public identifier) for the Notion
|
|
26
|
+
* connection. The secret lives in env or ~/.openexpert/secrets.json.
|
|
27
|
+
*/
|
|
28
|
+
notionClientId: string;
|
|
19
29
|
ai: AiConfig;
|
|
20
30
|
chat: ChatConfig;
|
|
21
31
|
};
|
package/dist/config.js
CHANGED
|
@@ -7,7 +7,9 @@ var DEFAULTS = {
|
|
|
7
7
|
modelId: "gemini-2.5-flash",
|
|
8
8
|
ollamaBaseUrl: "http://localhost:11434",
|
|
9
9
|
dataDir: "~/.openexpert",
|
|
10
|
-
|
|
10
|
+
googleClientId: "",
|
|
11
|
+
notionClientId: "",
|
|
12
|
+
ai: { temperature: 0.5, topP: 1, maxOutputTokens: 4096 },
|
|
11
13
|
chat: {
|
|
12
14
|
maxSteps: 50,
|
|
13
15
|
injectionGuard: true,
|
|
@@ -46,6 +48,8 @@ function loadConfig(cwd = process.cwd()) {
|
|
|
46
48
|
modelId: env["OPENEXPERT_MODEL_ID"] ?? file.modelId ?? DEFAULTS.modelId,
|
|
47
49
|
ollamaBaseUrl: env["OLLAMA_BASE_URL"] ?? file.ollamaBaseUrl ?? DEFAULTS.ollamaBaseUrl,
|
|
48
50
|
dataDir: expandHome(env["OPENEXPERT_DATA_DIR"] ?? file.dataDir ?? DEFAULTS.dataDir),
|
|
51
|
+
googleClientId: env["OPENEXPERT_GOOGLE_CLIENT_ID"] ?? file.googleClientId ?? DEFAULTS.googleClientId,
|
|
52
|
+
notionClientId: env["OPENEXPERT_NOTION_CLIENT_ID"] ?? file.notionClientId ?? DEFAULTS.notionClientId,
|
|
49
53
|
ai: {
|
|
50
54
|
temperature: num(fileAi.temperature, DEFAULTS.ai.temperature),
|
|
51
55
|
topP: num(fileAi.topP, DEFAULTS.ai.topP),
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/config.ts"],"names":[],"mappings":";;;;
|
|
1
|
+
{"version":3,"sources":["../src/config.ts"],"names":[],"mappings":"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","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 /**\n * Google OAuth client ID (non-secret public identifier) for the Drive\n * integration. The secret lives in env or ~/.openexpert/secrets.json.\n */\n googleClientId: string;\n /**\n * Notion OAuth client ID (non-secret public identifier) for the Notion\n * connection. The secret lives in env or ~/.openexpert/secrets.json.\n */\n notionClientId: 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 googleClientId: \"\",\n notionClientId: \"\",\n ai: { temperature: 0.5, 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 googleClientId:\n env[\"OPENEXPERT_GOOGLE_CLIENT_ID\"] ?? file.googleClientId ?? DEFAULTS.googleClientId,\n notionClientId:\n env[\"OPENEXPERT_NOTION_CLIENT_ID\"] ?? file.notionClientId ?? DEFAULTS.notionClientId,\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.js
CHANGED
|
@@ -7,7 +7,9 @@ var DEFAULTS = {
|
|
|
7
7
|
modelId: "gemini-2.5-flash",
|
|
8
8
|
ollamaBaseUrl: "http://localhost:11434",
|
|
9
9
|
dataDir: "~/.openexpert",
|
|
10
|
-
|
|
10
|
+
googleClientId: "",
|
|
11
|
+
notionClientId: "",
|
|
12
|
+
ai: { temperature: 0.5, topP: 1, maxOutputTokens: 4096 },
|
|
11
13
|
chat: {
|
|
12
14
|
maxSteps: 50,
|
|
13
15
|
injectionGuard: true,
|
|
@@ -46,6 +48,8 @@ function loadConfig(cwd = process.cwd()) {
|
|
|
46
48
|
modelId: env["OPENEXPERT_MODEL_ID"] ?? file.modelId ?? DEFAULTS.modelId,
|
|
47
49
|
ollamaBaseUrl: env["OLLAMA_BASE_URL"] ?? file.ollamaBaseUrl ?? DEFAULTS.ollamaBaseUrl,
|
|
48
50
|
dataDir: expandHome(env["OPENEXPERT_DATA_DIR"] ?? file.dataDir ?? DEFAULTS.dataDir),
|
|
51
|
+
googleClientId: env["OPENEXPERT_GOOGLE_CLIENT_ID"] ?? file.googleClientId ?? DEFAULTS.googleClientId,
|
|
52
|
+
notionClientId: env["OPENEXPERT_NOTION_CLIENT_ID"] ?? file.notionClientId ?? DEFAULTS.notionClientId,
|
|
49
53
|
ai: {
|
|
50
54
|
temperature: num(fileAi.temperature, DEFAULTS.ai.temperature),
|
|
51
55
|
topP: num(fileAi.topP, DEFAULTS.ai.topP),
|
|
@@ -84,8 +88,14 @@ function selectModel(env = process.env) {
|
|
|
84
88
|
keySource: "GOOGLE_API_KEY"
|
|
85
89
|
};
|
|
86
90
|
}
|
|
91
|
+
function stripTrailingSlashes(value) {
|
|
92
|
+
let end = value.length;
|
|
93
|
+
while (end > 0 && value[end - 1] === "/") end -= 1;
|
|
94
|
+
return value.slice(0, end);
|
|
95
|
+
}
|
|
87
96
|
function ollamaApiBaseUrl(baseUrl) {
|
|
88
|
-
|
|
97
|
+
const base = stripTrailingSlashes(baseUrl.trim());
|
|
98
|
+
return base.endsWith("/v1") ? base.slice(0, -3) : base;
|
|
89
99
|
}
|
|
90
100
|
function ollamaChatBaseUrl(baseUrl) {
|
|
91
101
|
return `${ollamaApiBaseUrl(baseUrl)}/v1`;
|
|
@@ -105,7 +115,6 @@ function missingKeyHint(sel, env = process.env) {
|
|
|
105
115
|
var LOCAL_TABLES = [
|
|
106
116
|
"experts",
|
|
107
117
|
"integrations",
|
|
108
|
-
"processes",
|
|
109
118
|
"activity",
|
|
110
119
|
"chat_messages",
|
|
111
120
|
"deals",
|
|
@@ -128,14 +137,12 @@ var TOOL_CATALOG = [
|
|
|
128
137
|
{ name: "list_overdue_invoices", domain: "finanzas", needs: "read", proposesOnly: false },
|
|
129
138
|
{ name: "get_campaign_performance", domain: "marketing", needs: "read", proposesOnly: false },
|
|
130
139
|
{ name: "get_churn_risk", domain: "general", needs: "read", proposesOnly: false },
|
|
131
|
-
{ name: "list_processes", domain: "transversal", needs: "read", proposesOnly: false },
|
|
132
140
|
{ name: "search_drive", domain: "drive", needs: "read", proposesOnly: false },
|
|
133
141
|
{ name: "read_drive_file", domain: "drive", needs: "read", proposesOnly: false },
|
|
134
142
|
{ name: "create_drive_file", domain: "drive", needs: "exec", proposesOnly: false },
|
|
135
143
|
{ name: "update_drive_file", domain: "drive", needs: "exec", proposesOnly: false },
|
|
136
144
|
{ name: "propose_invoice_reminders", domain: "finanzas", needs: "exec", proposesOnly: true },
|
|
137
145
|
{ name: "propose_pause_campaigns", domain: "marketing", needs: "exec", proposesOnly: true },
|
|
138
|
-
{ name: "request_process_run", domain: "transversal", needs: "exec", proposesOnly: true },
|
|
139
146
|
{ name: "open_expert_form", domain: "transversal", needs: "exec", proposesOnly: false }
|
|
140
147
|
];
|
|
141
148
|
|
package/dist/index.js.map
CHANGED
|
@@ -1 +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"]}
|
|
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 /**\n * Google OAuth client ID (non-secret public identifier) for the Drive\n * integration. The secret lives in env or ~/.openexpert/secrets.json.\n */\n googleClientId: string;\n /**\n * Notion OAuth client ID (non-secret public identifier) for the Notion\n * connection. The secret lives in env or ~/.openexpert/secrets.json.\n */\n notionClientId: 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 googleClientId: \"\",\n notionClientId: \"\",\n ai: { temperature: 0.5, 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 googleClientId:\n env[\"OPENEXPERT_GOOGLE_CLIENT_ID\"] ?? file.googleClientId ?? DEFAULTS.googleClientId,\n notionClientId:\n env[\"OPENEXPERT_NOTION_CLIENT_ID\"] ?? file.notionClientId ?? DEFAULTS.notionClientId,\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 *\n * Trailing slashes are removed with a loop, not with `/\\/+$/`: a regex has to\n * retry at every position of a long run of slashes, which is what CodeQL\n * reports as a polynomial ReDoS on `baseUrl`.\n */\nfunction stripTrailingSlashes(value: string): string {\n let end = value.length;\n while (end > 0 && value[end - 1] === \"/\") end -= 1;\n return value.slice(0, end);\n}\n\nexport function ollamaApiBaseUrl(baseUrl: string): string {\n const base = stripTrailingSlashes(baseUrl.trim());\n return base.endsWith(\"/v1\") ? base.slice(0, -3) : base;\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 | \"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 \"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 12).\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: \"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: \"open_expert_form\", domain: \"transversal\", needs: \"exec\", proposesOnly: false },\n];\n"]}
|
package/dist/model-provider.d.ts
CHANGED
|
@@ -6,11 +6,6 @@ type ModelSelection = {
|
|
|
6
6
|
keySource: "GOOGLE_API_KEY" | "OPENEXPERT_MODEL_KEY" | "none (local)";
|
|
7
7
|
};
|
|
8
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
9
|
declare function ollamaApiBaseUrl(baseUrl: string): string;
|
|
15
10
|
declare function ollamaChatBaseUrl(baseUrl: string): string;
|
|
16
11
|
declare function missingKeyHint(sel: ModelSelection, env?: NodeJS.ProcessEnv): string | null;
|
package/dist/model-provider.js
CHANGED
|
@@ -22,8 +22,14 @@ function selectModel(env = process.env) {
|
|
|
22
22
|
keySource: "GOOGLE_API_KEY"
|
|
23
23
|
};
|
|
24
24
|
}
|
|
25
|
+
function stripTrailingSlashes(value) {
|
|
26
|
+
let end = value.length;
|
|
27
|
+
while (end > 0 && value[end - 1] === "/") end -= 1;
|
|
28
|
+
return value.slice(0, end);
|
|
29
|
+
}
|
|
25
30
|
function ollamaApiBaseUrl(baseUrl) {
|
|
26
|
-
|
|
31
|
+
const base = stripTrailingSlashes(baseUrl.trim());
|
|
32
|
+
return base.endsWith("/v1") ? base.slice(0, -3) : base;
|
|
27
33
|
}
|
|
28
34
|
function ollamaChatBaseUrl(baseUrl) {
|
|
29
35
|
return `${ollamaApiBaseUrl(baseUrl)}/v1`;
|
|
@@ -1 +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;
|
|
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;AAWA,SAAS,qBAAqB,KAAA,EAAuB;AACnD,EAAA,IAAI,MAAM,KAAA,CAAM,MAAA;AAChB,EAAA,OAAO,MAAM,CAAA,IAAK,KAAA,CAAM,MAAM,CAAC,CAAA,KAAM,KAAK,GAAA,IAAO,CAAA;AACjD,EAAA,OAAO,KAAA,CAAM,KAAA,CAAM,CAAA,EAAG,GAAG,CAAA;AAC3B;AAEO,SAAS,iBAAiB,OAAA,EAAyB;AACxD,EAAA,MAAM,IAAA,GAAO,oBAAA,CAAqB,OAAA,CAAQ,IAAA,EAAM,CAAA;AAChD,EAAA,OAAO,IAAA,CAAK,SAAS,KAAK,CAAA,GAAI,KAAK,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA,GAAI,IAAA;AACpD;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 *\n * Trailing slashes are removed with a loop, not with `/\\/+$/`: a regex has to\n * retry at every position of a long run of slashes, which is what CodeQL\n * reports as a polynomial ReDoS on `baseUrl`.\n */\nfunction stripTrailingSlashes(value: string): string {\n let end = value.length;\n while (end > 0 && value[end - 1] === \"/\") end -= 1;\n return value.slice(0, end);\n}\n\nexport function ollamaApiBaseUrl(baseUrl: string): string {\n const base = stripTrailingSlashes(baseUrl.trim());\n return base.endsWith(\"/v1\") ? base.slice(0, -3) : base;\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"]}
|
package/dist/storage.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
type TableName = "experts" | "integrations" | "
|
|
1
|
+
type TableName = "experts" | "integrations" | "activity" | "chat_messages" | "deals" | "invoices" | "campaigns" | "accounts" | "settings";
|
|
2
2
|
type Row = Record<string, unknown>;
|
|
3
3
|
interface Storage {
|
|
4
4
|
readonly kind: "file";
|
package/dist/storage.js
CHANGED
package/dist/storage.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/storage.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"sources":["../src/storage.ts"],"names":[],"mappings":";AAuBO,IAAM,YAAA,GAA4B;AAAA,EACvC,SAAA;AAAA,EACA,cAAA;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 | \"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 \"activity\",\n \"chat_messages\",\n \"deals\",\n \"invoices\",\n \"campaigns\",\n \"accounts\",\n \"settings\",\n];\n"]}
|
package/dist/tools.js
CHANGED
|
@@ -5,14 +5,12 @@ var TOOL_CATALOG = [
|
|
|
5
5
|
{ name: "list_overdue_invoices", domain: "finanzas", needs: "read", proposesOnly: false },
|
|
6
6
|
{ name: "get_campaign_performance", domain: "marketing", needs: "read", proposesOnly: false },
|
|
7
7
|
{ name: "get_churn_risk", domain: "general", needs: "read", proposesOnly: false },
|
|
8
|
-
{ name: "list_processes", domain: "transversal", needs: "read", proposesOnly: false },
|
|
9
8
|
{ name: "search_drive", domain: "drive", needs: "read", proposesOnly: false },
|
|
10
9
|
{ name: "read_drive_file", domain: "drive", needs: "read", proposesOnly: false },
|
|
11
10
|
{ name: "create_drive_file", domain: "drive", needs: "exec", proposesOnly: false },
|
|
12
11
|
{ name: "update_drive_file", domain: "drive", needs: "exec", proposesOnly: false },
|
|
13
12
|
{ name: "propose_invoice_reminders", domain: "finanzas", needs: "exec", proposesOnly: true },
|
|
14
13
|
{ name: "propose_pause_campaigns", domain: "marketing", needs: "exec", proposesOnly: true },
|
|
15
|
-
{ name: "request_process_run", domain: "transversal", needs: "exec", proposesOnly: true },
|
|
16
14
|
{ name: "open_expert_form", domain: "transversal", needs: "exec", proposesOnly: false }
|
|
17
15
|
];
|
|
18
16
|
|
package/dist/tools.js.map
CHANGED
|
@@ -1 +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,
|
|
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,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,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 12).\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: \"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: \"open_expert_form\", domain: \"transversal\", needs: \"exec\", proposesOnly: false },\n];\n"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openexpert/opencore",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "OpenCore — open-source engine of OpenExpert (MIT).
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "OpenCore — open-source engine of OpenExpert (MIT). Config, model provider selector (Google / Ollama / OpenAI-compatible), storage and secrets interfaces, tool catalog, and CLI.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "./dist/index.js",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"agents",
|
|
57
57
|
"mit",
|
|
58
58
|
"oss",
|
|
59
|
-
"
|
|
59
|
+
"local-first"
|
|
60
60
|
],
|
|
61
61
|
"repository": {
|
|
62
62
|
"type": "git",
|
|
@@ -85,7 +85,7 @@
|
|
|
85
85
|
},
|
|
86
86
|
"dependencies": {
|
|
87
87
|
"@ai-sdk/openai": "^4.0.5",
|
|
88
|
-
"@clack/prompts": "^
|
|
88
|
+
"@clack/prompts": "^1.8.1",
|
|
89
89
|
"ai": "^7.0.0"
|
|
90
90
|
},
|
|
91
91
|
"devDependencies": {
|
|
@@ -26,6 +26,16 @@
|
|
|
26
26
|
"minLength": 1,
|
|
27
27
|
"description": "Directory where the SQLite database and credentials live. `~/` expands to the user's home directory."
|
|
28
28
|
},
|
|
29
|
+
"googleClientId": {
|
|
30
|
+
"type": "string",
|
|
31
|
+
"minLength": 1,
|
|
32
|
+
"description": "Google OAuth client ID (public identifier) used for the Drive integration. The matching client secret lives in secrets.json."
|
|
33
|
+
},
|
|
34
|
+
"notionClientId": {
|
|
35
|
+
"type": "string",
|
|
36
|
+
"minLength": 1,
|
|
37
|
+
"description": "Notion OAuth client ID (public identifier) used to connect Notion. The matching client secret lives in secrets.json."
|
|
38
|
+
},
|
|
29
39
|
"ai": {
|
|
30
40
|
"type": "object",
|
|
31
41
|
"additionalProperties": false,
|