claude-connect 0.1.6 → 0.1.7
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 +20 -5
- package/package.json +1 -1
- package/src/data/catalog-store.js +47 -2
- package/src/lib/app-paths.js +110 -0
- package/src/lib/claude-settings.js +9 -1
- package/src/wizard.js +16 -1
package/README.md
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# Claude Connect
|
|
2
2
|
|
|
3
|
-
> Conecta `Claude Code` con `OpenCode Go`, `Zen`, `Kimi`, `DeepSeek`, `Ollama`, `OpenAI`, `OpenRouter` y `Qwen` desde una interfaz de consola clara, rápida y reversible.
|
|
3
|
+
> Conecta `Claude Code` con `OpenCode Go`, `Zen`, `Kimi`, `DeepSeek`, `Ollama`, `OpenAI`, `Inception Labs`, `OpenRouter` y `Qwen` desde una interfaz de consola clara, rápida y reversible.
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/claude-connect)
|
|
6
6
|
[](https://nodejs.org/)
|
|
7
7
|
[](./LICENSE)
|
|
8
|
-
[](https://www.npmjs.com/package/claude-connect)
|
|
8
|
+
[](https://www.npmjs.com/package/claude-connect)
|
|
9
9
|
|
|
10
10
|
## Why Claude Connect
|
|
11
11
|
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
### Highlights
|
|
15
15
|
|
|
16
|
-
- `OpenCode Go`, `Zen`, `Kimi`, `DeepSeek`, `Ollama`, `OpenAI`, `OpenRouter` y `Qwen` listos desde el primer arranque
|
|
16
|
+
- `OpenCode Go`, `Zen`, `Kimi`, `DeepSeek`, `Ollama`, `OpenAI`, `Inception Labs`, `OpenRouter` y `Qwen` listos desde el primer arranque
|
|
17
17
|
- soporte para `Token` y `OAuth` cuando el proveedor lo permite
|
|
18
18
|
- API keys compartidas por proveedor para no repetir el mismo token en cada modelo
|
|
19
19
|
- activación reversible sobre la instalación real de `Claude Code`
|
|
@@ -80,6 +80,7 @@ Al activar:
|
|
|
80
80
|
- `DeepSeek` apunta a `https://api.deepseek.com/anthropic`
|
|
81
81
|
- `Ollama` pide una URL local o remota, valida `/api/tags` y usa el gateway local sobre `.../api/chat`
|
|
82
82
|
- `OpenAI` usa el gateway local sobre `https://api.openai.com/v1/chat/completions`
|
|
83
|
+
- `Inception Labs` usa el gateway local sobre `https://api.inceptionlabs.ai/v1/chat/completions`
|
|
83
84
|
- `OpenRouter` usa `openrouter/free` por gateway sobre `https://openrouter.ai/api/v1`
|
|
84
85
|
- `Qwen` apunta al gateway local `http://127.0.0.1:4310/anthropic`
|
|
85
86
|
|
|
@@ -93,6 +94,7 @@ Al activar:
|
|
|
93
94
|
| `DeepSeek` | `deepseek-chat`, `deepseek-reasoner` | `Token` | Directa |
|
|
94
95
|
| `Ollama` | modelos descubiertos desde tu servidor | `Servidor Ollama` | Gateway local |
|
|
95
96
|
| `OpenAI` | `gpt-5.4`, `gpt-5.4-mini`, `gpt-5.3-codex`, `gpt-5.2-codex`, `gpt-5.2`, `gpt-5.1-codex-max`, `gpt-5.1-codex-mini` | `Token` | Gateway local |
|
|
97
|
+
| `Inception Labs` | `mercury-2` | `Token` | Gateway local |
|
|
96
98
|
| `OpenRouter` | `openrouter/free` | `Token` | Gateway local |
|
|
97
99
|
| `Qwen` | `qwen3-coder-plus` | `OAuth`, `Token` | Gateway local |
|
|
98
100
|
|
|
@@ -118,6 +120,16 @@ Nota sobre `OpenAI`:
|
|
|
118
120
|
- https://platform.openai.com/docs/api-reference/authentication
|
|
119
121
|
- https://developers.openai.com/api/docs/models
|
|
120
122
|
|
|
123
|
+
Nota sobre `Inception Labs`:
|
|
124
|
+
|
|
125
|
+
- esta primera integracion expone solo `mercury-2`, que es el modelo chat-compatible oficial en `v1/chat/completions`
|
|
126
|
+
- `Mercury Edit 2` no se publica todavia en Claude Connect porque usa endpoints `fim/edit` que no encajan con Claude Code en esta arquitectura
|
|
127
|
+
- autenticacion soportada: `API key`
|
|
128
|
+
- referencias oficiales:
|
|
129
|
+
- https://docs.inceptionlabs.ai/get-started/get-started
|
|
130
|
+
- https://docs.inceptionlabs.ai/get-started/authentication
|
|
131
|
+
- https://docs.inceptionlabs.ai/get-started/models
|
|
132
|
+
|
|
121
133
|
Nota sobre `Ollama`:
|
|
122
134
|
|
|
123
135
|
- la URL del servidor se define al crear la conexión
|
|
@@ -151,14 +163,16 @@ Ahí viven:
|
|
|
151
163
|
El catálogo SQLite local se genera automáticamente en:
|
|
152
164
|
|
|
153
165
|
```text
|
|
154
|
-
storage/claude-connect.sqlite
|
|
166
|
+
Linux: ~/.claude-connect/storage/claude-connect.sqlite
|
|
167
|
+
Windows: %APPDATA%\claude-connect\storage\claude-connect.sqlite
|
|
155
168
|
```
|
|
156
169
|
|
|
157
170
|
Importante:
|
|
158
171
|
|
|
159
172
|
- esa base ya no se versiona en git
|
|
160
173
|
- el catálogo se siembra desde `src/data/catalog-store.js`
|
|
161
|
-
-
|
|
174
|
+
- ya no se crea en la carpeta donde ejecutas el comando
|
|
175
|
+
- esto evita conflictos molestos al hacer `git pull` y carpetas `storage/` accidentales en proyectos ajenos
|
|
162
176
|
|
|
163
177
|
## Claude Code Switching
|
|
164
178
|
|
|
@@ -175,6 +189,7 @@ Eso permite:
|
|
|
175
189
|
- activar otro proveedor sin tocar archivos manualmente
|
|
176
190
|
- evitar el `Auth conflict` entre sesión `claude.ai` y `API key`
|
|
177
191
|
- volver a tu estado original con `Revertir Claude`
|
|
192
|
+
- bloquear la activación si `Claude Code` no está realmente instalado todavía
|
|
178
193
|
|
|
179
194
|
## Qwen OAuth
|
|
180
195
|
|
package/package.json
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { DatabaseSync } from 'node:sqlite';
|
|
4
|
+
import { resolveClaudeConnectHomeSync } from '../lib/app-paths.js';
|
|
4
5
|
|
|
5
|
-
export
|
|
6
|
+
export function getDefaultCatalogDbPath(options = {}) {
|
|
7
|
+
const pathModule = options.platform === 'win32' ? path.win32 : path.posix;
|
|
8
|
+
return pathModule.join(resolveClaudeConnectHomeSync(options), 'storage', 'claude-connect.sqlite');
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const defaultCatalogDbPath = getDefaultCatalogDbPath();
|
|
6
12
|
|
|
7
13
|
const schemaSql = `
|
|
8
14
|
PRAGMA foreign_keys = ON;
|
|
@@ -673,6 +679,45 @@ const seedProviders = [
|
|
|
673
679
|
}
|
|
674
680
|
]
|
|
675
681
|
},
|
|
682
|
+
{
|
|
683
|
+
id: 'inception',
|
|
684
|
+
name: 'Inception Labs',
|
|
685
|
+
vendor: 'Inception Labs',
|
|
686
|
+
description: 'Inception Platform con Mercury 2 sobre un endpoint OpenAI-compatible. Claude Code se conecta a traves del gateway local para mantener compatibilidad Anthropic y herramientas.',
|
|
687
|
+
docsUrl: 'https://docs.inceptionlabs.ai/get-started/get-started',
|
|
688
|
+
docsVerifiedAt: '2026-04-03',
|
|
689
|
+
baseUrl: 'https://api.inceptionlabs.ai/v1',
|
|
690
|
+
defaultModelId: 'mercury-2',
|
|
691
|
+
defaultAuthMethodId: 'token',
|
|
692
|
+
defaultApiKeyEnvVar: 'INCEPTION_API_KEY',
|
|
693
|
+
models: [
|
|
694
|
+
{
|
|
695
|
+
id: 'mercury-2',
|
|
696
|
+
name: 'Mercury 2',
|
|
697
|
+
category: 'OpenAI Chat Completions',
|
|
698
|
+
contextWindow: '128K',
|
|
699
|
+
summary: 'Modelo generalista y de razonamiento de Inception Labs expuesto por v1/chat/completions.',
|
|
700
|
+
upstreamModelId: 'mercury-2',
|
|
701
|
+
transportMode: 'gateway',
|
|
702
|
+
apiStyle: 'openai-chat',
|
|
703
|
+
apiBaseUrl: 'https://api.inceptionlabs.ai/v1',
|
|
704
|
+
apiPath: '/chat/completions',
|
|
705
|
+
authEnvMode: 'auth_token',
|
|
706
|
+
sortOrder: 1,
|
|
707
|
+
isDefault: 1
|
|
708
|
+
}
|
|
709
|
+
],
|
|
710
|
+
authMethods: [
|
|
711
|
+
{
|
|
712
|
+
id: 'token',
|
|
713
|
+
name: 'Token',
|
|
714
|
+
description: 'Conexion por API key de Inception Labs.',
|
|
715
|
+
credentialKind: 'env_var',
|
|
716
|
+
sortOrder: 1,
|
|
717
|
+
isDefault: 1
|
|
718
|
+
}
|
|
719
|
+
]
|
|
720
|
+
},
|
|
676
721
|
{
|
|
677
722
|
id: 'openrouter',
|
|
678
723
|
name: 'OpenRouter',
|
|
@@ -1021,7 +1066,7 @@ function mapOAuthRow(row) {
|
|
|
1021
1066
|
};
|
|
1022
1067
|
}
|
|
1023
1068
|
|
|
1024
|
-
export function createCatalogStore({ filename =
|
|
1069
|
+
export function createCatalogStore({ filename = getDefaultCatalogDbPath() } = {}) {
|
|
1025
1070
|
if (filename !== ':memory:') {
|
|
1026
1071
|
fs.mkdirSync(path.dirname(filename), { recursive: true });
|
|
1027
1072
|
}
|
package/src/lib/app-paths.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import fs from 'node:fs/promises';
|
|
2
|
+
import fsSync from 'node:fs';
|
|
2
3
|
import os from 'node:os';
|
|
3
4
|
import path from 'node:path';
|
|
4
5
|
import process from 'node:process';
|
|
@@ -48,6 +49,14 @@ async function pathExists(targetPath) {
|
|
|
48
49
|
}
|
|
49
50
|
}
|
|
50
51
|
|
|
52
|
+
function pathExistsSync(targetPath) {
|
|
53
|
+
try {
|
|
54
|
+
return fsSync.existsSync(targetPath);
|
|
55
|
+
} catch (_error) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
51
60
|
function defaultHomedir(env, fallbackHomedir) {
|
|
52
61
|
const pathModule = getPathModule(process.platform);
|
|
53
62
|
|
|
@@ -179,6 +188,18 @@ export async function resolveClaudeConnectHome(options = {}) {
|
|
|
179
188
|
return candidates[0];
|
|
180
189
|
}
|
|
181
190
|
|
|
191
|
+
export function resolveClaudeConnectHomeSync(options = {}) {
|
|
192
|
+
const candidates = buildClaudeConnectHomeCandidates(options);
|
|
193
|
+
|
|
194
|
+
for (const candidate of candidates) {
|
|
195
|
+
if (pathExistsSync(candidate)) {
|
|
196
|
+
return candidate;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return candidates[0];
|
|
201
|
+
}
|
|
202
|
+
|
|
182
203
|
export async function resolveClaudeSettingsPath(options = {}) {
|
|
183
204
|
if (typeof options.env?.CLAUDE_SETTINGS_PATH === 'string' && options.env.CLAUDE_SETTINGS_PATH.trim().length > 0) {
|
|
184
205
|
return buildClaudeSettingsPathCandidates(options)[0];
|
|
@@ -244,6 +265,8 @@ export async function resolveClaudeConnectPaths(options = {}) {
|
|
|
244
265
|
|
|
245
266
|
return {
|
|
246
267
|
claudeConnectHome,
|
|
268
|
+
storageDir: path.join(claudeConnectHome, 'storage'),
|
|
269
|
+
catalogDbPath: path.join(claudeConnectHome, 'storage', 'claude-connect.sqlite'),
|
|
247
270
|
profilesDir: path.join(claudeConnectHome, 'profiles'),
|
|
248
271
|
tokensDir: path.join(claudeConnectHome, 'tokens'),
|
|
249
272
|
secretsDir: path.join(claudeConnectHome, 'secrets'),
|
|
@@ -269,3 +292,90 @@ export async function resolveClaudePaths(options = {}) {
|
|
|
269
292
|
...claudeConnectPaths
|
|
270
293
|
};
|
|
271
294
|
}
|
|
295
|
+
|
|
296
|
+
function buildExecutableNames(command, platform = process.platform, env = process.env) {
|
|
297
|
+
if (platform !== 'win32') {
|
|
298
|
+
return [command];
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
const pathext = typeof env.PATHEXT === 'string' && env.PATHEXT.length > 0
|
|
302
|
+
? env.PATHEXT.split(';').filter(Boolean)
|
|
303
|
+
: ['.EXE', '.CMD', '.BAT', '.COM'];
|
|
304
|
+
const hasExt = path.win32.extname(command).length > 0;
|
|
305
|
+
|
|
306
|
+
if (hasExt) {
|
|
307
|
+
return [command];
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
return pathext.map((ext) => `${command}${ext.toLowerCase()}`);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
export async function findExecutableOnPath(command, {
|
|
314
|
+
platform = process.platform,
|
|
315
|
+
env = process.env
|
|
316
|
+
} = {}) {
|
|
317
|
+
const pathModule = getPathModule(platform);
|
|
318
|
+
const pathValue = typeof env.PATH === 'string' ? env.PATH : '';
|
|
319
|
+
const pathEntries = pathValue.split(path.delimiter).filter(Boolean);
|
|
320
|
+
const commandNames = buildExecutableNames(command, platform, env);
|
|
321
|
+
|
|
322
|
+
for (const directory of pathEntries) {
|
|
323
|
+
for (const commandName of commandNames) {
|
|
324
|
+
const candidate = pathModule.join(directory, commandName);
|
|
325
|
+
|
|
326
|
+
if (await pathExists(candidate)) {
|
|
327
|
+
return candidate;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
return null;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
export async function detectClaudeCodeInstallation(options = {}) {
|
|
336
|
+
const settingsCandidates = buildClaudeSettingsPathCandidates(options);
|
|
337
|
+
const accountCandidates = buildClaudeAccountPathCandidates(options);
|
|
338
|
+
const credentialsCandidates = buildClaudeCredentialsPathCandidates(options);
|
|
339
|
+
const executablePath = await findExecutableOnPath('claude', options);
|
|
340
|
+
|
|
341
|
+
const [existingSettingsPath, existingAccountPath, existingCredentialsPath] = await Promise.all([
|
|
342
|
+
(async () => {
|
|
343
|
+
for (const candidate of settingsCandidates) {
|
|
344
|
+
if (await pathExists(candidate)) {
|
|
345
|
+
return candidate;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
return null;
|
|
350
|
+
})(),
|
|
351
|
+
(async () => {
|
|
352
|
+
for (const candidate of accountCandidates) {
|
|
353
|
+
if (await pathExists(candidate)) {
|
|
354
|
+
return candidate;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
return null;
|
|
359
|
+
})(),
|
|
360
|
+
(async () => {
|
|
361
|
+
for (const candidate of credentialsCandidates) {
|
|
362
|
+
if (await pathExists(candidate)) {
|
|
363
|
+
return candidate;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
return null;
|
|
368
|
+
})()
|
|
369
|
+
]);
|
|
370
|
+
|
|
371
|
+
return {
|
|
372
|
+
isInstalled: Boolean(executablePath || existingSettingsPath || existingAccountPath || existingCredentialsPath),
|
|
373
|
+
executablePath,
|
|
374
|
+
existingSettingsPath,
|
|
375
|
+
existingAccountPath,
|
|
376
|
+
existingCredentialsPath,
|
|
377
|
+
settingsCandidates,
|
|
378
|
+
accountCandidates,
|
|
379
|
+
credentialsCandidates
|
|
380
|
+
};
|
|
381
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import fs from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import { resolveClaudePaths } from './app-paths.js';
|
|
3
|
+
import { detectClaudeCodeInstallation, resolveClaudePaths } from './app-paths.js';
|
|
4
4
|
import { readManagedProviderTokenSecret, readManagedTokenSecret } from './secrets.js';
|
|
5
5
|
|
|
6
6
|
function isObject(value) {
|
|
@@ -240,6 +240,14 @@ export function buildClaudeSettingsForProfile({
|
|
|
240
240
|
}
|
|
241
241
|
|
|
242
242
|
export async function activateClaudeProfile({ profile, gatewayBaseUrl = 'http://127.0.0.1:4310/anthropic' }) {
|
|
243
|
+
const installation = await detectClaudeCodeInstallation();
|
|
244
|
+
|
|
245
|
+
if (!installation.isInstalled) {
|
|
246
|
+
throw new Error(
|
|
247
|
+
'Claude Code no parece estar instalado en esta maquina. Instala o ejecuta Claude Code primero y luego vuelve a activar la conexion.'
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
|
|
243
251
|
const {
|
|
244
252
|
claudeSettingsPath,
|
|
245
253
|
claudeAccountPath,
|
package/src/wizard.js
CHANGED
|
@@ -433,7 +433,22 @@ async function activateClaudeFromSavedProfile() {
|
|
|
433
433
|
return profile;
|
|
434
434
|
}
|
|
435
435
|
|
|
436
|
-
|
|
436
|
+
let result;
|
|
437
|
+
|
|
438
|
+
try {
|
|
439
|
+
result = await activateClaudeProfile({ profile });
|
|
440
|
+
} catch (error) {
|
|
441
|
+
renderInfoScreen({
|
|
442
|
+
title: 'No se pudo activar Claude',
|
|
443
|
+
subtitle: 'Claude Connect no pudo aplicar la conexion en Claude Code.',
|
|
444
|
+
lines: [
|
|
445
|
+
colorize(error instanceof Error ? error.message : String(error), colors.warning)
|
|
446
|
+
],
|
|
447
|
+
footer: 'Presiona una tecla para volver'
|
|
448
|
+
});
|
|
449
|
+
return await waitForAnyKey();
|
|
450
|
+
}
|
|
451
|
+
|
|
437
452
|
const gateway = result.connectionMode === 'gateway'
|
|
438
453
|
? await restartGatewayInBackground()
|
|
439
454
|
: await stopGateway();
|