voice-mode 2.29.0__py3-none-any.whl → 2.31.0__py3-none-any.whl
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.
- voice_mode/__version__.py +1 -1
- voice_mode/cli.py +171 -200
- voice_mode/frontend/.next/BUILD_ID +1 -1
- voice_mode/frontend/.next/app-build-manifest.json +5 -5
- voice_mode/frontend/.next/build-manifest.json +3 -3
- voice_mode/frontend/.next/next-minimal-server.js.nft.json +1 -1
- voice_mode/frontend/.next/next-server.js.nft.json +1 -1
- voice_mode/frontend/.next/prerender-manifest.json +1 -1
- voice_mode/frontend/.next/required-server-files.json +1 -1
- voice_mode/frontend/.next/server/app/_not-found/page.js +1 -1
- voice_mode/frontend/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- voice_mode/frontend/.next/server/app/_not-found.html +1 -1
- voice_mode/frontend/.next/server/app/_not-found.rsc +1 -1
- voice_mode/frontend/.next/server/app/api/connection-details/route.js +2 -2
- voice_mode/frontend/.next/server/app/favicon.ico/route.js +2 -2
- voice_mode/frontend/.next/server/app/index.html +1 -1
- voice_mode/frontend/.next/server/app/index.rsc +2 -2
- voice_mode/frontend/.next/server/app/page.js +3 -3
- voice_mode/frontend/.next/server/app/page_client-reference-manifest.js +1 -1
- voice_mode/frontend/.next/server/chunks/994.js +1 -1
- voice_mode/frontend/.next/server/middleware-build-manifest.js +1 -1
- voice_mode/frontend/.next/server/next-font-manifest.js +1 -1
- voice_mode/frontend/.next/server/next-font-manifest.json +1 -1
- voice_mode/frontend/.next/server/pages/404.html +1 -1
- voice_mode/frontend/.next/server/pages/500.html +1 -1
- voice_mode/frontend/.next/server/server-reference-manifest.json +1 -1
- voice_mode/frontend/.next/standalone/.next/BUILD_ID +1 -1
- voice_mode/frontend/.next/standalone/.next/app-build-manifest.json +5 -5
- voice_mode/frontend/.next/standalone/.next/build-manifest.json +3 -3
- voice_mode/frontend/.next/standalone/.next/prerender-manifest.json +1 -1
- voice_mode/frontend/.next/standalone/.next/required-server-files.json +1 -1
- voice_mode/frontend/.next/standalone/.next/server/app/_not-found/page.js +1 -1
- voice_mode/frontend/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- voice_mode/frontend/.next/standalone/.next/server/app/_not-found.html +1 -1
- voice_mode/frontend/.next/standalone/.next/server/app/_not-found.rsc +1 -1
- voice_mode/frontend/.next/standalone/.next/server/app/api/connection-details/route.js +2 -2
- voice_mode/frontend/.next/standalone/.next/server/app/favicon.ico/route.js +2 -2
- voice_mode/frontend/.next/standalone/.next/server/app/index.html +1 -1
- voice_mode/frontend/.next/standalone/.next/server/app/index.rsc +2 -2
- voice_mode/frontend/.next/standalone/.next/server/app/page.js +3 -3
- voice_mode/frontend/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- voice_mode/frontend/.next/standalone/.next/server/chunks/994.js +1 -1
- voice_mode/frontend/.next/standalone/.next/server/middleware-build-manifest.js +1 -1
- voice_mode/frontend/.next/standalone/.next/server/next-font-manifest.js +1 -1
- voice_mode/frontend/.next/standalone/.next/server/next-font-manifest.json +1 -1
- voice_mode/frontend/.next/standalone/.next/server/pages/404.html +1 -1
- voice_mode/frontend/.next/standalone/.next/server/pages/500.html +1 -1
- voice_mode/frontend/.next/standalone/.next/server/server-reference-manifest.json +1 -1
- voice_mode/frontend/.next/standalone/server.js +1 -1
- voice_mode/frontend/.next/static/chunks/app/{layout-53ce2eb95847e7bc.js → layout-f2d1799422b78b51.js} +1 -1
- voice_mode/frontend/.next/static/chunks/app/{page-9c7f7be4378697be.js → page-49b84bcf9a91501f.js} +1 -1
- voice_mode/frontend/.next/static/chunks/{main-app-2233caae67bf73bd.js → main-app-b61926fb6b68dca5.js} +1 -1
- voice_mode/frontend/.next/trace +43 -43
- voice_mode/frontend/.next/types/app/api/connection-details/route.ts +1 -1
- voice_mode/frontend/.next/types/app/layout.ts +1 -1
- voice_mode/frontend/.next/types/app/page.ts +1 -1
- voice_mode/tools/services/whisper/install.py +1 -1
- {voice_mode-2.29.0.dist-info → voice_mode-2.31.0.dist-info}/METADATA +1 -1
- {voice_mode-2.29.0.dist-info → voice_mode-2.31.0.dist-info}/RECORD +63 -63
- /voice_mode/frontend/.next/static/{998kY2RB1umOQfi6UBnLh → QYw7BshkzP8SKP3LsaTD0}/_buildManifest.js +0 -0
- /voice_mode/frontend/.next/static/{998kY2RB1umOQfi6UBnLh → QYw7BshkzP8SKP3LsaTD0}/_ssgManifest.js +0 -0
- {voice_mode-2.29.0.dist-info → voice_mode-2.31.0.dist-info}/WHEEL +0 -0
- {voice_mode-2.29.0.dist-info → voice_mode-2.31.0.dist-info}/entry_points.txt +0 -0
voice_mode/__version__.py
CHANGED
voice_mode/cli.py
CHANGED
@@ -473,7 +473,7 @@ def whisper_model_active(model_name):
|
|
473
473
|
# Check if model is installed
|
474
474
|
if not is_whisper_model_installed(model_name):
|
475
475
|
click.echo(f"Error: Model '{model_name}' is not installed.", err=True)
|
476
|
-
click.echo(f"Install it with:
|
476
|
+
click.echo(f"Install it with: voicemode whisper model install {model_name}", err=True)
|
477
477
|
raise click.Abort()
|
478
478
|
|
479
479
|
# Get previous model
|
@@ -492,14 +492,14 @@ def whisper_model_active(model_name):
|
|
492
492
|
if result.returncode == 0:
|
493
493
|
# Service is running
|
494
494
|
click.echo(f"\n⚠️ Please restart the whisper service for changes to take effect:")
|
495
|
-
click.echo(f" {click.style('
|
495
|
+
click.echo(f" {click.style('voicemode whisper restart', fg='yellow', bold=True)}")
|
496
496
|
else:
|
497
497
|
click.echo(f"\nWhisper service is not running. Start it with:")
|
498
|
-
click.echo(f"
|
498
|
+
click.echo(f" voicemode whisper start")
|
499
499
|
click.echo(f"(or restart the whisper service if it's managed by systemd/launchd)")
|
500
500
|
except:
|
501
501
|
click.echo(f"\nPlease restart the whisper service for changes to take effect:")
|
502
|
-
click.echo(f"
|
502
|
+
click.echo(f" voicemode whisper restart")
|
503
503
|
|
504
504
|
else:
|
505
505
|
# Show current model
|
@@ -527,8 +527,8 @@ def whisper_model_active(model_name):
|
|
527
527
|
except:
|
528
528
|
pass
|
529
529
|
|
530
|
-
click.echo(f"\nTo change:
|
531
|
-
click.echo(f"To list all models:
|
530
|
+
click.echo(f"\nTo change: voicemode whisper model active <model-name>")
|
531
|
+
click.echo(f"To list all models: voicemode whisper models")
|
532
532
|
|
533
533
|
|
534
534
|
@whisper.command("models")
|
@@ -604,8 +604,8 @@ def whisper_models():
|
|
604
604
|
click.echo(f"Models directory: {model_dir}")
|
605
605
|
click.echo(f"Total size: {format_size(total_installed_size)} installed / {format_size(total_available_size)} available")
|
606
606
|
click.echo("")
|
607
|
-
click.echo("To download a model:
|
608
|
-
click.echo("To set default model:
|
607
|
+
click.echo("To download a model: voicemode whisper model install <model-name>")
|
608
|
+
click.echo("To set default model: voicemode whisper model <model-name>")
|
609
609
|
|
610
610
|
|
611
611
|
@whisper_model.command("install")
|
@@ -613,7 +613,8 @@ def whisper_models():
|
|
613
613
|
@click.argument('model', default='large-v2')
|
614
614
|
@click.option('--force', '-f', is_flag=True, help='Re-download even if model exists')
|
615
615
|
@click.option('--skip-core-ml', is_flag=True, help='Skip Core ML conversion on Apple Silicon')
|
616
|
-
|
616
|
+
@click.option('--install-torch', is_flag=True, help='Install PyTorch for Core ML conversion (~2.5GB)')
|
617
|
+
def whisper_model_install(model, force, skip_core_ml, install_torch):
|
617
618
|
"""Install Whisper model(s) with optional Core ML conversion.
|
618
619
|
|
619
620
|
MODEL can be a model name (e.g., 'large-v2'), 'all' to download all models,
|
@@ -627,15 +628,36 @@ def whisper_model_install(model, force, skip_core_ml):
|
|
627
628
|
# Get the actual function from the MCP tool wrapper
|
628
629
|
tool = install_module.whisper_model_install
|
629
630
|
install_func = tool.fn if hasattr(tool, 'fn') else tool
|
631
|
+
|
632
|
+
# First attempt without install_torch to check if it's needed
|
630
633
|
result = asyncio.run(install_func(
|
631
634
|
model=model,
|
632
635
|
force_download=force,
|
633
|
-
skip_core_ml=skip_core_ml
|
636
|
+
skip_core_ml=skip_core_ml,
|
637
|
+
install_torch=install_torch,
|
638
|
+
auto_confirm=install_torch # If user passed --install-torch, skip confirmation
|
634
639
|
))
|
635
640
|
|
636
641
|
try:
|
637
642
|
# Parse JSON response
|
638
643
|
data = json.loads(result)
|
644
|
+
|
645
|
+
# Check if PyTorch installation is required for Core ML
|
646
|
+
if data.get('requires_confirmation') and not install_torch and not skip_core_ml:
|
647
|
+
click.echo("\n" + data.get('message', 'Core ML requires PyTorch (~2.5GB)'))
|
648
|
+
if data.get('recommendation'):
|
649
|
+
click.echo(f"💡 {data['recommendation']}")
|
650
|
+
|
651
|
+
if click.confirm("\nWould you like to install PyTorch for Core ML acceleration?"):
|
652
|
+
# Retry with install_torch=True
|
653
|
+
result = asyncio.run(install_func(
|
654
|
+
model=model,
|
655
|
+
force_download=force,
|
656
|
+
skip_core_ml=skip_core_ml,
|
657
|
+
install_torch=True,
|
658
|
+
auto_confirm=True
|
659
|
+
))
|
660
|
+
data = json.loads(result)
|
639
661
|
if data.get('success'):
|
640
662
|
click.echo("✅ Model download completed!")
|
641
663
|
|
@@ -984,7 +1006,7 @@ def frontend_install(auto_enable):
|
|
984
1006
|
if result.get('service_enabled'):
|
985
1007
|
click.echo("\n💡 Frontend service is enabled and will start automatically at boot/login")
|
986
1008
|
else:
|
987
|
-
click.echo("\n💡 Run '
|
1009
|
+
click.echo("\n💡 Run 'voicemode livekit frontend enable' to start automatically at boot/login")
|
988
1010
|
else:
|
989
1011
|
click.echo(f"❌ Frontend installation failed: {result.get('error', 'Unknown error')}")
|
990
1012
|
|
@@ -1185,7 +1207,7 @@ def frontend_build(force):
|
|
1185
1207
|
@voice_mode_main_cli.group()
|
1186
1208
|
@click.help_option('-h', '--help', help='Show this message and exit')
|
1187
1209
|
def config():
|
1188
|
-
"""Manage
|
1210
|
+
"""Manage voicemode configuration."""
|
1189
1211
|
pass
|
1190
1212
|
|
1191
1213
|
|
@@ -1232,7 +1254,7 @@ def config_get(key):
|
|
1232
1254
|
click.echo(f"{key}={env_value} (from environment)")
|
1233
1255
|
else:
|
1234
1256
|
click.echo(f"❌ Configuration key not found: {key}")
|
1235
|
-
click.echo("Run '
|
1257
|
+
click.echo("Run 'voicemode config list' to see available keys")
|
1236
1258
|
|
1237
1259
|
|
1238
1260
|
@config.command("set")
|
@@ -1246,163 +1268,17 @@ def config_set(key, value):
|
|
1246
1268
|
click.echo(result)
|
1247
1269
|
|
1248
1270
|
|
1249
|
-
# Shell completion group
|
1250
|
-
@voice_mode_main_cli.group()
|
1251
|
-
@click.help_option('-h', '--help', help='Show this message and exit')
|
1252
|
-
def completion():
|
1253
|
-
"""Generate shell completion scripts for voice-mode."""
|
1254
|
-
pass
|
1255
|
-
|
1256
|
-
|
1257
|
-
@completion.command("bash")
|
1258
|
-
def completion_bash():
|
1259
|
-
"""Generate bash completion script.
|
1260
|
-
|
1261
|
-
Add this to your ~/.bashrc:
|
1262
|
-
|
1263
|
-
eval "$(_VOICE_MODE_COMPLETE=bash_source voice-mode)"
|
1264
|
-
|
1265
|
-
Or for better performance, generate the script once:
|
1266
|
-
|
1267
|
-
_VOICE_MODE_COMPLETE=bash_source voice-mode > ~/.voice-mode-complete.bash
|
1268
|
-
echo '. ~/.voice-mode-complete.bash' >> ~/.bashrc
|
1269
|
-
"""
|
1270
|
-
# Output the instructions directly since the environment variable method
|
1271
|
-
# needs to be run from the shell itself
|
1272
|
-
click.echo("# Bash completion for voice-mode")
|
1273
|
-
click.echo("# Add this to your ~/.bashrc:")
|
1274
|
-
click.echo("")
|
1275
|
-
click.echo('eval "$(_VOICE_MODE_COMPLETE=bash_source voice-mode)"')
|
1276
|
-
click.echo("")
|
1277
|
-
click.echo("# Or for better performance, generate and save the script:")
|
1278
|
-
click.echo("# _VOICE_MODE_COMPLETE=bash_source voice-mode > ~/.voice-mode-complete.bash")
|
1279
|
-
click.echo("# Then add to ~/.bashrc:")
|
1280
|
-
click.echo("# . ~/.voice-mode-complete.bash")
|
1281
|
-
|
1282
|
-
|
1283
|
-
@completion.command("zsh")
|
1284
|
-
def completion_zsh():
|
1285
|
-
"""Generate zsh completion script.
|
1286
|
-
|
1287
|
-
Add this to your ~/.zshrc:
|
1288
|
-
|
1289
|
-
eval "$(_VOICE_MODE_COMPLETE=zsh_source voice-mode)"
|
1290
|
-
|
1291
|
-
Or for better performance, generate the script once:
|
1292
|
-
|
1293
|
-
_VOICE_MODE_COMPLETE=zsh_source voice-mode > ~/.voice-mode-complete.zsh
|
1294
|
-
echo '. ~/.voice-mode-complete.zsh' >> ~/.zshrc
|
1295
|
-
"""
|
1296
|
-
# Output the instructions directly
|
1297
|
-
click.echo("# Zsh completion for voice-mode")
|
1298
|
-
click.echo("# Add this to your ~/.zshrc:")
|
1299
|
-
click.echo("")
|
1300
|
-
click.echo('eval "$(_VOICE_MODE_COMPLETE=zsh_source voice-mode)"')
|
1301
|
-
click.echo("")
|
1302
|
-
click.echo("# Or for better performance, generate and save the script:")
|
1303
|
-
click.echo("# _VOICE_MODE_COMPLETE=zsh_source voice-mode > ~/.voice-mode-complete.zsh")
|
1304
|
-
click.echo("# Then add to ~/.zshrc:")
|
1305
|
-
click.echo("# . ~/.voice-mode-complete.zsh")
|
1306
|
-
|
1307
|
-
|
1308
|
-
@completion.command("fish")
|
1309
|
-
def completion_fish():
|
1310
|
-
"""Generate fish completion script.
|
1311
|
-
|
1312
|
-
Add this to ~/.config/fish/completions/voice-mode.fish:
|
1313
|
-
|
1314
|
-
_VOICE_MODE_COMPLETE=fish_source voice-mode | source
|
1315
|
-
|
1316
|
-
Or save it to a file:
|
1317
|
-
|
1318
|
-
_VOICE_MODE_COMPLETE=fish_source voice-mode > ~/.config/fish/completions/voice-mode.fish
|
1319
|
-
"""
|
1320
|
-
# Output the instructions directly
|
1321
|
-
click.echo("# Fish completion for voice-mode")
|
1322
|
-
click.echo("# Save this to ~/.config/fish/completions/voice-mode.fish:")
|
1323
|
-
click.echo("")
|
1324
|
-
click.echo("_VOICE_MODE_COMPLETE=fish_source voice-mode | source")
|
1325
|
-
click.echo("")
|
1326
|
-
click.echo("# Or run this command to save it:")
|
1327
|
-
click.echo("# _VOICE_MODE_COMPLETE=fish_source voice-mode > ~/.config/fish/completions/voice-mode.fish")
|
1328
|
-
|
1329
|
-
|
1330
|
-
@completion.command("install")
|
1331
|
-
@click.help_option('-h', '--help')
|
1332
|
-
@click.option('--shell', type=click.Choice(['bash', 'zsh', 'fish', 'auto']), default='auto', help='Shell type to install for')
|
1333
|
-
def completion_install(shell):
|
1334
|
-
"""Show installation instructions for shell completion.
|
1335
|
-
|
1336
|
-
This command displays the steps to enable tab completion
|
1337
|
-
for voice-mode in your shell.
|
1338
|
-
"""
|
1339
|
-
# Detect shell if auto
|
1340
|
-
if shell == 'auto':
|
1341
|
-
shell_env = os.environ.get('SHELL', '')
|
1342
|
-
if 'bash' in shell_env:
|
1343
|
-
shell = 'bash'
|
1344
|
-
elif 'zsh' in shell_env:
|
1345
|
-
shell = 'zsh'
|
1346
|
-
elif 'fish' in shell_env:
|
1347
|
-
shell = 'fish'
|
1348
|
-
else:
|
1349
|
-
click.echo("Could not detect shell type. Showing instructions for all shells.")
|
1350
|
-
click.echo("")
|
1351
|
-
|
1352
|
-
# Show all instructions
|
1353
|
-
click.echo("=== Bash ===")
|
1354
|
-
click.echo("Add to ~/.bashrc:")
|
1355
|
-
click.echo(' eval "$(_VOICE_MODE_COMPLETE=bash_source voice-mode)"')
|
1356
|
-
click.echo("")
|
1357
|
-
|
1358
|
-
click.echo("=== Zsh ===")
|
1359
|
-
click.echo("Add to ~/.zshrc:")
|
1360
|
-
click.echo(' eval "$(_VOICE_MODE_COMPLETE=zsh_source voice-mode)"')
|
1361
|
-
click.echo("")
|
1362
|
-
|
1363
|
-
click.echo("=== Fish ===")
|
1364
|
-
click.echo("Run this command:")
|
1365
|
-
click.echo(' _VOICE_MODE_COMPLETE=fish_source voice-mode > ~/.config/fish/completions/voice-mode.fish')
|
1366
|
-
return
|
1367
|
-
|
1368
|
-
click.echo(f"To enable tab completion for voice-mode in {shell}:")
|
1369
|
-
click.echo("")
|
1370
|
-
|
1371
|
-
if shell == 'bash':
|
1372
|
-
click.echo("Add this line to your ~/.bashrc:")
|
1373
|
-
click.echo(' eval "$(_VOICE_MODE_COMPLETE=bash_source voice-mode)"')
|
1374
|
-
click.echo("")
|
1375
|
-
click.echo("Or for better performance, generate the script once:")
|
1376
|
-
click.echo(" _VOICE_MODE_COMPLETE=bash_source voice-mode > ~/.voice-mode-complete.bash")
|
1377
|
-
click.echo(" echo '. ~/.voice-mode-complete.bash' >> ~/.bashrc")
|
1378
|
-
elif shell == 'zsh':
|
1379
|
-
click.echo("Add this line to your ~/.zshrc:")
|
1380
|
-
click.echo(' eval "$(_VOICE_MODE_COMPLETE=zsh_source voice-mode)"')
|
1381
|
-
click.echo("")
|
1382
|
-
click.echo("Or for better performance, generate the script once:")
|
1383
|
-
click.echo(" _VOICE_MODE_COMPLETE=zsh_source voice-mode > ~/.voice-mode-complete.zsh")
|
1384
|
-
click.echo(" echo '. ~/.voice-mode-complete.zsh' >> ~/.zshrc")
|
1385
|
-
elif shell == 'fish':
|
1386
|
-
click.echo("Run this command:")
|
1387
|
-
click.echo(' _VOICE_MODE_COMPLETE=fish_source voice-mode > ~/.config/fish/completions/voice-mode.fish')
|
1388
|
-
click.echo("")
|
1389
|
-
click.echo("Fish will automatically load the completion from this location.")
|
1390
|
-
|
1391
|
-
click.echo("")
|
1392
|
-
click.echo("After making these changes, restart your shell or source the config file.")
|
1393
|
-
|
1394
|
-
|
1395
1271
|
# Diagnostics group
|
1396
1272
|
@voice_mode_main_cli.group()
|
1397
1273
|
@click.help_option('-h', '--help', help='Show this message and exit')
|
1398
1274
|
def diag():
|
1399
|
-
"""Diagnostic tools for
|
1275
|
+
"""Diagnostic tools for voicemode."""
|
1400
1276
|
pass
|
1401
1277
|
|
1402
1278
|
|
1403
1279
|
@diag.command()
|
1404
1280
|
def info():
|
1405
|
-
"""Show
|
1281
|
+
"""Show voicemode installation information."""
|
1406
1282
|
from voice_mode.tools.diagnostics import voice_mode_info
|
1407
1283
|
result = asyncio.run(voice_mode_info.fn())
|
1408
1284
|
click.echo(result)
|
@@ -1471,7 +1347,7 @@ def dependencies():
|
|
1471
1347
|
click.echo(str(result))
|
1472
1348
|
|
1473
1349
|
|
1474
|
-
# Legacy CLI for
|
1350
|
+
# Legacy CLI for voicemode-cli command
|
1475
1351
|
@click.group()
|
1476
1352
|
@click.version_option()
|
1477
1353
|
@click.help_option('-h', '--help')
|
@@ -1518,16 +1394,16 @@ def converse(message, wait, duration, min_duration, transport, room_name, voice,
|
|
1518
1394
|
Examples:
|
1519
1395
|
|
1520
1396
|
# Simple conversation
|
1521
|
-
|
1397
|
+
voicemode converse
|
1522
1398
|
|
1523
1399
|
# Speak a message without waiting
|
1524
|
-
|
1400
|
+
voicemode converse -m "Hello there!" --no-wait
|
1525
1401
|
|
1526
1402
|
# Continuous conversation mode
|
1527
|
-
|
1403
|
+
voicemode converse --continuous
|
1528
1404
|
|
1529
1405
|
# Use specific voice
|
1530
|
-
|
1406
|
+
voicemode converse --voice nova
|
1531
1407
|
"""
|
1532
1408
|
from voice_mode.tools.converse import converse as converse_fn
|
1533
1409
|
|
@@ -1694,18 +1570,89 @@ def version():
|
|
1694
1570
|
@click.help_option('-h', '--help')
|
1695
1571
|
@click.option('--force', is_flag=True, help='Force reinstall even if already up to date')
|
1696
1572
|
def update(force):
|
1697
|
-
"""Update Voice Mode to the latest version.
|
1573
|
+
"""Update Voice Mode to the latest version.
|
1574
|
+
|
1575
|
+
Automatically detects installation method (UV tool, UV pip, or regular pip)
|
1576
|
+
and uses the appropriate update command.
|
1577
|
+
"""
|
1698
1578
|
import subprocess
|
1699
1579
|
import requests
|
1580
|
+
from pathlib import Path
|
1700
1581
|
from importlib.metadata import version as get_version, PackageNotFoundError
|
1701
1582
|
|
1583
|
+
def detect_uv_tool_installation():
|
1584
|
+
"""Detect if running from a UV tool installation."""
|
1585
|
+
prefix_path = Path(sys.prefix).resolve()
|
1586
|
+
uv_tools_base = Path.home() / ".local" / "share" / "uv" / "tools"
|
1587
|
+
|
1588
|
+
# Check if sys.prefix is within UV tools directory
|
1589
|
+
if uv_tools_base in prefix_path.parents or prefix_path.parent == uv_tools_base:
|
1590
|
+
# Find the tool directory
|
1591
|
+
tool_dir = prefix_path if prefix_path.parent == uv_tools_base else None
|
1592
|
+
|
1593
|
+
if not tool_dir:
|
1594
|
+
for parent in prefix_path.parents:
|
1595
|
+
if parent.parent == uv_tools_base:
|
1596
|
+
tool_dir = parent
|
1597
|
+
break
|
1598
|
+
|
1599
|
+
if tool_dir:
|
1600
|
+
# Verify with uv-receipt.toml
|
1601
|
+
receipt_file = tool_dir / "uv-receipt.toml"
|
1602
|
+
if receipt_file.exists():
|
1603
|
+
# Parse tool name from receipt or use directory name
|
1604
|
+
try:
|
1605
|
+
with open(receipt_file) as f:
|
1606
|
+
content = f.read()
|
1607
|
+
import re
|
1608
|
+
match = re.search(r'name = "([^"]+)"', content)
|
1609
|
+
tool_name = match.group(1) if match else tool_dir.name
|
1610
|
+
return True, tool_name
|
1611
|
+
except Exception:
|
1612
|
+
return True, tool_dir.name
|
1613
|
+
|
1614
|
+
return False, None
|
1615
|
+
|
1616
|
+
def detect_uv_venv():
|
1617
|
+
"""Detect if running in a UV-managed virtual environment."""
|
1618
|
+
# Check if we're in a venv
|
1619
|
+
if sys.prefix == sys.base_prefix:
|
1620
|
+
return False
|
1621
|
+
|
1622
|
+
# Check for UV markers in pyvenv.cfg
|
1623
|
+
pyvenv_cfg = Path(sys.prefix) / "pyvenv.cfg"
|
1624
|
+
if pyvenv_cfg.exists():
|
1625
|
+
try:
|
1626
|
+
with open(pyvenv_cfg) as f:
|
1627
|
+
content = f.read()
|
1628
|
+
if "uv" in content.lower() or "managed by uv" in content:
|
1629
|
+
return True
|
1630
|
+
except Exception:
|
1631
|
+
pass
|
1632
|
+
|
1633
|
+
return False
|
1634
|
+
|
1635
|
+
def check_uv_available():
|
1636
|
+
"""Check if UV is available."""
|
1637
|
+
try:
|
1638
|
+
result = subprocess.run(
|
1639
|
+
["uv", "--version"],
|
1640
|
+
capture_output=True,
|
1641
|
+
text=True,
|
1642
|
+
timeout=2
|
1643
|
+
)
|
1644
|
+
return result.returncode == 0
|
1645
|
+
except (FileNotFoundError, subprocess.TimeoutExpired):
|
1646
|
+
return False
|
1647
|
+
|
1648
|
+
# Get current version
|
1702
1649
|
try:
|
1703
1650
|
current_version = get_version("voice-mode")
|
1704
1651
|
except PackageNotFoundError:
|
1705
1652
|
current_version = "development"
|
1706
1653
|
|
1654
|
+
# Check if update needed (unless forced)
|
1707
1655
|
if not force and current_version != "development":
|
1708
|
-
# Check if update is needed
|
1709
1656
|
try:
|
1710
1657
|
response = requests.get(
|
1711
1658
|
"https://pypi.org/pypi/voice-mode/json",
|
@@ -1717,58 +1664,82 @@ def update(force):
|
|
1717
1664
|
click.echo(f"Already running the latest version ({current_version})")
|
1718
1665
|
return
|
1719
1666
|
except (requests.RequestException, KeyError, ValueError):
|
1720
|
-
# Continue with update if we can't check
|
1721
|
-
pass
|
1667
|
+
pass # Continue with update if we can't check
|
1722
1668
|
|
1723
|
-
|
1669
|
+
# Detect installation method
|
1670
|
+
is_uv_tool, tool_name = detect_uv_tool_installation()
|
1724
1671
|
|
1725
|
-
|
1726
|
-
|
1727
|
-
|
1672
|
+
if is_uv_tool:
|
1673
|
+
# UV tool installation - use uv tool upgrade
|
1674
|
+
click.echo(f"Updating Voice Mode (UV tool: {tool_name})...")
|
1675
|
+
|
1728
1676
|
result = subprocess.run(
|
1729
|
-
["uv", "
|
1677
|
+
["uv", "tool", "upgrade", tool_name],
|
1730
1678
|
capture_output=True,
|
1731
|
-
text=True
|
1732
|
-
check=False
|
1679
|
+
text=True
|
1733
1680
|
)
|
1734
1681
|
|
1735
1682
|
if result.returncode == 0:
|
1736
|
-
|
1683
|
+
try:
|
1684
|
+
new_version = get_version("voice-mode")
|
1685
|
+
click.echo(f"✅ Successfully updated to version {new_version}")
|
1686
|
+
except PackageNotFoundError:
|
1687
|
+
click.echo("✅ Successfully updated Voice Mode")
|
1688
|
+
else:
|
1689
|
+
click.echo(f"❌ Update failed: {result.stderr}")
|
1690
|
+
click.echo(f"Try running manually: uv tool upgrade {tool_name}")
|
1691
|
+
|
1692
|
+
elif detect_uv_venv():
|
1693
|
+
# UV-managed virtual environment
|
1694
|
+
click.echo("Updating Voice Mode (UV virtual environment)...")
|
1695
|
+
|
1696
|
+
result = subprocess.run(
|
1697
|
+
["uv", "pip", "install", "--upgrade", "voice-mode"],
|
1698
|
+
capture_output=True,
|
1699
|
+
text=True
|
1700
|
+
)
|
1701
|
+
|
1702
|
+
if result.returncode == 0:
|
1703
|
+
try:
|
1704
|
+
new_version = get_version("voice-mode")
|
1705
|
+
click.echo(f"✅ Successfully updated to version {new_version}")
|
1706
|
+
except PackageNotFoundError:
|
1707
|
+
click.echo("✅ Successfully updated Voice Mode")
|
1708
|
+
else:
|
1709
|
+
click.echo(f"❌ Update failed: {result.stderr}")
|
1710
|
+
click.echo("Try running: uv pip install --upgrade voice-mode")
|
1711
|
+
|
1712
|
+
else:
|
1713
|
+
# Standard installation - try UV if available, else pip
|
1714
|
+
has_uv = check_uv_available()
|
1715
|
+
|
1716
|
+
if has_uv:
|
1717
|
+
click.echo("Updating Voice Mode (using UV)...")
|
1737
1718
|
result = subprocess.run(
|
1738
1719
|
["uv", "pip", "install", "--upgrade", "voice-mode"],
|
1739
1720
|
capture_output=True,
|
1740
1721
|
text=True
|
1741
1722
|
)
|
1742
|
-
if result.returncode == 0:
|
1743
|
-
# Get new version
|
1744
|
-
try:
|
1745
|
-
new_version = get_version("voice-mode")
|
1746
|
-
click.echo(f"✅ Successfully updated to version {new_version}")
|
1747
|
-
except PackageNotFoundError:
|
1748
|
-
click.echo("✅ Successfully updated Voice Mode")
|
1749
|
-
else:
|
1750
|
-
click.echo(f"❌ Update failed: {result.stderr}")
|
1751
|
-
click.echo("Try running: uv pip install --upgrade voice-mode")
|
1752
1723
|
else:
|
1753
|
-
|
1724
|
+
click.echo("Updating Voice Mode (using pip)...")
|
1754
1725
|
result = subprocess.run(
|
1755
1726
|
[sys.executable, "-m", "pip", "install", "--upgrade", "voice-mode"],
|
1756
1727
|
capture_output=True,
|
1757
1728
|
text=True
|
1758
1729
|
)
|
1759
|
-
|
1760
|
-
|
1761
|
-
|
1762
|
-
|
1763
|
-
|
1764
|
-
|
1730
|
+
|
1731
|
+
if result.returncode == 0:
|
1732
|
+
try:
|
1733
|
+
new_version = get_version("voice-mode")
|
1734
|
+
click.echo(f"✅ Successfully updated to version {new_version}")
|
1735
|
+
except PackageNotFoundError:
|
1736
|
+
click.echo("✅ Successfully updated Voice Mode")
|
1737
|
+
else:
|
1738
|
+
click.echo(f"❌ Update failed: {result.stderr}")
|
1739
|
+
if has_uv:
|
1740
|
+
click.echo("Try running: uv pip install --upgrade voice-mode")
|
1765
1741
|
else:
|
1766
|
-
click.echo(f"❌ Update failed: {result.stderr}")
|
1767
1742
|
click.echo("Try running: pip install --upgrade voice-mode")
|
1768
|
-
|
1769
|
-
except FileNotFoundError as e:
|
1770
|
-
click.echo(f"❌ Update failed: {e}")
|
1771
|
-
click.echo("Please install UV or pip and try again")
|
1772
1743
|
|
1773
1744
|
|
1774
1745
|
# Completions command
|
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
QYw7BshkzP8SKP3LsaTD0
|
@@ -4,25 +4,25 @@
|
|
4
4
|
"static/chunks/webpack-0ea9b80f19935b70.js",
|
5
5
|
"static/chunks/fd9d1056-af324d327b243cf1.js",
|
6
6
|
"static/chunks/117-40bc79a2b97edb21.js",
|
7
|
-
"static/chunks/main-app-
|
7
|
+
"static/chunks/main-app-b61926fb6b68dca5.js",
|
8
8
|
"static/chunks/app/_not-found/page-5011050e402ab9c8.js"
|
9
9
|
],
|
10
10
|
"/layout": [
|
11
11
|
"static/chunks/webpack-0ea9b80f19935b70.js",
|
12
12
|
"static/chunks/fd9d1056-af324d327b243cf1.js",
|
13
13
|
"static/chunks/117-40bc79a2b97edb21.js",
|
14
|
-
"static/chunks/main-app-
|
14
|
+
"static/chunks/main-app-b61926fb6b68dca5.js",
|
15
15
|
"static/css/a2f49a47752b5010.css",
|
16
|
-
"static/chunks/app/layout-
|
16
|
+
"static/chunks/app/layout-f2d1799422b78b51.js"
|
17
17
|
],
|
18
18
|
"/page": [
|
19
19
|
"static/chunks/webpack-0ea9b80f19935b70.js",
|
20
20
|
"static/chunks/fd9d1056-af324d327b243cf1.js",
|
21
21
|
"static/chunks/117-40bc79a2b97edb21.js",
|
22
|
-
"static/chunks/main-app-
|
22
|
+
"static/chunks/main-app-b61926fb6b68dca5.js",
|
23
23
|
"static/chunks/144d3bae-2d5f122b82426d88.js",
|
24
24
|
"static/chunks/471-bd4b96a33883dfa2.js",
|
25
|
-
"static/chunks/app/page-
|
25
|
+
"static/chunks/app/page-49b84bcf9a91501f.js"
|
26
26
|
]
|
27
27
|
}
|
28
28
|
}
|
@@ -5,14 +5,14 @@
|
|
5
5
|
"devFiles": [],
|
6
6
|
"ampDevFiles": [],
|
7
7
|
"lowPriorityFiles": [
|
8
|
-
"static/
|
9
|
-
"static/
|
8
|
+
"static/QYw7BshkzP8SKP3LsaTD0/_buildManifest.js",
|
9
|
+
"static/QYw7BshkzP8SKP3LsaTD0/_ssgManifest.js"
|
10
10
|
],
|
11
11
|
"rootMainFiles": [
|
12
12
|
"static/chunks/webpack-0ea9b80f19935b70.js",
|
13
13
|
"static/chunks/fd9d1056-af324d327b243cf1.js",
|
14
14
|
"static/chunks/117-40bc79a2b97edb21.js",
|
15
|
-
"static/chunks/main-app-
|
15
|
+
"static/chunks/main-app-b61926fb6b68dca5.js"
|
16
16
|
],
|
17
17
|
"pages": {
|
18
18
|
"/_app": [
|
@@ -1 +1 @@
|
|
1
|
-
{"version":1,"files":["../node_modules/styled-jsx/index.js","../node_modules/styled-jsx/package.json","../node_modules/styled-jsx/dist/index/index.js","../node_modules/react/package.json","../node_modules/react/index.js","../node_modules/client-only/package.json","../node_modules/react/cjs/react.production.min.js","../node_modules/client-only/index.js","../node_modules/styled-jsx/style.js","../node_modules/next/dist/compiled/next-server/server.runtime.prod.js","../node_modules/next/package.json","../node_modules/next/dist/lib/constants.js","../node_modules/next/dist/server/body-streams.js","../node_modules/next/dist/lib/picocolors.js","../node_modules/next/dist/shared/lib/constants.js","../node_modules/next/dist/server/web/utils.js","../node_modules/next/dist/client/components/app-router-headers.js","../node_modules/next/dist/server/lib/trace/tracer.js","../node_modules/next/dist/server/lib/trace/constants.js","../node_modules/next/dist/client/components/static-generation-async-storage.external.js","../node_modules/next/dist/shared/lib/error-source.js","../node_modules/next/dist/shared/lib/modern-browserslist-target.js","../node_modules/next/dist/compiled/debug/package.json","../node_modules/next/dist/client/components/static-generation-async-storage-instance.js","../node_modules/next/dist/shared/lib/runtime-config.external.js","../node_modules/next/dist/compiled/debug/index.js","../node_modules/next/dist/compiled/ws/package.json","../node_modules/next/dist/compiled/node-html-parser/package.json","../node_modules/next/dist/compiled/lru-cache/package.json","../node_modules/@swc/helpers/_/_interop_require_default/package.json","../node_modules/next/dist/compiled/ws/index.js","../node_modules/next/dist/compiled/node-html-parser/index.js","../node_modules/next/dist/compiled/lru-cache/index.js","../node_modules/next/dist/client/components/async-local-storage.js","../node_modules/next/dist/compiled/@opentelemetry/api/package.json","../node_modules/@swc/helpers/package.json","../node_modules/next/dist/client/components/react-dev-overlay/internal/helpers/parseStack.js","../node_modules/next/dist/client/components/react-dev-overlay/internal/helpers/nodeStackFrames.js","../node_modules/next/dist/compiled/jsonwebtoken/package.json","../node_modules/next/dist/client/components/react-dev-overlay/server/middleware.js","../node_modules/@swc/helpers/cjs/_interop_require_default.cjs","../node_modules/next/dist/compiled/@opentelemetry/api/index.js","../node_modules/next/dist/compiled/jsonwebtoken/index.js","../node_modules/next/dist/compiled/browserslist/package.json","../node_modules/next/dist/compiled/browserslist/index.js","../node_modules/next/dist/client/components/react-dev-overlay/server/shared.js","../node_modules/next/dist/client/components/react-dev-overlay/internal/helpers/getRawSourceMap.js","../node_modules/next/dist/client/components/react-dev-overlay/internal/helpers/launchEditor.js","../node_modules/next/dist/compiled/babel/code-frame.js","../node_modules/next/dist/compiled/json5/package.json","../node_modules/next/dist/compiled/semver/package.json","../node_modules/next/dist/compiled/babel/package.json","../node_modules/next/dist/lib/semver-noop.js","../node_modules/next/dist/compiled/json5/index.js","../node_modules/next/dist/compiled/semver/index.js","../node_modules/next/dist/compiled/stacktrace-parser/package.json","../node_modules/next/dist/compiled/source-map08/package.json","../node_modules/caniuse-lite/dist/unpacker/agents.js","../node_modules/caniuse-lite/dist/unpacker/
|
1
|
+
{"version":1,"files":["../node_modules/styled-jsx/index.js","../node_modules/styled-jsx/package.json","../node_modules/styled-jsx/dist/index/index.js","../node_modules/react/package.json","../node_modules/react/index.js","../node_modules/client-only/package.json","../node_modules/react/cjs/react.production.min.js","../node_modules/client-only/index.js","../node_modules/styled-jsx/style.js","../node_modules/next/dist/compiled/next-server/server.runtime.prod.js","../node_modules/next/package.json","../node_modules/next/dist/lib/constants.js","../node_modules/next/dist/server/body-streams.js","../node_modules/next/dist/lib/picocolors.js","../node_modules/next/dist/shared/lib/constants.js","../node_modules/next/dist/server/web/utils.js","../node_modules/next/dist/client/components/app-router-headers.js","../node_modules/next/dist/server/lib/trace/tracer.js","../node_modules/next/dist/server/lib/trace/constants.js","../node_modules/next/dist/client/components/static-generation-async-storage.external.js","../node_modules/next/dist/shared/lib/error-source.js","../node_modules/next/dist/shared/lib/modern-browserslist-target.js","../node_modules/next/dist/compiled/debug/package.json","../node_modules/next/dist/client/components/static-generation-async-storage-instance.js","../node_modules/next/dist/shared/lib/runtime-config.external.js","../node_modules/next/dist/compiled/debug/index.js","../node_modules/next/dist/compiled/ws/package.json","../node_modules/next/dist/compiled/node-html-parser/package.json","../node_modules/next/dist/compiled/lru-cache/package.json","../node_modules/@swc/helpers/_/_interop_require_default/package.json","../node_modules/next/dist/compiled/ws/index.js","../node_modules/next/dist/compiled/node-html-parser/index.js","../node_modules/next/dist/compiled/lru-cache/index.js","../node_modules/next/dist/client/components/async-local-storage.js","../node_modules/next/dist/compiled/@opentelemetry/api/package.json","../node_modules/@swc/helpers/package.json","../node_modules/next/dist/client/components/react-dev-overlay/internal/helpers/parseStack.js","../node_modules/next/dist/client/components/react-dev-overlay/internal/helpers/nodeStackFrames.js","../node_modules/next/dist/compiled/jsonwebtoken/package.json","../node_modules/next/dist/client/components/react-dev-overlay/server/middleware.js","../node_modules/@swc/helpers/cjs/_interop_require_default.cjs","../node_modules/next/dist/compiled/@opentelemetry/api/index.js","../node_modules/next/dist/compiled/jsonwebtoken/index.js","../node_modules/next/dist/compiled/browserslist/package.json","../node_modules/next/dist/compiled/browserslist/index.js","../node_modules/next/dist/client/components/react-dev-overlay/server/shared.js","../node_modules/next/dist/client/components/react-dev-overlay/internal/helpers/getRawSourceMap.js","../node_modules/next/dist/client/components/react-dev-overlay/internal/helpers/launchEditor.js","../node_modules/next/dist/compiled/babel/code-frame.js","../node_modules/next/dist/compiled/json5/package.json","../node_modules/next/dist/compiled/semver/package.json","../node_modules/next/dist/compiled/babel/package.json","../node_modules/next/dist/lib/semver-noop.js","../node_modules/next/dist/compiled/json5/index.js","../node_modules/next/dist/compiled/semver/index.js","../node_modules/next/dist/compiled/stacktrace-parser/package.json","../node_modules/next/dist/compiled/source-map08/package.json","../node_modules/caniuse-lite/dist/unpacker/agents.js","../node_modules/caniuse-lite/dist/unpacker/feature.js","../node_modules/caniuse-lite/dist/unpacker/region.js","../node_modules/next/dist/compiled/babel/bundle.js","../node_modules/next/dist/client/components/react-dev-overlay/internal/helpers/getSourceMapUrl.js","../node_modules/next/dist/compiled/stacktrace-parser/stack-trace-parser.cjs.js","../node_modules/next/dist/compiled/source-map08/source-map.js","../node_modules/caniuse-lite/package.json","../node_modules/next/dist/compiled/babel/core.js","../node_modules/caniuse-lite/data/agents.js","../node_modules/caniuse-lite/dist/lib/statuses.js","../node_modules/caniuse-lite/dist/lib/supported.js","../node_modules/caniuse-lite/dist/unpacker/browsers.js","../node_modules/caniuse-lite/dist/unpacker/browserVersions.js","../node_modules/next/dist/compiled/data-uri-to-buffer/package.json","../node_modules/next/dist/compiled/shell-quote/package.json","../node_modules/next/dist/compiled/data-uri-to-buffer/index.js","../node_modules/next/dist/compiled/shell-quote/index.js","../node_modules/caniuse-lite/data/browsers.js","../node_modules/caniuse-lite/data/browserVersions.js","../node_modules/next/dist/compiled/babel-packages/package.json","../node_modules/next/dist/compiled/babel-packages/packages-bundle.js","../node_modules/next/dist/compiled/babel/parser.js","../node_modules/next/dist/compiled/babel/traverse.js","../node_modules/next/dist/compiled/babel/types.js","../node_modules/next/dist/server/future/route-modules/app-page/vendored/contexts/amp-context.js","../node_modules/next/dist/server/future/route-modules/app-page/vendored/contexts/app-router-context.js","../node_modules/next/dist/server/future/route-modules/app-page/vendored/contexts/entrypoints.js","../node_modules/next/dist/server/future/route-modules/app-page/vendored/contexts/head-manager-context.js","../node_modules/next/dist/server/future/route-modules/app-page/vendored/contexts/hooks-client-context.js","../node_modules/next/dist/server/future/route-modules/app-page/vendored/contexts/html-context.js","../node_modules/next/dist/server/future/route-modules/app-page/vendored/contexts/image-config-context.js","../node_modules/next/dist/server/future/route-modules/app-page/vendored/contexts/loadable-context.js","../node_modules/next/dist/server/future/route-modules/app-page/vendored/contexts/loadable.js","../node_modules/next/dist/server/future/route-modules/app-page/vendored/contexts/router-context.js","../node_modules/next/dist/server/future/route-modules/app-page/vendored/contexts/server-inserted-html.js","../node_modules/next/dist/server/future/route-modules/app-page/module.compiled.js","../node_modules/next/dist/server/future/route-modules/pages/vendored/contexts/amp-context.js","../node_modules/next/dist/server/future/route-modules/pages/vendored/contexts/app-router-context.js","../node_modules/next/dist/server/future/route-modules/pages/vendored/contexts/entrypoints.js","../node_modules/next/dist/server/future/route-modules/pages/vendored/contexts/head-manager-context.js","../node_modules/next/dist/server/future/route-modules/pages/vendored/contexts/hooks-client-context.js","../node_modules/next/dist/server/future/route-modules/pages/vendored/contexts/html-context.js","../node_modules/next/dist/server/future/route-modules/pages/vendored/contexts/image-config-context.js","../node_modules/next/dist/server/future/route-modules/pages/vendored/contexts/loadable-context.js","../node_modules/next/dist/server/future/route-modules/pages/vendored/contexts/loadable.js","../node_modules/next/dist/server/future/route-modules/pages/vendored/contexts/router-context.js","../node_modules/next/dist/server/future/route-modules/pages/vendored/contexts/server-inserted-html.js","../node_modules/next/dist/server/future/route-modules/pages/module.compiled.js"]}
|