@iaforged/context-code 1.1.5 → 1.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.
|
@@ -34,7 +34,12 @@ const LANGUAGE_NAME_TO_CODE = {
|
|
|
34
34
|
export function normalizeLanguageForSTT(language) {
|
|
35
35
|
if (!language)
|
|
36
36
|
return { code: DEFAULT_STT_LANGUAGE };
|
|
37
|
-
|
|
37
|
+
// Normaliza eliminando tildes/diacriticos para que "Español" -> "espanol".
|
|
38
|
+
const lower = language
|
|
39
|
+
.toLowerCase()
|
|
40
|
+
.normalize('NFD')
|
|
41
|
+
.replace(/[\u0300-\u036f]/g, '')
|
|
42
|
+
.trim();
|
|
38
43
|
if (!lower)
|
|
39
44
|
return { code: DEFAULT_STT_LANGUAGE };
|
|
40
45
|
if (lower === 'auto')
|
|
@@ -34,7 +34,11 @@ function getConfiguredExecutable() {
|
|
|
34
34
|
if (stored?.trim()) {
|
|
35
35
|
return stored.trim();
|
|
36
36
|
}
|
|
37
|
-
|
|
37
|
+
// Fallback al nombre por defecto en PATH segun plataforma. En macOS/Linux
|
|
38
|
+
// probamos primero `whisper-cli` (releases) y luego `whisper-cpp` (Homebrew).
|
|
39
|
+
if (process.platform === 'win32')
|
|
40
|
+
return 'whisper-cli.exe';
|
|
41
|
+
return 'whisper-cli';
|
|
38
42
|
}
|
|
39
43
|
function getConfiguredModel() {
|
|
40
44
|
const model = process.env.CONTEXT_CODE_DICTATION_MODEL ??
|
|
@@ -207,7 +211,7 @@ async function findFileRecursive(rootDir, predicate) {
|
|
|
207
211
|
async function findInstalledExecutable(installDir) {
|
|
208
212
|
const candidateNames = process.platform === 'win32'
|
|
209
213
|
? ['whisper-cli.exe', 'main.exe']
|
|
210
|
-
: ['whisper-cli', 'main'];
|
|
214
|
+
: ['whisper-cli', 'whisper-cpp', 'main'];
|
|
211
215
|
return findFileRecursive(installDir, path => candidateNames.some(name => path.toLowerCase().endsWith(name.toLowerCase())));
|
|
212
216
|
}
|
|
213
217
|
function persistInstalledDictationConfig(config) {
|
|
@@ -280,7 +284,146 @@ export async function getLocalDictationStatus() {
|
|
|
280
284
|
}
|
|
281
285
|
return lines.join('\n');
|
|
282
286
|
}
|
|
287
|
+
async function isCommandAvailable(command) {
|
|
288
|
+
const probe = process.platform === 'win32' ? 'where' : 'which';
|
|
289
|
+
try {
|
|
290
|
+
const result = await execa(probe, [command], {
|
|
291
|
+
reject: false,
|
|
292
|
+
windowsHide: true,
|
|
293
|
+
timeout: 5_000,
|
|
294
|
+
});
|
|
295
|
+
return result.exitCode === 0;
|
|
296
|
+
}
|
|
297
|
+
catch {
|
|
298
|
+
return false;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
async function getBrewPrefix() {
|
|
302
|
+
try {
|
|
303
|
+
const result = await execa('brew', ['--prefix'], {
|
|
304
|
+
reject: false,
|
|
305
|
+
windowsHide: true,
|
|
306
|
+
timeout: 10_000,
|
|
307
|
+
});
|
|
308
|
+
if (result.exitCode === 0) {
|
|
309
|
+
const prefix = result.stdout.trim();
|
|
310
|
+
return prefix || null;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
catch {
|
|
314
|
+
// ignore
|
|
315
|
+
}
|
|
316
|
+
return null;
|
|
317
|
+
}
|
|
318
|
+
async function installViaHomebrew(modelName) {
|
|
319
|
+
const normalizedModelName = normalizeModelName(modelName);
|
|
320
|
+
const modelFileName = buildModelFileName(normalizedModelName);
|
|
321
|
+
const installDir = getInstallRoot();
|
|
322
|
+
// Instala (o reinstala/actualiza si ya estaba) whisper-cpp con brew.
|
|
323
|
+
const brewResult = await execa('brew', ['install', 'whisper-cpp'], {
|
|
324
|
+
reject: false,
|
|
325
|
+
windowsHide: true,
|
|
326
|
+
timeout: 600_000,
|
|
327
|
+
});
|
|
328
|
+
if (brewResult.exitCode !== 0) {
|
|
329
|
+
throw new Error(`brew install whisper-cpp fallo:\n${brewResult.stderr || brewResult.stdout || 'error desconocido'}`);
|
|
330
|
+
}
|
|
331
|
+
// Homebrew instala el binario como `whisper-cli` (igual que los releases),
|
|
332
|
+
// pero algunas versiones antiguas usaban `whisper-cpp`. Probamos ambos.
|
|
333
|
+
const brewPrefix = await getBrewPrefix();
|
|
334
|
+
const binNames = ['whisper-cli', 'whisper-cpp'];
|
|
335
|
+
const candidatePaths = [];
|
|
336
|
+
for (const name of binNames) {
|
|
337
|
+
if (brewPrefix)
|
|
338
|
+
candidatePaths.push(join(brewPrefix, 'bin', name));
|
|
339
|
+
candidatePaths.push(`/opt/homebrew/bin/${name}`);
|
|
340
|
+
candidatePaths.push(`/usr/local/bin/${name}`);
|
|
341
|
+
}
|
|
342
|
+
let executablePath = candidatePaths.find(fileExists) ?? null;
|
|
343
|
+
if (!executablePath) {
|
|
344
|
+
// Fallback: resolver via `which` para cualquiera de los nombres.
|
|
345
|
+
for (const name of binNames) {
|
|
346
|
+
const which = await execa('which', [name], {
|
|
347
|
+
reject: false,
|
|
348
|
+
windowsHide: true,
|
|
349
|
+
timeout: 5_000,
|
|
350
|
+
});
|
|
351
|
+
if (which.exitCode === 0 && which.stdout.trim()) {
|
|
352
|
+
executablePath = which.stdout.trim();
|
|
353
|
+
break;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
if (!executablePath) {
|
|
358
|
+
throw new Error('brew instalo whisper-cpp pero no encontre el binario en el PATH.');
|
|
359
|
+
}
|
|
360
|
+
// Descarga el modelo GGML (Homebrew no lo trae) en nuestra carpeta privada.
|
|
361
|
+
const modelDir = join(installDir, 'models');
|
|
362
|
+
const modelPath = join(modelDir, modelFileName);
|
|
363
|
+
await mkdir(modelDir, { recursive: true });
|
|
364
|
+
if (!fileExists(modelPath)) {
|
|
365
|
+
await writeFile(modelPath, await fetchBuffer(`${WHISPER_MODEL_BASE_URL}/${modelFileName}?download=1`, `modelo ${modelFileName}`));
|
|
366
|
+
}
|
|
367
|
+
// Intenta resolver la version instalada para guardarla como releaseTag.
|
|
368
|
+
let releaseTag = 'homebrew';
|
|
369
|
+
try {
|
|
370
|
+
const versionResult = await execa(executablePath, ['--version'], {
|
|
371
|
+
reject: false,
|
|
372
|
+
windowsHide: true,
|
|
373
|
+
timeout: 10_000,
|
|
374
|
+
});
|
|
375
|
+
const text = `${versionResult.stdout}\n${versionResult.stderr}`;
|
|
376
|
+
const match = text.match(/v?\d+\.\d+(?:\.\d+)?/);
|
|
377
|
+
if (match)
|
|
378
|
+
releaseTag = `homebrew-${match[0]}`;
|
|
379
|
+
}
|
|
380
|
+
catch {
|
|
381
|
+
// ignore
|
|
382
|
+
}
|
|
383
|
+
persistInstalledDictationConfig({
|
|
384
|
+
executablePath,
|
|
385
|
+
installDir,
|
|
386
|
+
installedAt: new Date().toISOString(),
|
|
387
|
+
modelName: normalizedModelName,
|
|
388
|
+
modelPath,
|
|
389
|
+
releaseTag,
|
|
390
|
+
});
|
|
391
|
+
logForDebugging(`[dictation] Instalacion via Homebrew: ${executablePath}, modelo en ${modelPath}`);
|
|
392
|
+
return { executablePath, installDir, modelPath, releaseTag };
|
|
393
|
+
}
|
|
394
|
+
function getManualInstallInstructions() {
|
|
395
|
+
if (process.platform === 'darwin') {
|
|
396
|
+
return [
|
|
397
|
+
'En macOS no hay binarios precompilados en los releases oficiales de whisper.cpp.',
|
|
398
|
+
'Opciones para instalarlo manualmente:',
|
|
399
|
+
'1) Instala Homebrew (https://brew.sh) y luego ejecuta `brew install whisper-cpp`.',
|
|
400
|
+
'2) Compila desde fuente: clona https://github.com/ggml-org/whisper.cpp y',
|
|
401
|
+
' ejecuta `cmake -B build && cmake --build build -j --config Release`.',
|
|
402
|
+
'Despues apunta el backend con la variable CONTEXT_CODE_DICTATION_EXECUTABLE',
|
|
403
|
+
'y el modelo con CONTEXT_CODE_DICTATION_MODEL, o vuelve a ejecutar /dictar install.',
|
|
404
|
+
].join('\n');
|
|
405
|
+
}
|
|
406
|
+
if (process.platform === 'linux') {
|
|
407
|
+
return [
|
|
408
|
+
'En Linux no hay binarios precompilados en los releases oficiales de whisper.cpp.',
|
|
409
|
+
'Compila desde fuente:',
|
|
410
|
+
' git clone https://github.com/ggml-org/whisper.cpp && cd whisper.cpp',
|
|
411
|
+
' cmake -B build && cmake --build build -j --config Release',
|
|
412
|
+
'Despues exporta CONTEXT_CODE_DICTATION_EXECUTABLE y CONTEXT_CODE_DICTATION_MODEL,',
|
|
413
|
+
'o vuelve a ejecutar /dictar install una vez tengas el binario en el PATH.',
|
|
414
|
+
].join('\n');
|
|
415
|
+
}
|
|
416
|
+
return 'No encontre un binario compatible para tu plataforma.';
|
|
417
|
+
}
|
|
283
418
|
export async function installLocalDictation(modelName) {
|
|
419
|
+
// En macOS los releases oficiales solo publican binarios para Windows e iOS,
|
|
420
|
+
// asi que usamos Homebrew como camino preferido.
|
|
421
|
+
if (process.platform === 'darwin') {
|
|
422
|
+
if (await isCommandAvailable('brew')) {
|
|
423
|
+
return installViaHomebrew(modelName);
|
|
424
|
+
}
|
|
425
|
+
throw new Error(`No se encontro Homebrew en el sistema.\n${getManualInstallInstructions()}`);
|
|
426
|
+
}
|
|
284
427
|
const normalizedModelName = normalizeModelName(modelName);
|
|
285
428
|
const modelFileName = buildModelFileName(normalizedModelName);
|
|
286
429
|
const installDir = getInstallRoot();
|
|
@@ -289,7 +432,7 @@ export async function installLocalDictation(modelName) {
|
|
|
289
432
|
const release = await fetchLatestRelease();
|
|
290
433
|
const asset = pickReleaseAsset(release.assets);
|
|
291
434
|
if (!asset) {
|
|
292
|
-
throw new Error(`No encontre un binario compatible de whisper.cpp para ${process.platform}/${process.arch}
|
|
435
|
+
throw new Error(`No encontre un binario compatible de whisper.cpp para ${process.platform}/${process.arch}.\n${getManualInstallInstructions()}`);
|
|
293
436
|
}
|
|
294
437
|
const archivePath = join(tempDir, asset.name);
|
|
295
438
|
const modelPath = join(installDir, 'models', modelFileName);
|
|
@@ -552,6 +552,8 @@ export function modelDisplayString(model) {
|
|
|
552
552
|
}
|
|
553
553
|
// @[MODEL LAUNCH]: Add a marketing name mapping for the new model below.
|
|
554
554
|
export function getMarketingNameForModel(modelId) {
|
|
555
|
+
if (!modelId)
|
|
556
|
+
return undefined;
|
|
555
557
|
if (getAPIProvider() === 'foundry') {
|
|
556
558
|
// deployment ID is user-defined in Foundry, so it may have no relation to the actual model
|
|
557
559
|
return undefined;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@iaforged/context-code",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.7",
|
|
4
4
|
"description": "Context Code es un asistente de desarrollo para la terminal. Puede revisar tu proyecto, editar archivos, ejecutar comandos y apoyarte en tareas reales de programacion.",
|
|
5
5
|
"author": "Context AI",
|
|
6
6
|
"license": "MIT",
|