omnexx 0.5.0 → 0.6.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.
Files changed (43) hide show
  1. package/dist/chat-server-NB3GPOMD.js +205 -0
  2. package/dist/chat-server-NB3GPOMD.js.map +1 -0
  3. package/dist/chat-settings-D3WKVSFU.js +110 -0
  4. package/dist/chat-settings-D3WKVSFU.js.map +1 -0
  5. package/dist/{chunk-YMIRAOIB.js → chunk-55VJCO7L.js} +12 -4
  6. package/dist/chunk-55VJCO7L.js.map +1 -0
  7. package/dist/{chunk-CLAS22GZ.js → chunk-5T4EFIY2.js} +10 -76
  8. package/dist/chunk-5T4EFIY2.js.map +1 -0
  9. package/dist/chunk-7PC4SSYS.js +78 -0
  10. package/dist/chunk-7PC4SSYS.js.map +1 -0
  11. package/dist/chunk-7PNGHZYH.js +87 -0
  12. package/dist/chunk-7PNGHZYH.js.map +1 -0
  13. package/dist/{chunk-IJPR52MO.js → chunk-AOIUX7TJ.js} +6 -4
  14. package/dist/{chunk-IJPR52MO.js.map → chunk-AOIUX7TJ.js.map} +1 -1
  15. package/dist/{start-Y5B2FUMR.js → chunk-M64SDRL3.js} +250 -1008
  16. package/dist/chunk-M64SDRL3.js.map +1 -0
  17. package/dist/{chunk-TZ3KO3PA.js → chunk-N2WJ2YTX.js} +571 -461
  18. package/dist/chunk-N2WJ2YTX.js.map +1 -0
  19. package/dist/{chunk-OXDXHUTX.js → chunk-PY47EEHG.js} +279 -345
  20. package/dist/chunk-PY47EEHG.js.map +1 -0
  21. package/dist/{chunk-Y74QSMFT.js → chunk-S3TUDM5B.js} +23 -100
  22. package/dist/chunk-S3TUDM5B.js.map +1 -0
  23. package/dist/chunk-UZ6WXVKI.js +146 -0
  24. package/dist/chunk-UZ6WXVKI.js.map +1 -0
  25. package/dist/cli.js +33 -24
  26. package/dist/cli.js.map +1 -1
  27. package/dist/model-picker-7NLP3QO6.js +20 -0
  28. package/dist/model-picker-7NLP3QO6.js.map +1 -0
  29. package/dist/{ollama-VFXDRFQ4.js → ollama-V6LN6HAR.js} +6 -4
  30. package/dist/{ollama-VFXDRFQ4.js.map → ollama-V6LN6HAR.js.map} +1 -1
  31. package/dist/{print-KUDY6NOG.js → print-OUSVBDAA.js} +5 -4
  32. package/dist/{print-KUDY6NOG.js.map → print-OUSVBDAA.js.map} +1 -1
  33. package/dist/session-YXEM22IA.js +26 -0
  34. package/dist/session-YXEM22IA.js.map +1 -0
  35. package/dist/start-ZJQLZBS6.js +709 -0
  36. package/dist/start-ZJQLZBS6.js.map +1 -0
  37. package/package.json +2 -2
  38. package/dist/chunk-CLAS22GZ.js.map +0 -1
  39. package/dist/chunk-OXDXHUTX.js.map +0 -1
  40. package/dist/chunk-TZ3KO3PA.js.map +0 -1
  41. package/dist/chunk-Y74QSMFT.js.map +0 -1
  42. package/dist/chunk-YMIRAOIB.js.map +0 -1
  43. package/dist/start-Y5B2FUMR.js.map +0 -1
@@ -1,82 +1,20 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ println,
4
+ readLine
5
+ } from "./chunk-7PC4SSYS.js";
2
6
  import {
3
7
  EXIT,
4
- UsageError,
5
8
  findProviderKey,
6
9
  loadConfig,
7
10
  makeEndpointProvider,
8
11
  parseDuration,
9
12
  resolvePaths,
10
13
  userConfigFile
11
- } from "./chunk-Y74QSMFT.js";
12
-
13
- // src/cli/io.ts
14
- import { createInterface } from "readline";
15
- function processIO() {
16
- return {
17
- stdout: process.stdout,
18
- stderr: process.stderr,
19
- stdin: process.stdin,
20
- env: process.env,
21
- cwd: process.cwd(),
22
- isTTY: process.stdin.isTTY && process.stdout.isTTY
23
- };
24
- }
25
- function println(out, line = "") {
26
- out.write(`${line}
27
- `);
28
- }
29
- function readLine(io, prompt) {
30
- io.stdout.write(prompt);
31
- return new Promise((resolve) => {
32
- const rl = createInterface({ input: io.stdin, terminal: false });
33
- let answered = false;
34
- rl.once("line", (line) => {
35
- answered = true;
36
- rl.close();
37
- resolve(line);
38
- });
39
- rl.once("close", () => {
40
- if (!answered) resolve(void 0);
41
- });
42
- });
43
- }
44
- async function confirm(io, question) {
45
- const answer = await readLine(io, `${question} [y/N] `);
46
- return /^\s*y(es)?\s*$/i.test(answer ?? "");
47
- }
48
- async function readSecret(io, prompt) {
49
- const stdin = io.stdin;
50
- if (!io.isTTY || typeof stdin.setRawMode !== "function") return readLine(io, prompt);
51
- io.stdout.write(prompt);
52
- stdin.setRawMode(true);
53
- stdin.resume();
54
- return new Promise((resolve) => {
55
- let value = "";
56
- const onData = (chunk) => {
57
- for (const ch of chunk.toString("utf8")) {
58
- if (ch === "\r" || ch === "\n" || ch === "") {
59
- finish(value);
60
- return;
61
- }
62
- if (ch === "") {
63
- finish(void 0);
64
- return;
65
- }
66
- if (ch === "\x7F") value = value.slice(0, -1);
67
- else value += ch;
68
- }
69
- };
70
- const finish = (v) => {
71
- stdin.off("data", onData);
72
- stdin.setRawMode(false);
73
- stdin.pause();
74
- io.stdout.write("\n");
75
- resolve(v);
76
- };
77
- stdin.on("data", onData);
78
- });
79
- }
14
+ } from "./chunk-S3TUDM5B.js";
15
+ import {
16
+ UsageError
17
+ } from "./chunk-7PNGHZYH.js";
80
18
 
81
19
  // src/cli/commands/providers.ts
82
20
  import { appendFile, mkdir, readFile } from "fs/promises";
@@ -332,13 +270,9 @@ var register = (program, io, setExit) => {
332
270
  };
333
271
 
334
272
  export {
335
- processIO,
336
- println,
337
- readLine,
338
- confirm,
339
- readSecret,
340
273
  PROVIDER_TEMPLATES,
341
274
  appendEndpointBlock,
275
+ removeEndpointBlock,
342
276
  register
343
277
  };
344
- //# sourceMappingURL=chunk-CLAS22GZ.js.map
278
+ //# sourceMappingURL=chunk-5T4EFIY2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/commands/providers.ts"],"sourcesContent":["import { appendFile, mkdir, readFile } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport type { Command } from 'commander';\nimport { stringify as stringifyToml } from 'smol-toml';\nimport { findProviderKey } from '../../auth/keys.js';\nimport { loadConfig } from '../../config/load.js';\nimport { parseDuration } from '../../config/duration.js';\nimport { resolvePaths, userConfigFile } from '../../core/paths.js';\nimport { UsageError } from '../../errors.js';\nimport { makeEndpointProvider } from '../../providers/make.js';\nimport type { CommandRegistrar } from './extra/types.js';\nimport { println, readLine, type CliIO } from '../io.js';\nimport { EXIT } from '../exit-codes.js';\n\n/** Preset templates: suggestions only, written into user config on `add`. */\nexport interface ProviderTemplate {\n baseUrl: string;\n keyEnv: string | undefined;\n free: boolean;\n kind: 'openai' | 'responses' | 'gemini';\n /** Display name. */\n label?: string;\n /** How its API keys start, so a pasted key is recognised. */\n keyPrefix?: string;\n /** Where to get a key. */\n signup?: string;\n /** Local server: no key, started by the person. */\n local?: boolean;\n}\n\ntype Row = [\n name: string,\n label: string,\n baseUrl: string,\n keyEnv: string | undefined,\n keyPrefix: string | undefined,\n signup: string | undefined,\n];\n\n/**\n * Every provider omnexx knows by name (checked 2026-10). All speak the OpenAI Chat Completions\n * API except Gemini (native). Anthropic is built in and not listed here. Any other\n * OpenAI-compatible service works by URL: `/connect https://host/v1 KEY`.\n * One per line: name | label | base URL | key env var | key prefix | signup ('-' = none).\n */\nconst HOSTED: Row[] = [\n 'openai | OpenAI | https://api.openai.com/v1 | OPENAI_API_KEY | sk- | https://platform.openai.com/api-keys',\n 'gemini | Google Gemini | https://generativelanguage.googleapis.com | GEMINI_API_KEY | AIza | https://aistudio.google.com/apikey',\n 'xai | xAI (Grok) | https://api.x.ai/v1 | XAI_API_KEY | xai- | https://console.x.ai',\n 'mistral | Mistral | https://api.mistral.ai/v1 | MISTRAL_API_KEY | - | https://console.mistral.ai/api-keys',\n 'deepseek | DeepSeek | https://api.deepseek.com/v1 | DEEPSEEK_API_KEY | - | https://platform.deepseek.com/api_keys',\n 'groq | Groq | https://api.groq.com/openai/v1 | GROQ_API_KEY | gsk_ | https://console.groq.com/keys',\n 'cerebras | Cerebras | https://api.cerebras.ai/v1 | CEREBRAS_API_KEY | csk- | https://cloud.cerebras.ai',\n 'openrouter | OpenRouter (hundreds of models) | https://openrouter.ai/api/v1 | OPENROUTER_API_KEY | sk-or- | https://openrouter.ai/keys',\n 'together | Together AI | https://api.together.xyz/v1 | TOGETHER_API_KEY | - | https://api.together.ai/settings/api-keys',\n 'fireworks | Fireworks | https://api.fireworks.ai/inference/v1 | FIREWORKS_API_KEY | fw_ | https://fireworks.ai/account/api-keys',\n 'nvidia | NVIDIA NIM | https://integrate.api.nvidia.com/v1 | NVIDIA_API_KEY | nvapi- | https://build.nvidia.com',\n 'moonshot | Moonshot (Kimi) | https://api.moonshot.ai/v1 | MOONSHOT_API_KEY | - | https://platform.moonshot.ai/console/api-keys',\n 'zai | Z.ai (GLM) | https://api.z.ai/api/paas/v4 | ZAI_API_KEY | - | https://z.ai/manage-apikey/apikey-list',\n 'dashscope | Alibaba Cloud (Qwen) | https://dashscope-intl.aliyuncs.com/compatible-mode/v1 | DASHSCOPE_API_KEY | - | https://modelstudio.console.alibabacloud.com',\n 'siliconflow | SiliconFlow | https://api.siliconflow.com/v1 | SILICONFLOW_API_KEY | - | https://cloud.siliconflow.com/account/ak',\n 'deepinfra | DeepInfra | https://api.deepinfra.com/v1/openai | DEEPINFRA_API_KEY | - | https://deepinfra.com/dash/api_keys',\n 'huggingface | Hugging Face Inference | https://router.huggingface.co/v1 | HF_TOKEN | hf_ | https://huggingface.co/settings/tokens',\n 'perplexity | Perplexity | https://api.perplexity.ai | PERPLEXITY_API_KEY | pplx- | https://www.perplexity.ai/settings/api',\n 'cohere | Cohere | https://api.cohere.ai/compatibility/v1 | COHERE_API_KEY | - | https://dashboard.cohere.com/api-keys',\n 'vercel | Vercel AI Gateway | https://ai-gateway.vercel.sh/v1 | AI_GATEWAY_API_KEY | - | https://vercel.com/ai-gateway',\n 'github | GitHub Models | https://models.github.ai/inference | GITHUB_TOKEN | - | https://github.com/settings/tokens',\n 'novita | Novita AI | https://api.novita.ai/v3/openai | NOVITA_API_KEY | - | https://novita.ai/settings/key-management',\n 'hyperbolic | Hyperbolic | https://api.hyperbolic.xyz/v1 | HYPERBOLIC_API_KEY | - | https://app.hyperbolic.xyz/settings',\n 'sambanova | SambaNova | https://api.sambanova.ai/v1 | SAMBANOVA_API_KEY | - | https://cloud.sambanova.ai/apis',\n]\n .map((line) => line.split(' | ').map((f) => (f === '-' ? undefined : f)))\n .map(([name = '', label = '', baseUrl = '', keyEnv, keyPrefix, signup]) => [\n name,\n label,\n baseUrl,\n keyEnv,\n keyPrefix,\n signup,\n ]);\n\nconst LOCAL: [string, string, string][] = [\n ['ollama', 'Ollama', 'http://localhost:11434/v1'],\n ['lmstudio', 'LM Studio', 'http://localhost:1234/v1'],\n ['vllm', 'vLLM', 'http://localhost:8000/v1'],\n ['llamacpp', 'llama.cpp server', 'http://localhost:8080/v1'],\n ['litellm', 'LiteLLM proxy', 'http://localhost:4000/v1'],\n ['jan', 'Jan', 'http://localhost:1337/v1'],\n];\n\nexport const PROVIDER_TEMPLATES: Record<string, ProviderTemplate> = Object.fromEntries([\n ...HOSTED.map(([name, label, baseUrl, keyEnv, keyPrefix, signup]): [string, ProviderTemplate] => [\n name,\n {\n label,\n baseUrl,\n keyEnv,\n free: false,\n kind: name === 'gemini' ? 'gemini' : 'openai',\n ...(keyPrefix ? { keyPrefix } : {}),\n ...(signup ? { signup } : {}),\n },\n ]),\n ...LOCAL.map(([name, label, baseUrl]): [string, ProviderTemplate] => [\n name,\n { label, baseUrl, keyEnv: undefined, free: true, kind: 'openai', local: true },\n ]),\n [\n 'custom',\n { baseUrl: 'http://localhost:8000/v1', keyEnv: undefined, free: false, kind: 'openai' },\n ],\n]);\n\nexport function templateFor(name: string): ProviderTemplate | undefined {\n return PROVIDER_TEMPLATES[name.toLowerCase()];\n}\n\nexport async function appendEndpointBlock(\n file: string,\n name: string,\n t: ProviderTemplate,\n): Promise<void> {\n const block = stringifyToml({\n providers: {\n endpoints: {\n [name]: {\n kind: t.kind,\n base_url: t.baseUrl,\n ...(t.keyEnv ? { api_key_env: t.keyEnv } : {}),\n ...(t.free ? { free: true } : {}),\n },\n },\n },\n });\n await mkdir(dirname(file), { recursive: true });\n await appendFile(file, `\\n${block}`);\n}\n\nexport async function removeEndpointBlock(file: string, name: string): Promise<boolean> {\n let text: string;\n try {\n text = await readFile(file, 'utf8');\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return false;\n throw err;\n }\n const lines = text.split('\\n');\n const start = lines.findIndex((l) => l.trim() === `[providers.endpoints.${name}]`);\n if (start === -1) return false;\n let end = lines.length;\n for (let i = start + 1; i < lines.length; i++) {\n if (/^\\s*\\[.+\\]\\s*$/.test(lines[i] ?? '')) {\n end = i;\n break;\n }\n }\n await mkdir(dirname(file), { recursive: true });\n const { writeFile } = await import('node:fs/promises');\n await writeFile(file, lines.slice(0, start).concat(lines.slice(end)).join('\\n'));\n return true;\n}\n\nasync function testEndpoint(\n io: CliIO,\n name: string,\n baseUrl: string,\n apiKey: string | undefined,\n kind: 'openai' | 'responses' | 'gemini',\n): Promise<{ ok: boolean; detail: string }> {\n const { config } = await loadConfig({ cwd: io.cwd, env: io.env });\n const ep = config.providers.endpoints[name];\n const timeoutMs = ep ? parseDuration(ep.request_timeout) : 10_000;\n const opts = { name, baseUrl, apiKey, timeoutMs, ...(io.fetch ? { fetch: io.fetch } : {}) };\n const provider = makeEndpointProvider(kind, opts);\n try {\n // 1-token test call: tiny maxTokens, no tools.\n const res = await provider.complete({\n model: 'test',\n system: [{ text: 'Reply with the single word: ok' }],\n tools: [],\n messages: [{ role: 'user', content: [{ type: 'text', text: 'ok' }] }],\n maxTokens: 1,\n messageBreakpoints: [],\n });\n const text = res.content\n .filter((b) => b.type === 'text')\n .map((b) => (b as { text: string }).text)\n .join('')\n .slice(0, 80);\n return { ok: true, detail: text ? `answered (${text})` : 'answered' };\n } catch (err) {\n return { ok: false, detail: err instanceof Error ? err.message : String(err) };\n }\n}\n\nexport interface ProvidersAddOptions {\n baseUrl?: string | undefined;\n keyEnv?: string | undefined;\n free?: boolean | undefined;\n kind?: 'openai' | 'responses' | undefined;\n skipTest?: boolean | undefined;\n}\n\nexport async function providersAdd(\n io: CliIO,\n name: string,\n opts: ProvidersAddOptions,\n): Promise<number> {\n const lower = name.toLowerCase();\n if (!/^[a-z][a-z0-9_-]*$/.test(lower))\n throw new UsageError(`bad provider name \"${name}\"`, 'use lowercase letters, digits, _ or -');\n const { config } = await loadConfig({ cwd: io.cwd, env: io.env });\n if (config.providers.endpoints[lower])\n throw new UsageError(\n `provider \"${lower}\" already exists`,\n `use \\`omnexx providers remove ${lower}\\` first`,\n );\n const template = templateFor(lower);\n let baseUrl = opts.baseUrl;\n let keyEnv = opts.keyEnv;\n let free = opts.free;\n const kind = opts.kind ?? template?.kind ?? 'openai';\n if (baseUrl === undefined || keyEnv === undefined) {\n if (io.isTTY && process.env.VITEST === undefined) {\n // Interactive prompts (readline, no new deps).\n println(io.stdout, `Adding provider \"${lower}\"${template ? ` (template: ${lower})` : ''}.`);\n const askBase = await readLine(\n io,\n `Base URL [${template?.baseUrl ?? 'http://localhost:8000/v1'}]: `,\n );\n baseUrl = baseUrl ?? askBase?.trim() ?? template?.baseUrl ?? 'http://localhost:8000/v1';\n const askKey = await readLine(io, `Key env var [${template?.keyEnv ?? 'none'}]: `);\n const trimmedKey = (keyEnv ?? askKey?.trim() ?? template?.keyEnv ?? '').trim();\n keyEnv = trimmedKey ? trimmedKey : undefined;\n if (free === undefined) {\n const askFree = await readLine(io, 'Free / no key needed? [y/N]: ');\n const saidYes = /^\\s*y(es)?\\s*$/i.test(askFree ?? '');\n const templateFree = keyEnv === undefined && template?.free === true;\n free = saidYes || templateFree;\n }\n } else {\n baseUrl ??= template?.baseUrl;\n keyEnv ??= template?.keyEnv;\n free ??= template?.free ?? false;\n if (!baseUrl)\n throw new UsageError('missing --base-url', 'pass --base-url or use a known template name');\n }\n }\n free = free ?? false;\n const file = userConfigFile(resolvePaths(io.env));\n await appendEndpointBlock(file, lower, { baseUrl, keyEnv, free, kind });\n println(io.stdout, `Added [providers.endpoints.${lower}] to ${file}.`);\n if (!opts.skipTest) {\n const paths = resolvePaths(io.env);\n const key = await findProviderKey(paths, io.env, lower, keyEnv);\n const t = await testEndpoint(io, lower, baseUrl, key?.key, kind);\n println(io.stdout, t.ok ? `Test call ok: ${t.detail}` : `Test call failed: ${t.detail}`);\n if (!t.ok) return EXIT.error;\n }\n return EXIT.ok;\n}\n\nexport async function providersList(io: CliIO): Promise<number> {\n const { config } = await loadConfig({ cwd: io.cwd, env: io.env });\n println(io.stdout, 'anthropic (built-in)');\n for (const [name, ep] of Object.entries(config.providers.endpoints)) {\n println(io.stdout, `${name} ${ep.base_url}${ep.free ? ' (free)' : ''}`);\n }\n return EXIT.ok;\n}\n\nexport async function providersRemove(io: CliIO, name: string): Promise<number> {\n const lower = name.toLowerCase();\n if (lower === 'anthropic') throw new UsageError('cannot remove anthropic', 'it is built in');\n const file = userConfigFile(resolvePaths(io.env));\n const removed = await removeEndpointBlock(file, lower);\n println(\n io.stdout,\n removed\n ? `Removed [providers.endpoints.${lower}] from ${file}.`\n : `No [providers.endpoints.${lower}] in ${file}.`,\n );\n return EXIT.ok;\n}\n\nexport async function providersTest(io: CliIO, name: string): Promise<number> {\n const lower = name.toLowerCase();\n if (lower === 'anthropic')\n throw new UsageError('anthropic has no test yet', 'run `omnexx doctor` to check the key');\n const { config } = await loadConfig({ cwd: io.cwd, env: io.env });\n const ep = config.providers.endpoints[lower];\n if (!ep)\n throw new UsageError(\n `unknown provider \"${lower}\"`,\n '`omnexx providers list` shows configured providers',\n );\n const key = await findProviderKey(resolvePaths(io.env), io.env, lower, ep.api_key_env);\n const t = await testEndpoint(\n io,\n lower,\n ep.base_url,\n key?.key,\n (ep as { kind?: 'openai' | 'responses' }).kind ?? 'openai',\n );\n println(io.stdout, t.ok ? `ok: ${t.detail}` : `failed: ${t.detail}`);\n return t.ok ? EXIT.ok : EXIT.error;\n}\n\nexport const register: CommandRegistrar = (\n program: Command,\n io: CliIO,\n setExit: (c: number) => void,\n) => {\n const p = program.command('providers').description('add, list, remove and test model providers');\n p.command('add [name]')\n .description('add a provider (interactive, or flags)')\n .option('--base-url <url>', 'endpoint base URL')\n .option('--key-env <var>', 'env var holding the key')\n .option('--free', 'no key needed (local models)')\n .option('--kind <kind>', 'openai|responses')\n .option('--no-test', 'skip the 1-token test call')\n .action(\n async (\n name: string | undefined,\n opts: { baseUrl?: string; keyEnv?: string; free?: boolean; kind?: string; test?: boolean },\n ) => {\n const n = name ?? 'custom';\n const kind = opts.kind === 'responses' ? 'responses' : 'openai';\n setExit(\n await providersAdd(io, n, {\n baseUrl: opts.baseUrl,\n keyEnv: opts.keyEnv,\n free: opts.free,\n kind,\n skipTest: opts.test === false,\n }),\n );\n },\n );\n p.command('list')\n .description('list configured providers')\n .action(async () => {\n setExit(await providersList(io));\n });\n p.command('remove <name>')\n .description('remove a provider from user config')\n .action(async (name: string) => {\n setExit(await providersRemove(io, name));\n });\n p.command('test <name>')\n .description('run a 1-token test call')\n .action(async (name: string) => {\n setExit(await providersTest(io, name));\n });\n};\n"],"mappings":"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","names":[]}
@@ -0,0 +1,78 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/cli/io.ts
4
+ import { createInterface } from "readline";
5
+ function processIO() {
6
+ return {
7
+ stdout: process.stdout,
8
+ stderr: process.stderr,
9
+ stdin: process.stdin,
10
+ env: process.env,
11
+ cwd: process.cwd(),
12
+ isTTY: process.stdin.isTTY && process.stdout.isTTY
13
+ };
14
+ }
15
+ function println(out, line = "") {
16
+ out.write(`${line}
17
+ `);
18
+ }
19
+ function readLine(io, prompt) {
20
+ io.stdout.write(prompt);
21
+ return new Promise((resolve) => {
22
+ const rl = createInterface({ input: io.stdin, terminal: false });
23
+ let answered = false;
24
+ rl.once("line", (line) => {
25
+ answered = true;
26
+ rl.close();
27
+ resolve(line);
28
+ });
29
+ rl.once("close", () => {
30
+ if (!answered) resolve(void 0);
31
+ });
32
+ });
33
+ }
34
+ async function confirm(io, question) {
35
+ const answer = await readLine(io, `${question} [y/N] `);
36
+ return /^\s*y(es)?\s*$/i.test(answer ?? "");
37
+ }
38
+ async function readSecret(io, prompt) {
39
+ const stdin = io.stdin;
40
+ if (!io.isTTY || typeof stdin.setRawMode !== "function") return readLine(io, prompt);
41
+ io.stdout.write(prompt);
42
+ stdin.setRawMode(true);
43
+ stdin.resume();
44
+ return new Promise((resolve) => {
45
+ let value = "";
46
+ const onData = (chunk) => {
47
+ for (const ch of chunk.toString("utf8")) {
48
+ if (ch === "\r" || ch === "\n" || ch === "") {
49
+ finish(value);
50
+ return;
51
+ }
52
+ if (ch === "") {
53
+ finish(void 0);
54
+ return;
55
+ }
56
+ if (ch === "\x7F") value = value.slice(0, -1);
57
+ else value += ch;
58
+ }
59
+ };
60
+ const finish = (v) => {
61
+ stdin.off("data", onData);
62
+ stdin.setRawMode(false);
63
+ stdin.pause();
64
+ io.stdout.write("\n");
65
+ resolve(v);
66
+ };
67
+ stdin.on("data", onData);
68
+ });
69
+ }
70
+
71
+ export {
72
+ processIO,
73
+ println,
74
+ readLine,
75
+ confirm,
76
+ readSecret
77
+ };
78
+ //# sourceMappingURL=chunk-7PC4SSYS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/io.ts"],"sourcesContent":["import { createInterface } from 'node:readline';\nimport type { Readable, Writable } from 'node:stream';\nimport type { Clock } from '../core/clock.js';\nimport type { RunHooks } from '../core/run.js';\nimport type { SuperviseOptions } from '../core/supervisor.js';\nimport type { Provider } from '../providers/types.js';\n\n/** Everything a command touches in the outside world, injectable so tests drive it directly. */\nexport interface CliIO {\n stdout: Writable;\n stderr: Writable;\n stdin: Readable;\n env: NodeJS.ProcessEnv;\n cwd: string;\n isTTY: boolean;\n /** Builds the model provider from the API key. Tests inject a scripted provider here. */\n makeProvider?: (apiKey: string) => Provider;\n clock?: Clock;\n fetch?: typeof fetch;\n /** Opens a sign-in page; the default browser when unset (tests substitute a fake). */\n openUrl?: (url: string) => void;\n /** argv prefix used to start supervisors (`node dist/cli.js`); tests substitute a scripted entry. */\n entry?: string[];\n /** Phase hooks for supervisors started by this CLI (chaos tests kill at a phase). */\n hooks?: RunHooks;\n supervise?: SuperviseOptions;\n}\n\nexport function processIO(): CliIO {\n return {\n stdout: process.stdout,\n stderr: process.stderr,\n stdin: process.stdin,\n env: process.env,\n cwd: process.cwd(),\n isTTY: process.stdin.isTTY && process.stdout.isTTY,\n };\n}\n\nexport function println(out: Writable, line = ''): void {\n out.write(`${line}\\n`);\n}\n\n/** Read one line from stdin. Resolves `undefined` on EOF. */\nexport function readLine(io: CliIO, prompt: string): Promise<string | undefined> {\n io.stdout.write(prompt);\n return new Promise((resolve) => {\n const rl = createInterface({ input: io.stdin, terminal: false });\n let answered = false;\n rl.once('line', (line) => {\n answered = true;\n rl.close();\n resolve(line);\n });\n rl.once('close', () => {\n if (!answered) resolve(undefined);\n });\n });\n}\n\nexport async function confirm(io: CliIO, question: string): Promise<boolean> {\n const answer = await readLine(io, `${question} [y/N] `);\n return /^\\s*y(es)?\\s*$/i.test(answer ?? '');\n}\n\n/** Read a secret without echoing it when stdin is a TTY; plain line read when piped. */\nexport async function readSecret(io: CliIO, prompt: string): Promise<string | undefined> {\n const stdin = io.stdin as NodeJS.ReadStream;\n if (!io.isTTY || typeof stdin.setRawMode !== 'function') return readLine(io, prompt);\n io.stdout.write(prompt);\n stdin.setRawMode(true);\n stdin.resume();\n return new Promise((resolve) => {\n let value = '';\n const onData = (chunk: Buffer): void => {\n for (const ch of chunk.toString('utf8')) {\n if (ch === '\\r' || ch === '\\n' || ch === '\\u0004') {\n finish(value);\n return;\n }\n if (ch === '\\u0003') {\n finish(undefined);\n return;\n }\n if (ch === '\\u007f') value = value.slice(0, -1);\n else value += ch;\n }\n };\n const finish = (v: string | undefined): void => {\n stdin.off('data', onData);\n stdin.setRawMode(false);\n stdin.pause();\n io.stdout.write('\\n');\n resolve(v);\n };\n stdin.on('data', onData);\n });\n}\n"],"mappings":";;;AAAA,SAAS,uBAAuB;AA4BzB,SAAS,YAAmB;AACjC,SAAO;AAAA,IACL,QAAQ,QAAQ;AAAA,IAChB,QAAQ,QAAQ;AAAA,IAChB,OAAO,QAAQ;AAAA,IACf,KAAK,QAAQ;AAAA,IACb,KAAK,QAAQ,IAAI;AAAA,IACjB,OAAO,QAAQ,MAAM,SAAS,QAAQ,OAAO;AAAA,EAC/C;AACF;AAEO,SAAS,QAAQ,KAAe,OAAO,IAAU;AACtD,MAAI,MAAM,GAAG,IAAI;AAAA,CAAI;AACvB;AAGO,SAAS,SAAS,IAAW,QAA6C;AAC/E,KAAG,OAAO,MAAM,MAAM;AACtB,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,UAAM,KAAK,gBAAgB,EAAE,OAAO,GAAG,OAAO,UAAU,MAAM,CAAC;AAC/D,QAAI,WAAW;AACf,OAAG,KAAK,QAAQ,CAAC,SAAS;AACxB,iBAAW;AACX,SAAG,MAAM;AACT,cAAQ,IAAI;AAAA,IACd,CAAC;AACD,OAAG,KAAK,SAAS,MAAM;AACrB,UAAI,CAAC,SAAU,SAAQ,MAAS;AAAA,IAClC,CAAC;AAAA,EACH,CAAC;AACH;AAEA,eAAsB,QAAQ,IAAW,UAAoC;AAC3E,QAAM,SAAS,MAAM,SAAS,IAAI,GAAG,QAAQ,SAAS;AACtD,SAAO,kBAAkB,KAAK,UAAU,EAAE;AAC5C;AAGA,eAAsB,WAAW,IAAW,QAA6C;AACvF,QAAM,QAAQ,GAAG;AACjB,MAAI,CAAC,GAAG,SAAS,OAAO,MAAM,eAAe,WAAY,QAAO,SAAS,IAAI,MAAM;AACnF,KAAG,OAAO,MAAM,MAAM;AACtB,QAAM,WAAW,IAAI;AACrB,QAAM,OAAO;AACb,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,QAAI,QAAQ;AACZ,UAAM,SAAS,CAAC,UAAwB;AACtC,iBAAW,MAAM,MAAM,SAAS,MAAM,GAAG;AACvC,YAAI,OAAO,QAAQ,OAAO,QAAQ,OAAO,KAAU;AACjD,iBAAO,KAAK;AACZ;AAAA,QACF;AACA,YAAI,OAAO,KAAU;AACnB,iBAAO,MAAS;AAChB;AAAA,QACF;AACA,YAAI,OAAO,OAAU,SAAQ,MAAM,MAAM,GAAG,EAAE;AAAA,YACzC,UAAS;AAAA,MAChB;AAAA,IACF;AACA,UAAM,SAAS,CAAC,MAAgC;AAC9C,YAAM,IAAI,QAAQ,MAAM;AACxB,YAAM,WAAW,KAAK;AACtB,YAAM,MAAM;AACZ,SAAG,OAAO,MAAM,IAAI;AACpB,cAAQ,CAAC;AAAA,IACX;AACA,UAAM,GAAG,QAAQ,MAAM;AAAA,EACzB,CAAC;AACH;","names":[]}
@@ -0,0 +1,87 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/errors.ts
4
+ var OmnexxError = class extends Error {
5
+ code;
6
+ hint;
7
+ constructor(code, message, hint, options) {
8
+ super(message, options);
9
+ this.name = new.target.name;
10
+ this.code = code;
11
+ this.hint = hint;
12
+ }
13
+ /** One line, suitable for a terminal: `error[code]: message (hint)`. */
14
+ oneLine() {
15
+ return `error[${this.code}]: ${this.message}${this.hint ? ` (${this.hint})` : ""}`;
16
+ }
17
+ };
18
+ var ConfigError = class extends OmnexxError {
19
+ constructor(message, hint) {
20
+ super("config", message, hint);
21
+ }
22
+ };
23
+ var NotImplementedError = class extends OmnexxError {
24
+ constructor(feature, milestone) {
25
+ super(
26
+ "not-implemented",
27
+ `${feature} is not implemented in this version (planned for ${milestone})`,
28
+ 'see README "What does not work yet"'
29
+ );
30
+ }
31
+ };
32
+ var PolicyError = class extends OmnexxError {
33
+ constructor(message, hint) {
34
+ super("policy", message, hint);
35
+ }
36
+ };
37
+ var GitError = class extends OmnexxError {
38
+ constructor(message, hint, options) {
39
+ super("git", message, hint, options);
40
+ }
41
+ };
42
+ var ProviderError = class extends OmnexxError {
43
+ retryable;
44
+ status;
45
+ /** The provider's content filter refused this request; another model may take it. */
46
+ contentFilter;
47
+ constructor(message, opts) {
48
+ super("provider", message, opts.hint, { cause: opts.cause });
49
+ this.retryable = opts.retryable;
50
+ this.status = opts.status;
51
+ this.contentFilter = opts.contentFilter ?? false;
52
+ }
53
+ };
54
+ var LockError = class extends OmnexxError {
55
+ constructor(message, hint) {
56
+ super("lock", message, hint);
57
+ }
58
+ };
59
+ var StateError = class extends OmnexxError {
60
+ constructor(message, hint) {
61
+ super("state", message, hint);
62
+ }
63
+ };
64
+ var UsageError = class extends OmnexxError {
65
+ constructor(message, hint) {
66
+ super("usage", message, hint);
67
+ }
68
+ };
69
+ function describeError(err) {
70
+ if (err instanceof OmnexxError) return err.oneLine();
71
+ if (err instanceof Error) return `error: ${err.message}`;
72
+ return `error: ${String(err)}`;
73
+ }
74
+
75
+ export {
76
+ OmnexxError,
77
+ ConfigError,
78
+ NotImplementedError,
79
+ PolicyError,
80
+ GitError,
81
+ ProviderError,
82
+ LockError,
83
+ StateError,
84
+ UsageError,
85
+ describeError
86
+ };
87
+ //# sourceMappingURL=chunk-7PNGHZYH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/errors.ts"],"sourcesContent":["/**\n * Every error Omnexx raises on purpose is an OmnexxError: a stable `code` for scripts and tests,\n * a message that says what went wrong, and a `hint` that says what to do about it.\n */\nexport class OmnexxError extends Error {\n readonly code: string;\n readonly hint: string | undefined;\n\n constructor(code: string, message: string, hint?: string, options?: { cause?: unknown }) {\n super(message, options);\n this.name = new.target.name;\n this.code = code;\n this.hint = hint;\n }\n\n /** One line, suitable for a terminal: `error[code]: message (hint)`. */\n oneLine(): string {\n return `error[${this.code}]: ${this.message}${this.hint ? ` (${this.hint})` : ''}`;\n }\n}\n\nexport class ConfigError extends OmnexxError {\n constructor(message: string, hint?: string) {\n super('config', message, hint);\n }\n}\n\nexport class NotImplementedError extends OmnexxError {\n constructor(feature: string, milestone: string) {\n super(\n 'not-implemented',\n `${feature} is not implemented in this version (planned for ${milestone})`,\n 'see README \"What does not work yet\"',\n );\n }\n}\n\nexport class PolicyError extends OmnexxError {\n constructor(message: string, hint?: string) {\n super('policy', message, hint);\n }\n}\n\nexport class GitError extends OmnexxError {\n constructor(message: string, hint?: string, options?: { cause?: unknown }) {\n super('git', message, hint, options);\n }\n}\n\nexport class ProviderError extends OmnexxError {\n readonly retryable: boolean;\n readonly status: number | undefined;\n /** The provider's content filter refused this request; another model may take it. */\n readonly contentFilter: boolean;\n\n constructor(\n message: string,\n opts: {\n retryable: boolean;\n status?: number;\n hint?: string;\n cause?: unknown;\n contentFilter?: boolean;\n },\n ) {\n super('provider', message, opts.hint, { cause: opts.cause });\n this.retryable = opts.retryable;\n this.status = opts.status;\n this.contentFilter = opts.contentFilter ?? false;\n }\n}\n\nexport class LockError extends OmnexxError {\n constructor(message: string, hint?: string) {\n super('lock', message, hint);\n }\n}\n\nexport class StateError extends OmnexxError {\n constructor(message: string, hint?: string) {\n super('state', message, hint);\n }\n}\n\nexport class UsageError extends OmnexxError {\n constructor(message: string, hint?: string) {\n super('usage', message, hint);\n }\n}\n\n/** Render any thrown value as a single line without leaking stack traces to the user. */\nexport function describeError(err: unknown): string {\n if (err instanceof OmnexxError) return err.oneLine();\n if (err instanceof Error) return `error: ${err.message}`;\n return `error: ${String(err)}`;\n}\n"],"mappings":";;;AAIO,IAAM,cAAN,cAA0B,MAAM;AAAA,EAC5B;AAAA,EACA;AAAA,EAET,YAAY,MAAc,SAAiB,MAAe,SAA+B;AACvF,UAAM,SAAS,OAAO;AACtB,SAAK,OAAO,WAAW;AACvB,SAAK,OAAO;AACZ,SAAK,OAAO;AAAA,EACd;AAAA;AAAA,EAGA,UAAkB;AAChB,WAAO,SAAS,KAAK,IAAI,MAAM,KAAK,OAAO,GAAG,KAAK,OAAO,KAAK,KAAK,IAAI,MAAM,EAAE;AAAA,EAClF;AACF;AAEO,IAAM,cAAN,cAA0B,YAAY;AAAA,EAC3C,YAAY,SAAiB,MAAe;AAC1C,UAAM,UAAU,SAAS,IAAI;AAAA,EAC/B;AACF;AAEO,IAAM,sBAAN,cAAkC,YAAY;AAAA,EACnD,YAAY,SAAiB,WAAmB;AAC9C;AAAA,MACE;AAAA,MACA,GAAG,OAAO,oDAAoD,SAAS;AAAA,MACvE;AAAA,IACF;AAAA,EACF;AACF;AAEO,IAAM,cAAN,cAA0B,YAAY;AAAA,EAC3C,YAAY,SAAiB,MAAe;AAC1C,UAAM,UAAU,SAAS,IAAI;AAAA,EAC/B;AACF;AAEO,IAAM,WAAN,cAAuB,YAAY;AAAA,EACxC,YAAY,SAAiB,MAAe,SAA+B;AACzE,UAAM,OAAO,SAAS,MAAM,OAAO;AAAA,EACrC;AACF;AAEO,IAAM,gBAAN,cAA4B,YAAY;AAAA,EACpC;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EAET,YACE,SACA,MAOA;AACA,UAAM,YAAY,SAAS,KAAK,MAAM,EAAE,OAAO,KAAK,MAAM,CAAC;AAC3D,SAAK,YAAY,KAAK;AACtB,SAAK,SAAS,KAAK;AACnB,SAAK,gBAAgB,KAAK,iBAAiB;AAAA,EAC7C;AACF;AAEO,IAAM,YAAN,cAAwB,YAAY;AAAA,EACzC,YAAY,SAAiB,MAAe;AAC1C,UAAM,QAAQ,SAAS,IAAI;AAAA,EAC7B;AACF;AAEO,IAAM,aAAN,cAAyB,YAAY;AAAA,EAC1C,YAAY,SAAiB,MAAe;AAC1C,UAAM,SAAS,SAAS,IAAI;AAAA,EAC9B;AACF;AAEO,IAAM,aAAN,cAAyB,YAAY;AAAA,EAC1C,YAAY,SAAiB,MAAe;AAC1C,UAAM,SAAS,SAAS,IAAI;AAAA,EAC9B;AACF;AAGO,SAAS,cAAc,KAAsB;AAClD,MAAI,eAAe,YAAa,QAAO,IAAI,QAAQ;AACnD,MAAI,eAAe,MAAO,QAAO,UAAU,IAAI,OAAO;AACtD,SAAO,UAAU,OAAO,GAAG,CAAC;AAC9B;","names":[]}
@@ -2,16 +2,18 @@
2
2
  import {
3
3
  PROVIDER_TEMPLATES,
4
4
  appendEndpointBlock
5
- } from "./chunk-CLAS22GZ.js";
5
+ } from "./chunk-5T4EFIY2.js";
6
6
  import {
7
- UsageError,
8
7
  discoverModels,
9
8
  findProviderKey,
10
9
  loadConfig,
11
10
  resolvePaths,
12
11
  storeKey,
13
12
  userConfigFile
14
- } from "./chunk-Y74QSMFT.js";
13
+ } from "./chunk-S3TUDM5B.js";
14
+ import {
15
+ UsageError
16
+ } from "./chunk-7PNGHZYH.js";
15
17
 
16
18
  // src/cli/connect.ts
17
19
  var KEY_PREFIXES = [
@@ -177,4 +179,4 @@ export {
177
179
  envKeys,
178
180
  connectFromEnv
179
181
  };
180
- //# sourceMappingURL=chunk-IJPR52MO.js.map
182
+ //# sourceMappingURL=chunk-AOIUX7TJ.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli/connect.ts"],"sourcesContent":["import { storeKey, findProviderKey } from '../auth/keys.js';\nimport { loadConfig } from '../config/load.js';\nimport { resolvePaths, userConfigFile } from '../core/paths.js';\nimport { UsageError } from '../errors.js';\nimport { discoverModels } from '../providers/discovery.js';\nimport {\n appendEndpointBlock,\n PROVIDER_TEMPLATES,\n type ProviderTemplate,\n} from './commands/providers.js';\nimport type { CliIO } from './io.js';\n\n/** Key prefixes that name their provider, from the catalog; longest first so sk-or- beats sk-. */\nconst KEY_PREFIXES: readonly (readonly [string, string])[] = (\n [\n ['sk-ant-', 'anthropic'],\n ...Object.entries(PROVIDER_TEMPLATES).flatMap(([name, t]): [string, string][] =>\n t.keyPrefix ? [[t.keyPrefix, name]] : [],\n ),\n ] as [string, string][]\n).sort((a, b) => b[0].length - a[0].length);\n\n/** The provider a pasted key belongs to, or undefined when it doesn't look like a key. */\nexport function providerForKey(text: string): string | undefined {\n const t = text.trim();\n if (/\\s/.test(t) || t.length < 20) return undefined;\n return KEY_PREFIXES.find(([p]) => t.startsWith(p))?.[1];\n}\n\n/** A token long and random enough to be a secret: 24+ chars mixing letters and digits. */\nconst SECRETISH = /^[A-Za-z0-9][A-Za-z0-9_.-]{23,}$/;\n\nexport interface FoundKey {\n key: string;\n /** Undefined when the key has no telltale prefix and the text names no provider. */\n provider: string | undefined;\n}\n\n/**\n * An API key inside a message (\"here's my mistral key abc123…\"): a token with a known prefix, or\n * a secret-looking token next to a provider name the catalog knows. Detection is local; the key is\n * never sent to a model.\n */\nexport function findKeyInText(text: string): FoundKey | undefined {\n const tokens = text.split(/[\\s\"'`,;()<>]+/).map((t) => t.replace(/[.:]+$/, ''));\n for (const t of tokens) {\n const provider = providerForKey(t);\n if (provider) return { key: t, provider };\n }\n const key = tokens.find(\n (t) => SECRETISH.test(t) && /\\d/.test(t) && /[A-Za-z]/.test(t) && !/^https?/i.test(t),\n );\n if (!key) return undefined;\n const words = text.toLowerCase();\n const named = Object.entries(PROVIDER_TEMPLATES).find(\n ([name, t]) =>\n name !== 'custom' &&\n !t.local &&\n (new RegExp(`\\\\b${name}\\\\b`).test(words) ||\n (t.label !== undefined && words.includes(t.label.toLowerCase()))),\n );\n if (named) return { key, provider: named[0] };\n return /\\b(api[ _-]?key|key|token|secret)\\b/.test(words)\n ? { key, provider: undefined }\n : undefined;\n}\n\nexport function looksLikeKey(text: string): boolean {\n return providerForKey(text) !== undefined;\n}\n\n/** A name for an endpoint URL: a matching template, else the host's distinctive label. */\nexport function nameForUrl(url: string): string {\n const u = new URL(url);\n for (const [name, t] of Object.entries(PROVIDER_TEMPLATES)) {\n if (name === 'custom') continue;\n const tu = new URL(t.baseUrl);\n if (tu.host === u.host) return name;\n }\n if (u.hostname === 'localhost' || u.hostname === '127.0.0.1') return 'local';\n const labels = u.hostname.split('.').filter((l) => !['api', 'www', 'inference'].includes(l));\n const label = labels.length > 1 ? labels[labels.length - 2] : labels[0];\n return (label ?? 'custom').toLowerCase().replace(/[^a-z0-9_-]/g, '-');\n}\n\nexport interface ConnectResult {\n name: string;\n added: boolean;\n keyStored: boolean;\n models: string[];\n /** A ready-to-use model ref, e.g. \"openrouter:deepseek/deepseek-v4\". */\n suggested: string | undefined;\n notes: string[];\n}\n\n/**\n * One step from nothing to a usable provider. `target` is a provider name (\"openrouter\"), a base\n * URL (\"http://localhost:11434/v1\"), or a pasted API key. The key goes to the 0600 credentials\n * file, the endpoint to user config, and the endpoint's models are listed to prove it works.\n */\nexport async function connect(\n io: CliIO,\n target: string,\n key?: string,\n opts: { name?: string } = {},\n): Promise<ConnectResult> {\n let t = target.trim();\n let k = key?.trim() ? key.trim() : undefined;\n if (!t) throw new UsageError('nothing to connect', 'try `connect openrouter <key>` or a URL');\n const keyProvider = providerForKey(t);\n if (keyProvider && !k) {\n k = t;\n t = keyProvider;\n }\n let name: string;\n let template: ProviderTemplate | undefined;\n if (/^https?:\\/\\//i.test(t)) {\n name = opts.name ?? nameForUrl(t);\n const local = /^https?:\\/\\/(localhost|127\\.0\\.0\\.1)/i.test(t);\n template = { baseUrl: t, keyEnv: undefined, free: local && !k, kind: 'openai' };\n } else {\n name = (opts.name ?? t).toLowerCase();\n template = PROVIDER_TEMPLATES[name];\n }\n if (!/^[a-z][a-z0-9_-]*$/.test(name))\n throw new UsageError(`bad provider name \"${name}\"`, 'use lowercase letters, digits, _ or -');\n\n const paths = resolvePaths(io.env);\n const notes: string[] = [];\n let keyStored = false;\n if (k) {\n await storeKey(paths, name, k);\n keyStored = true;\n }\n if (name === 'anthropic') {\n const found = await findProviderKey(paths, io.env, 'anthropic');\n if (!found) notes.push('no Anthropic key yet: paste one (sk-ant-…)');\n return {\n name,\n added: false,\n keyStored,\n models: ['opus', 'sonnet', 'haiku'],\n suggested: found ? 'anthropic:sonnet' : undefined,\n notes,\n };\n }\n\n const { config } = await loadConfig({ cwd: io.cwd, env: io.env });\n const existing = config.providers.endpoints[name];\n let added = false;\n let baseUrl = existing?.base_url;\n if (!existing) {\n if (!template)\n throw new UsageError(\n `unknown provider \"${name}\"`,\n `known: ${Object.keys(PROVIDER_TEMPLATES).join(', ')}; or connect a base URL`,\n );\n // Keys live in the credentials file, so the endpoint doesn't need an env var.\n await appendEndpointBlock(userConfigFile(paths), name, { ...template, keyEnv: undefined });\n baseUrl = template.baseUrl;\n added = true;\n }\n const apiKey = (await findProviderKey(paths, io.env, name, existing?.api_key_env))?.key;\n if (!apiKey && !(existing?.free ?? template?.free)) notes.push(`no key for ${name} yet`);\n const local = /localhost|127\\.0\\.0\\.1/.test(baseUrl ?? '');\n const models = baseUrl\n ? (\n await discoverModels(\n { baseUrl, ...(apiKey ? { apiKey } : {}) },\n io.fetch ? { fetch: io.fetch } : {},\n )\n ).map((m) => m.id)\n : [];\n if (!models.length)\n notes.push(\n local\n ? `nothing answered at ${baseUrl}; is the server running?`\n : `couldn't list models at ${baseUrl}; check the key`,\n );\n const first = models[0];\n return {\n name,\n added,\n keyStored,\n models,\n suggested: first ? `${name}:${first}` : undefined,\n notes,\n };\n}\n\nexport function describeConnect(r: ConnectResult): string {\n const lines = [\n `${r.added ? 'added' : 'updated'} ${r.name}${r.keyStored ? ' (key saved, 0600)' : ''}`,\n ];\n if (r.models.length) {\n const shown = r.models.slice(0, 8).join(', ');\n lines.push(\n `${r.models.length} model${r.models.length === 1 ? '' : 's'}: ${shown}${r.models.length > 8 ? ', …' : ''}`,\n );\n }\n for (const n of r.notes) lines.push(n);\n if (r.suggested) lines.push(`chat with it: /model ${r.suggested}`);\n return lines.join('\\n');\n}\n\nexport interface EnvKey {\n name: string;\n label: string;\n keyEnv: string;\n}\n\n/**\n * Providers whose standard key variable is already set in the environment but that aren't\n * configured yet: the fastest way to a working model on a machine that already has keys.\n */\nexport async function envKeys(io: CliIO): Promise<EnvKey[]> {\n const { config } = await loadConfig({ cwd: io.cwd, env: io.env });\n const out: EnvKey[] = [];\n if (io.env.ANTHROPIC_API_KEY?.trim())\n out.push({ name: 'anthropic', label: 'Anthropic', keyEnv: 'ANTHROPIC_API_KEY' });\n for (const [name, t] of Object.entries(PROVIDER_TEMPLATES)) {\n if (!t.keyEnv || config.providers.endpoints[name]) continue;\n if (io.env[t.keyEnv]?.trim()) out.push({ name, label: t.label ?? name, keyEnv: t.keyEnv });\n }\n return out;\n}\n\n/**\n * `/connect env`: add every provider found by envKeys(), pointing each endpoint at its env var\n * (the key is never copied into omnexx's files). Anthropic needs nothing: its key is read from\n * the environment already.\n */\nexport async function connectFromEnv(io: CliIO): Promise<EnvKey[]> {\n const found = await envKeys(io);\n const file = userConfigFile(resolvePaths(io.env));\n // One after another: every block is appended to the same file.\n await found.reduce(async (prev, k) => {\n await prev;\n const t = PROVIDER_TEMPLATES[k.name];\n if (t) await appendEndpointBlock(file, k.name, { ...t, keyEnv: k.keyEnv });\n }, Promise.resolve());\n return found;\n}\n"],"mappings":"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","names":["local"]}
1
+ {"version":3,"sources":["../src/cli/connect.ts"],"sourcesContent":["import { storeKey, findProviderKey } from '../auth/keys.js';\nimport { loadConfig } from '../config/load.js';\nimport { resolvePaths, userConfigFile } from '../core/paths.js';\nimport { UsageError } from '../errors.js';\nimport { discoverModels } from '../providers/discovery.js';\nimport {\n appendEndpointBlock,\n PROVIDER_TEMPLATES,\n type ProviderTemplate,\n} from './commands/providers.js';\nimport type { CliIO } from './io.js';\n\n/** Key prefixes that name their provider, from the catalog; longest first so sk-or- beats sk-. */\nconst KEY_PREFIXES: readonly (readonly [string, string])[] = (\n [\n ['sk-ant-', 'anthropic'],\n ...Object.entries(PROVIDER_TEMPLATES).flatMap(([name, t]): [string, string][] =>\n t.keyPrefix ? [[t.keyPrefix, name]] : [],\n ),\n ] as [string, string][]\n).sort((a, b) => b[0].length - a[0].length);\n\n/** The provider a pasted key belongs to, or undefined when it doesn't look like a key. */\nexport function providerForKey(text: string): string | undefined {\n const t = text.trim();\n if (/\\s/.test(t) || t.length < 20) return undefined;\n return KEY_PREFIXES.find(([p]) => t.startsWith(p))?.[1];\n}\n\n/** A token long and random enough to be a secret: 24+ chars mixing letters and digits. */\nconst SECRETISH = /^[A-Za-z0-9][A-Za-z0-9_.-]{23,}$/;\n\nexport interface FoundKey {\n key: string;\n /** Undefined when the key has no telltale prefix and the text names no provider. */\n provider: string | undefined;\n}\n\n/**\n * An API key inside a message (\"here's my mistral key abc123…\"): a token with a known prefix, or\n * a secret-looking token next to a provider name the catalog knows. Detection is local; the key is\n * never sent to a model.\n */\nexport function findKeyInText(text: string): FoundKey | undefined {\n const tokens = text.split(/[\\s\"'`,;()<>]+/).map((t) => t.replace(/[.:]+$/, ''));\n for (const t of tokens) {\n const provider = providerForKey(t);\n if (provider) return { key: t, provider };\n }\n const key = tokens.find(\n (t) => SECRETISH.test(t) && /\\d/.test(t) && /[A-Za-z]/.test(t) && !/^https?/i.test(t),\n );\n if (!key) return undefined;\n const words = text.toLowerCase();\n const named = Object.entries(PROVIDER_TEMPLATES).find(\n ([name, t]) =>\n name !== 'custom' &&\n !t.local &&\n (new RegExp(`\\\\b${name}\\\\b`).test(words) ||\n (t.label !== undefined && words.includes(t.label.toLowerCase()))),\n );\n if (named) return { key, provider: named[0] };\n return /\\b(api[ _-]?key|key|token|secret)\\b/.test(words)\n ? { key, provider: undefined }\n : undefined;\n}\n\nexport function looksLikeKey(text: string): boolean {\n return providerForKey(text) !== undefined;\n}\n\n/** A name for an endpoint URL: a matching template, else the host's distinctive label. */\nexport function nameForUrl(url: string): string {\n const u = new URL(url);\n for (const [name, t] of Object.entries(PROVIDER_TEMPLATES)) {\n if (name === 'custom') continue;\n const tu = new URL(t.baseUrl);\n if (tu.host === u.host) return name;\n }\n if (u.hostname === 'localhost' || u.hostname === '127.0.0.1') return 'local';\n const labels = u.hostname.split('.').filter((l) => !['api', 'www', 'inference'].includes(l));\n const label = labels.length > 1 ? labels[labels.length - 2] : labels[0];\n return (label ?? 'custom').toLowerCase().replace(/[^a-z0-9_-]/g, '-');\n}\n\nexport interface ConnectResult {\n name: string;\n added: boolean;\n keyStored: boolean;\n models: string[];\n /** A ready-to-use model ref, e.g. \"openrouter:deepseek/deepseek-v4\". */\n suggested: string | undefined;\n notes: string[];\n}\n\n/**\n * One step from nothing to a usable provider. `target` is a provider name (\"openrouter\"), a base\n * URL (\"http://localhost:11434/v1\"), or a pasted API key. The key goes to the 0600 credentials\n * file, the endpoint to user config, and the endpoint's models are listed to prove it works.\n */\nexport async function connect(\n io: CliIO,\n target: string,\n key?: string,\n opts: { name?: string } = {},\n): Promise<ConnectResult> {\n let t = target.trim();\n let k = key?.trim() ? key.trim() : undefined;\n if (!t) throw new UsageError('nothing to connect', 'try `connect openrouter <key>` or a URL');\n const keyProvider = providerForKey(t);\n if (keyProvider && !k) {\n k = t;\n t = keyProvider;\n }\n let name: string;\n let template: ProviderTemplate | undefined;\n if (/^https?:\\/\\//i.test(t)) {\n name = opts.name ?? nameForUrl(t);\n const local = /^https?:\\/\\/(localhost|127\\.0\\.0\\.1)/i.test(t);\n template = { baseUrl: t, keyEnv: undefined, free: local && !k, kind: 'openai' };\n } else {\n name = (opts.name ?? t).toLowerCase();\n template = PROVIDER_TEMPLATES[name];\n }\n if (!/^[a-z][a-z0-9_-]*$/.test(name))\n throw new UsageError(`bad provider name \"${name}\"`, 'use lowercase letters, digits, _ or -');\n\n const paths = resolvePaths(io.env);\n const notes: string[] = [];\n let keyStored = false;\n if (k) {\n await storeKey(paths, name, k);\n keyStored = true;\n }\n if (name === 'anthropic') {\n const found = await findProviderKey(paths, io.env, 'anthropic');\n if (!found) notes.push('no Anthropic key yet: paste one (sk-ant-…)');\n return {\n name,\n added: false,\n keyStored,\n models: ['opus', 'sonnet', 'haiku'],\n suggested: found ? 'anthropic:sonnet' : undefined,\n notes,\n };\n }\n\n const { config } = await loadConfig({ cwd: io.cwd, env: io.env });\n const existing = config.providers.endpoints[name];\n let added = false;\n let baseUrl = existing?.base_url;\n if (!existing) {\n if (!template)\n throw new UsageError(\n `unknown provider \"${name}\"`,\n `known: ${Object.keys(PROVIDER_TEMPLATES).join(', ')}; or connect a base URL`,\n );\n // Keys live in the credentials file, so the endpoint doesn't need an env var.\n await appendEndpointBlock(userConfigFile(paths), name, { ...template, keyEnv: undefined });\n baseUrl = template.baseUrl;\n added = true;\n }\n const apiKey = (await findProviderKey(paths, io.env, name, existing?.api_key_env))?.key;\n if (!apiKey && !(existing?.free ?? template?.free)) notes.push(`no key for ${name} yet`);\n const local = /localhost|127\\.0\\.0\\.1/.test(baseUrl ?? '');\n const models = baseUrl\n ? (\n await discoverModels(\n { baseUrl, ...(apiKey ? { apiKey } : {}) },\n io.fetch ? { fetch: io.fetch } : {},\n )\n ).map((m) => m.id)\n : [];\n if (!models.length)\n notes.push(\n local\n ? `nothing answered at ${baseUrl}; is the server running?`\n : `couldn't list models at ${baseUrl}; check the key`,\n );\n const first = models[0];\n return {\n name,\n added,\n keyStored,\n models,\n suggested: first ? `${name}:${first}` : undefined,\n notes,\n };\n}\n\nexport function describeConnect(r: ConnectResult): string {\n const lines = [\n `${r.added ? 'added' : 'updated'} ${r.name}${r.keyStored ? ' (key saved, 0600)' : ''}`,\n ];\n if (r.models.length) {\n const shown = r.models.slice(0, 8).join(', ');\n lines.push(\n `${r.models.length} model${r.models.length === 1 ? '' : 's'}: ${shown}${r.models.length > 8 ? ', …' : ''}`,\n );\n }\n for (const n of r.notes) lines.push(n);\n if (r.suggested) lines.push(`chat with it: /model ${r.suggested}`);\n return lines.join('\\n');\n}\n\nexport interface EnvKey {\n name: string;\n label: string;\n keyEnv: string;\n}\n\n/**\n * Providers whose standard key variable is already set in the environment but that aren't\n * configured yet: the fastest way to a working model on a machine that already has keys.\n */\nexport async function envKeys(io: CliIO): Promise<EnvKey[]> {\n const { config } = await loadConfig({ cwd: io.cwd, env: io.env });\n const out: EnvKey[] = [];\n if (io.env.ANTHROPIC_API_KEY?.trim())\n out.push({ name: 'anthropic', label: 'Anthropic', keyEnv: 'ANTHROPIC_API_KEY' });\n for (const [name, t] of Object.entries(PROVIDER_TEMPLATES)) {\n if (!t.keyEnv || config.providers.endpoints[name]) continue;\n if (io.env[t.keyEnv]?.trim()) out.push({ name, label: t.label ?? name, keyEnv: t.keyEnv });\n }\n return out;\n}\n\n/**\n * `/connect env`: add every provider found by envKeys(), pointing each endpoint at its env var\n * (the key is never copied into omnexx's files). Anthropic needs nothing: its key is read from\n * the environment already.\n */\nexport async function connectFromEnv(io: CliIO): Promise<EnvKey[]> {\n const found = await envKeys(io);\n const file = userConfigFile(resolvePaths(io.env));\n // One after another: every block is appended to the same file.\n await found.reduce(async (prev, k) => {\n await prev;\n const t = PROVIDER_TEMPLATES[k.name];\n if (t) await appendEndpointBlock(file, k.name, { ...t, keyEnv: k.keyEnv });\n }, Promise.resolve());\n return found;\n}\n"],"mappings":"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","names":["local"]}