mcli-framework 7.12.2__py3-none-any.whl → 7.12.4__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.

Potentially problematic release.


This version of mcli-framework might be problematic. Click here for more details.

Files changed (216) hide show
  1. mcli/app/__init__.py +0 -2
  2. mcli/app/commands_cmd.py +30 -26
  3. mcli/app/completion_helpers.py +5 -5
  4. mcli/app/init_cmd.py +10 -10
  5. mcli/app/lock_cmd.py +29 -24
  6. mcli/app/main.py +2 -8
  7. mcli/app/model/model.py +5 -10
  8. mcli/app/store_cmd.py +8 -8
  9. mcli/app/video/__init__.py +0 -2
  10. mcli/app/video/video.py +1 -14
  11. mcli/chat/chat.py +90 -108
  12. mcli/chat/command_rag.py +0 -4
  13. mcli/chat/enhanced_chat.py +32 -41
  14. mcli/chat/system_controller.py +37 -37
  15. mcli/chat/system_integration.py +4 -5
  16. mcli/cli.py +2 -3
  17. mcli/lib/api/api.py +4 -9
  18. mcli/lib/api/daemon_client.py +19 -20
  19. mcli/lib/api/daemon_client_local.py +1 -3
  20. mcli/lib/api/daemon_decorator.py +6 -6
  21. mcli/lib/api/mcli_decorators.py +4 -8
  22. mcli/lib/auth/__init__.py +0 -1
  23. mcli/lib/auth/auth.py +4 -5
  24. mcli/lib/auth/mcli_manager.py +7 -12
  25. mcli/lib/auth/token_util.py +5 -5
  26. mcli/lib/config/__init__.py +29 -1
  27. mcli/lib/config/config.py +0 -1
  28. mcli/lib/custom_commands.py +1 -1
  29. mcli/lib/discovery/command_discovery.py +15 -15
  30. mcli/lib/erd/erd.py +7 -7
  31. mcli/lib/files/files.py +1 -1
  32. mcli/lib/fs/__init__.py +31 -1
  33. mcli/lib/fs/fs.py +12 -13
  34. mcli/lib/lib.py +0 -1
  35. mcli/lib/logger/logger.py +7 -10
  36. mcli/lib/performance/optimizer.py +25 -27
  37. mcli/lib/performance/rust_bridge.py +22 -27
  38. mcli/lib/performance/uvloop_config.py +0 -1
  39. mcli/lib/pickles/__init__.py +0 -1
  40. mcli/lib/pickles/pickles.py +0 -2
  41. mcli/lib/secrets/commands.py +0 -2
  42. mcli/lib/secrets/manager.py +0 -1
  43. mcli/lib/secrets/repl.py +2 -3
  44. mcli/lib/secrets/store.py +1 -2
  45. mcli/lib/services/data_pipeline.py +34 -34
  46. mcli/lib/services/lsh_client.py +38 -40
  47. mcli/lib/shell/shell.py +2 -2
  48. mcli/lib/toml/__init__.py +0 -1
  49. mcli/lib/ui/styling.py +0 -1
  50. mcli/lib/ui/visual_effects.py +33 -41
  51. mcli/lib/watcher/watcher.py +0 -1
  52. mcli/ml/__init__.py +1 -1
  53. mcli/ml/api/__init__.py +1 -1
  54. mcli/ml/api/app.py +8 -9
  55. mcli/ml/api/middleware.py +10 -10
  56. mcli/ml/api/routers/__init__.py +1 -1
  57. mcli/ml/api/routers/admin_router.py +3 -3
  58. mcli/ml/api/routers/auth_router.py +17 -18
  59. mcli/ml/api/routers/backtest_router.py +2 -2
  60. mcli/ml/api/routers/data_router.py +2 -2
  61. mcli/ml/api/routers/model_router.py +14 -15
  62. mcli/ml/api/routers/monitoring_router.py +2 -2
  63. mcli/ml/api/routers/portfolio_router.py +2 -2
  64. mcli/ml/api/routers/prediction_router.py +10 -9
  65. mcli/ml/api/routers/trade_router.py +2 -2
  66. mcli/ml/api/routers/websocket_router.py +6 -7
  67. mcli/ml/api/schemas.py +2 -2
  68. mcli/ml/auth/__init__.py +1 -1
  69. mcli/ml/auth/auth_manager.py +22 -23
  70. mcli/ml/auth/models.py +17 -17
  71. mcli/ml/auth/permissions.py +17 -17
  72. mcli/ml/backtesting/__init__.py +1 -1
  73. mcli/ml/backtesting/backtest_engine.py +31 -35
  74. mcli/ml/backtesting/performance_metrics.py +12 -14
  75. mcli/ml/backtesting/run.py +1 -2
  76. mcli/ml/cache.py +35 -36
  77. mcli/ml/cli/__init__.py +1 -1
  78. mcli/ml/cli/main.py +21 -24
  79. mcli/ml/config/__init__.py +1 -1
  80. mcli/ml/config/settings.py +28 -29
  81. mcli/ml/configs/__init__.py +1 -1
  82. mcli/ml/configs/dvc_config.py +14 -15
  83. mcli/ml/configs/mlflow_config.py +12 -13
  84. mcli/ml/configs/mlops_manager.py +19 -21
  85. mcli/ml/dashboard/__init__.py +4 -4
  86. mcli/ml/dashboard/app.py +20 -30
  87. mcli/ml/dashboard/app_supabase.py +16 -19
  88. mcli/ml/dashboard/app_training.py +11 -14
  89. mcli/ml/dashboard/cli.py +2 -2
  90. mcli/ml/dashboard/common.py +2 -3
  91. mcli/ml/dashboard/components/__init__.py +1 -1
  92. mcli/ml/dashboard/components/charts.py +13 -11
  93. mcli/ml/dashboard/components/metrics.py +7 -7
  94. mcli/ml/dashboard/components/tables.py +12 -9
  95. mcli/ml/dashboard/overview.py +2 -2
  96. mcli/ml/dashboard/pages/__init__.py +1 -1
  97. mcli/ml/dashboard/pages/cicd.py +15 -18
  98. mcli/ml/dashboard/pages/debug_dependencies.py +7 -7
  99. mcli/ml/dashboard/pages/monte_carlo_predictions.py +11 -18
  100. mcli/ml/dashboard/pages/predictions_enhanced.py +24 -32
  101. mcli/ml/dashboard/pages/scrapers_and_logs.py +22 -24
  102. mcli/ml/dashboard/pages/test_portfolio.py +3 -6
  103. mcli/ml/dashboard/pages/trading.py +16 -18
  104. mcli/ml/dashboard/pages/workflows.py +20 -30
  105. mcli/ml/dashboard/utils.py +9 -9
  106. mcli/ml/dashboard/warning_suppression.py +3 -3
  107. mcli/ml/data_ingestion/__init__.py +1 -1
  108. mcli/ml/data_ingestion/api_connectors.py +41 -46
  109. mcli/ml/data_ingestion/data_pipeline.py +36 -46
  110. mcli/ml/data_ingestion/stream_processor.py +43 -46
  111. mcli/ml/database/__init__.py +1 -1
  112. mcli/ml/database/migrations/env.py +2 -2
  113. mcli/ml/database/models.py +22 -24
  114. mcli/ml/database/session.py +14 -14
  115. mcli/ml/experimentation/__init__.py +1 -1
  116. mcli/ml/experimentation/ab_testing.py +45 -46
  117. mcli/ml/features/__init__.py +1 -1
  118. mcli/ml/features/ensemble_features.py +22 -27
  119. mcli/ml/features/recommendation_engine.py +30 -30
  120. mcli/ml/features/stock_features.py +29 -32
  121. mcli/ml/features/test_feature_engineering.py +10 -11
  122. mcli/ml/logging.py +4 -4
  123. mcli/ml/mlops/__init__.py +1 -1
  124. mcli/ml/mlops/data_versioning.py +29 -30
  125. mcli/ml/mlops/experiment_tracker.py +24 -24
  126. mcli/ml/mlops/model_serving.py +31 -34
  127. mcli/ml/mlops/pipeline_orchestrator.py +27 -35
  128. mcli/ml/models/__init__.py +5 -6
  129. mcli/ml/models/base_models.py +23 -23
  130. mcli/ml/models/ensemble_models.py +31 -31
  131. mcli/ml/models/recommendation_models.py +18 -19
  132. mcli/ml/models/test_models.py +14 -16
  133. mcli/ml/monitoring/__init__.py +1 -1
  134. mcli/ml/monitoring/drift_detection.py +32 -36
  135. mcli/ml/monitoring/metrics.py +2 -2
  136. mcli/ml/optimization/__init__.py +1 -1
  137. mcli/ml/optimization/optimize.py +1 -2
  138. mcli/ml/optimization/portfolio_optimizer.py +30 -32
  139. mcli/ml/predictions/__init__.py +1 -1
  140. mcli/ml/preprocessing/__init__.py +1 -1
  141. mcli/ml/preprocessing/data_cleaners.py +22 -23
  142. mcli/ml/preprocessing/feature_extractors.py +23 -26
  143. mcli/ml/preprocessing/ml_pipeline.py +23 -23
  144. mcli/ml/preprocessing/test_preprocessing.py +7 -8
  145. mcli/ml/scripts/populate_sample_data.py +0 -4
  146. mcli/ml/serving/serve.py +1 -2
  147. mcli/ml/tasks.py +17 -17
  148. mcli/ml/tests/test_integration.py +29 -30
  149. mcli/ml/tests/test_training_dashboard.py +21 -21
  150. mcli/ml/trading/__init__.py +1 -1
  151. mcli/ml/trading/migrations.py +5 -5
  152. mcli/ml/trading/models.py +21 -23
  153. mcli/ml/trading/paper_trading.py +16 -13
  154. mcli/ml/trading/risk_management.py +17 -18
  155. mcli/ml/trading/trading_service.py +25 -28
  156. mcli/ml/training/__init__.py +1 -1
  157. mcli/ml/training/train.py +0 -1
  158. mcli/public/oi/oi.py +1 -2
  159. mcli/self/completion_cmd.py +6 -10
  160. mcli/self/logs_cmd.py +19 -24
  161. mcli/self/migrate_cmd.py +22 -20
  162. mcli/self/redis_cmd.py +10 -11
  163. mcli/self/self_cmd.py +10 -18
  164. mcli/self/store_cmd.py +10 -12
  165. mcli/self/visual_cmd.py +9 -14
  166. mcli/self/zsh_cmd.py +2 -4
  167. mcli/workflow/daemon/async_command_database.py +23 -24
  168. mcli/workflow/daemon/async_process_manager.py +27 -29
  169. mcli/workflow/daemon/client.py +27 -33
  170. mcli/workflow/daemon/daemon.py +32 -36
  171. mcli/workflow/daemon/enhanced_daemon.py +24 -33
  172. mcli/workflow/daemon/process_cli.py +11 -12
  173. mcli/workflow/daemon/process_manager.py +23 -26
  174. mcli/workflow/daemon/test_daemon.py +4 -5
  175. mcli/workflow/dashboard/dashboard_cmd.py +0 -1
  176. mcli/workflow/doc_convert.py +15 -17
  177. mcli/workflow/gcloud/__init__.py +0 -1
  178. mcli/workflow/gcloud/gcloud.py +11 -8
  179. mcli/workflow/git_commit/ai_service.py +14 -15
  180. mcli/workflow/lsh_integration.py +9 -11
  181. mcli/workflow/model_service/client.py +26 -31
  182. mcli/workflow/model_service/download_and_run_efficient_models.py +10 -14
  183. mcli/workflow/model_service/lightweight_embedder.py +25 -35
  184. mcli/workflow/model_service/lightweight_model_server.py +26 -32
  185. mcli/workflow/model_service/lightweight_test.py +7 -10
  186. mcli/workflow/model_service/model_service.py +80 -91
  187. mcli/workflow/model_service/ollama_efficient_runner.py +14 -18
  188. mcli/workflow/model_service/openai_adapter.py +23 -23
  189. mcli/workflow/model_service/pdf_processor.py +21 -26
  190. mcli/workflow/model_service/test_efficient_runner.py +12 -16
  191. mcli/workflow/model_service/test_example.py +11 -13
  192. mcli/workflow/model_service/test_integration.py +3 -5
  193. mcli/workflow/model_service/test_new_features.py +7 -8
  194. mcli/workflow/notebook/converter.py +1 -1
  195. mcli/workflow/notebook/notebook_cmd.py +5 -6
  196. mcli/workflow/notebook/schema.py +0 -1
  197. mcli/workflow/notebook/validator.py +7 -3
  198. mcli/workflow/openai/openai.py +1 -2
  199. mcli/workflow/registry/registry.py +4 -1
  200. mcli/workflow/repo/repo.py +6 -7
  201. mcli/workflow/scheduler/cron_parser.py +16 -19
  202. mcli/workflow/scheduler/job.py +10 -10
  203. mcli/workflow/scheduler/monitor.py +15 -15
  204. mcli/workflow/scheduler/persistence.py +17 -18
  205. mcli/workflow/scheduler/scheduler.py +37 -38
  206. mcli/workflow/secrets/__init__.py +1 -1
  207. mcli/workflow/sync/test_cmd.py +0 -1
  208. mcli/workflow/wakatime/__init__.py +5 -9
  209. mcli/workflow/wakatime/wakatime.py +1 -2
  210. {mcli_framework-7.12.2.dist-info → mcli_framework-7.12.4.dist-info}/METADATA +1 -1
  211. mcli_framework-7.12.4.dist-info/RECORD +279 -0
  212. mcli_framework-7.12.2.dist-info/RECORD +0 -279
  213. {mcli_framework-7.12.2.dist-info → mcli_framework-7.12.4.dist-info}/WHEEL +0 -0
  214. {mcli_framework-7.12.2.dist-info → mcli_framework-7.12.4.dist-info}/entry_points.txt +0 -0
  215. {mcli_framework-7.12.2.dist-info → mcli_framework-7.12.4.dist-info}/licenses/LICENSE +0 -0
  216. {mcli_framework-7.12.2.dist-info → mcli_framework-7.12.4.dist-info}/top_level.txt +0 -0
@@ -1,17 +1,15 @@
1
1
  import asyncio
2
2
  import json
3
3
  import os
4
- import signal
5
4
  import uuid
6
5
  from contextlib import asynccontextmanager
7
6
  from dataclasses import asdict, dataclass
8
7
  from datetime import datetime
9
8
  from enum import Enum
10
9
  from pathlib import Path
11
- from typing import Any, Dict, List, Optional, Union
10
+ from typing import Dict, List, Optional
12
11
 
13
12
  import aiosqlite
14
- import psutil
15
13
  import redis.asyncio as redis
16
14
 
17
15
  from mcli.lib.logger.logger import get_logger
@@ -30,7 +28,7 @@ class ProcessStatus(Enum):
30
28
 
31
29
  @dataclass
32
30
  class ProcessInfo:
33
- """Information about a managed process"""
31
+ """Information about a managed process."""
34
32
 
35
33
  id: str
36
34
  name: str
@@ -57,7 +55,7 @@ class ProcessInfo:
57
55
 
58
56
 
59
57
  class AsyncProcessContainer:
60
- """Manages a single async process with enhanced monitoring"""
58
+ """Manages a single async process with enhanced monitoring."""
61
59
 
62
60
  def __init__(self, process_info: ProcessInfo, redis_client: Optional[redis.Redis] = None):
63
61
  self.info = process_info
@@ -69,7 +67,7 @@ class AsyncProcessContainer:
69
67
  self._setup_container_environment()
70
68
 
71
69
  def _setup_container_environment(self):
72
- """Setup isolated environment for the process"""
70
+ """Setup isolated environment for the process."""
73
71
  base_dir = Path.home() / ".local" / "mcli" / "containers"
74
72
  self.container_dir = base_dir / self.info.id
75
73
  self.container_dir.mkdir(parents=True, exist_ok=True)
@@ -80,7 +78,7 @@ class AsyncProcessContainer:
80
78
  json.dump(asdict(self.info), f, indent=2, default=str)
81
79
 
82
80
  async def start(self, timeout: Optional[float] = None) -> bool:
83
- """Start the async process with optional timeout"""
81
+ """Start the async process with optional timeout."""
84
82
  try:
85
83
  if self.process and self.process.returncode is None:
86
84
  logger.warning(f"Process {self.info.id} is already running")
@@ -122,7 +120,7 @@ class AsyncProcessContainer:
122
120
  return False
123
121
 
124
122
  async def stop(self, timeout: float = 10.0) -> bool:
125
- """Stop the process gracefully with timeout"""
123
+ """Stop the process gracefully with timeout."""
126
124
  if not self.process or self.process.returncode is not None:
127
125
  return True
128
126
 
@@ -161,7 +159,7 @@ class AsyncProcessContainer:
161
159
  return False
162
160
 
163
161
  async def kill(self) -> bool:
164
- """Force kill the process"""
162
+ """Force kill the process."""
165
163
  if not self.process or self.process.returncode is not None:
166
164
  return True
167
165
 
@@ -191,7 +189,7 @@ class AsyncProcessContainer:
191
189
  return False
192
190
 
193
191
  async def wait(self, timeout: Optional[float] = None) -> int:
194
- """Wait for process to complete with optional timeout"""
192
+ """Wait for process to complete with optional timeout."""
195
193
  if not self.process:
196
194
  raise RuntimeError("Process not started")
197
195
 
@@ -218,7 +216,7 @@ class AsyncProcessContainer:
218
216
  return self.process.returncode
219
217
 
220
218
  async def _monitor_stdout(self):
221
- """Monitor stdout and collect lines"""
219
+ """Monitor stdout and collect lines."""
222
220
  if not self.process or not self.process.stdout:
223
221
  return
224
222
 
@@ -246,7 +244,7 @@ class AsyncProcessContainer:
246
244
  logger.error(f"Error monitoring stdout for {self.info.id}: {e}")
247
245
 
248
246
  async def _monitor_stderr(self):
249
- """Monitor stderr and collect lines"""
247
+ """Monitor stderr and collect lines."""
250
248
  if not self.process or not self.process.stderr:
251
249
  return
252
250
 
@@ -274,7 +272,7 @@ class AsyncProcessContainer:
274
272
  logger.error(f"Error monitoring stderr for {self.info.id}: {e}")
275
273
 
276
274
  async def _timeout_handler(self, timeout: float):
277
- """Handle process timeout"""
275
+ """Handle process timeout."""
278
276
  await asyncio.sleep(timeout)
279
277
 
280
278
  if self.process and self.process.returncode is None:
@@ -282,7 +280,7 @@ class AsyncProcessContainer:
282
280
  await self.kill()
283
281
 
284
282
  async def _cache_process_info(self):
285
- """Cache process info in Redis"""
283
+ """Cache process info in Redis."""
286
284
  if not self.redis_client:
287
285
  return
288
286
 
@@ -306,7 +304,7 @@ class AsyncProcessContainer:
306
304
 
307
305
 
308
306
  class AsyncProcessManager:
309
- """High-performance async process manager with SQLite and Redis"""
307
+ """High-performance async process manager with SQLite and Redis."""
310
308
 
311
309
  def __init__(self, db_path: Optional[str] = None, redis_url: Optional[str] = None):
312
310
  if db_path is None:
@@ -325,13 +323,13 @@ class AsyncProcessManager:
325
323
  self._db_pool_lock = asyncio.Lock()
326
324
 
327
325
  async def initialize(self):
328
- """Initialize the process manager"""
326
+ """Initialize the process manager."""
329
327
  await self._init_database()
330
328
  await self._init_redis()
331
329
  await self._init_db_pool()
332
330
 
333
331
  async def _init_database(self):
334
- """Initialize SQLite database with optimizations"""
332
+ """Initialize SQLite database with optimizations."""
335
333
  async with aiosqlite.connect(self.db_path) as db:
336
334
  # Enable WAL mode for better concurrency
337
335
  await db.execute("PRAGMA journal_mode=WAL")
@@ -370,7 +368,7 @@ class AsyncProcessManager:
370
368
  await db.commit()
371
369
 
372
370
  async def _init_redis(self):
373
- """Initialize Redis connection for caching"""
371
+ """Initialize Redis connection for caching."""
374
372
  try:
375
373
  self.redis_client = redis.from_url(self.redis_url, decode_responses=True)
376
374
  await self.redis_client.ping()
@@ -380,7 +378,7 @@ class AsyncProcessManager:
380
378
  self.redis_client = None
381
379
 
382
380
  async def _init_db_pool(self):
383
- """Initialize connection pool for SQLite"""
381
+ """Initialize connection pool for SQLite."""
384
382
  async with self._db_pool_lock:
385
383
  for _ in range(self._db_pool_size):
386
384
  conn = await aiosqlite.connect(self.db_path)
@@ -389,7 +387,7 @@ class AsyncProcessManager:
389
387
 
390
388
  @asynccontextmanager
391
389
  async def _get_db_connection(self):
392
- """Get a database connection from the pool"""
390
+ """Get a database connection from the pool."""
393
391
  async with self._db_pool_lock:
394
392
  if self._db_pool:
395
393
  conn = self._db_pool.pop()
@@ -415,7 +413,7 @@ class AsyncProcessManager:
415
413
  environment: Optional[Dict[str, str]] = None,
416
414
  timeout: Optional[float] = None,
417
415
  ) -> str:
418
- """Start a new async process"""
416
+ """Start a new async process."""
419
417
  process_info = ProcessInfo(
420
418
  id=str(uuid.uuid4()),
421
419
  name=name,
@@ -442,7 +440,7 @@ class AsyncProcessManager:
442
440
  raise RuntimeError(f"Failed to start process: {name}")
443
441
 
444
442
  async def stop_process(self, process_id: str, timeout: float = 10.0) -> bool:
445
- """Stop a process gracefully"""
443
+ """Stop a process gracefully."""
446
444
  if process_id not in self.processes:
447
445
  raise KeyError(f"Process not found: {process_id}")
448
446
 
@@ -455,7 +453,7 @@ class AsyncProcessManager:
455
453
  return success
456
454
 
457
455
  async def kill_process(self, process_id: str) -> bool:
458
- """Force kill a process"""
456
+ """Force kill a process."""
459
457
  if process_id not in self.processes:
460
458
  raise KeyError(f"Process not found: {process_id}")
461
459
 
@@ -468,7 +466,7 @@ class AsyncProcessManager:
468
466
  return success
469
467
 
470
468
  async def get_process_info(self, process_id: str) -> ProcessInfo:
471
- """Get process information"""
469
+ """Get process information."""
472
470
  if process_id in self.processes:
473
471
  return self.processes[process_id].info
474
472
 
@@ -482,7 +480,7 @@ class AsyncProcessManager:
482
480
  raise KeyError(f"Process not found: {process_id}")
483
481
 
484
482
  async def list_processes(self, status_filter: Optional[str] = None) -> List[ProcessInfo]:
485
- """List all processes with optional status filter"""
483
+ """List all processes with optional status filter."""
486
484
  processes = []
487
485
 
488
486
  # Add active processes
@@ -511,7 +509,7 @@ class AsyncProcessManager:
511
509
  return processes
512
510
 
513
511
  async def cleanup_finished(self) -> List[str]:
514
- """Remove finished processes from memory"""
512
+ """Remove finished processes from memory."""
515
513
  finished_ids = []
516
514
 
517
515
  for process_id, container in list(self.processes.items()):
@@ -527,7 +525,7 @@ class AsyncProcessManager:
527
525
  return finished_ids
528
526
 
529
527
  async def _save_process_info(self, process_info: ProcessInfo):
530
- """Save process info to database"""
528
+ """Save process info to database."""
531
529
  async with self._get_db_connection() as db:
532
530
  await db.execute(
533
531
  """
@@ -556,7 +554,7 @@ class AsyncProcessManager:
556
554
  await db.commit()
557
555
 
558
556
  def _row_to_process_info(self, row) -> ProcessInfo:
559
- """Convert database row to ProcessInfo"""
557
+ """Convert database row to ProcessInfo."""
560
558
  return ProcessInfo(
561
559
  id=row[0],
562
560
  name=row[1],
@@ -575,7 +573,7 @@ class AsyncProcessManager:
575
573
  )
576
574
 
577
575
  async def close(self):
578
- """Clean up resources"""
576
+ """Clean up resources."""
579
577
  # Close all active processes
580
578
  for container in self.processes.values():
581
579
  await container.stop()
@@ -1,8 +1,3 @@
1
- import json
2
- import os
3
- import subprocess
4
- import sys
5
- import tempfile
6
1
  import uuid
7
2
  from datetime import datetime
8
3
  from pathlib import Path
@@ -17,11 +12,10 @@ from .commands import Command, CommandDatabase, CommandExecutor
17
12
  @click.group()
18
13
  def client():
19
14
  """Client CLI for daemon commands."""
20
- pass
21
15
 
22
16
 
23
17
  class DaemonClient:
24
- """Client interface for interacting with the daemon service"""
18
+ """Client interface for interacting with the daemon service."""
25
19
 
26
20
  def __init__(self, timeout: int = 30):
27
21
  self.db = CommandDatabase()
@@ -30,7 +24,7 @@ class DaemonClient:
30
24
  self._validate_connection()
31
25
 
32
26
  def _validate_connection(self):
33
- """Verify connection to the daemon service"""
27
+ """Verify connection to the daemon service."""
34
28
  try:
35
29
  self.db.get_all_commands() # Simple query to test connection
36
30
  except Exception as e:
@@ -45,7 +39,7 @@ class DaemonClient:
45
39
  group: Optional[str] = None,
46
40
  tags: Optional[List[str]] = None,
47
41
  ) -> str:
48
- """Add a command from a file"""
42
+ """Add a command from a file."""
49
43
  # Read the file
50
44
  with open(file_path, "r") as f:
51
45
  code = f.read()
@@ -84,12 +78,12 @@ class DaemonClient:
84
78
  group: Optional[str] = None,
85
79
  tags: Optional[List[str]] = None,
86
80
  ) -> str:
87
- """Add a command from stdin"""
81
+ """Add a command from stdin."""
88
82
  click.echo("Enter your code (Ctrl+D when done):")
89
83
 
90
84
  # Read from stdin
91
85
  lines = []
92
- try:
86
+ try: # noqa: SIM105
93
87
  while True:
94
88
  line = input()
95
89
  lines.append(line)
@@ -105,7 +99,7 @@ class DaemonClient:
105
99
  command = Command(
106
100
  id=str(uuid.uuid4()),
107
101
  name=name,
108
- description=description or f"Command from stdin",
102
+ description=description or "Command from stdin",
109
103
  code=code,
110
104
  language=language,
111
105
  group=group,
@@ -116,13 +110,13 @@ class DaemonClient:
116
110
  return self.db.add_command(command)
117
111
 
118
112
  def add_command_interactive(self) -> Optional[str]:
119
- """Interactive command creation"""
113
+ """Interactive command creation."""
120
114
  # Get command name
121
115
  name = click.prompt("Command name", type=str)
122
116
 
123
117
  # Check if name already exists
124
118
  existing = self.db.search_commands(name, limit=1)
125
- if existing and existing[0].name == name:
119
+ if existing and existing[0].name == name: # noqa: SIM102
126
120
  if not click.confirm(f"Command '{name}' already exists. Overwrite?"):
127
121
  return None
128
122
 
@@ -156,7 +150,7 @@ class DaemonClient:
156
150
  else: # paste
157
151
  click.echo("Paste your code below (Ctrl+D when done):")
158
152
  lines = []
159
- try:
153
+ try: # noqa: SIM105
160
154
  while True:
161
155
  line = input()
162
156
  lines.append(line)
@@ -172,7 +166,7 @@ class DaemonClient:
172
166
  command = Command(
173
167
  id=str(uuid.uuid4()),
174
168
  name=name,
175
- description=description or f"Command from paste",
169
+ description=description or "Command from paste",
176
170
  code=code,
177
171
  language=language,
178
172
  group=group,
@@ -183,7 +177,7 @@ class DaemonClient:
183
177
  return self.db.add_command(command)
184
178
 
185
179
  def execute_command(self, command_id: str, args: List[str] = None) -> Dict[str, Any]:
186
- """Execute a command"""
180
+ """Execute a command."""
187
181
  command = self.db.get_command(command_id)
188
182
  if not command:
189
183
  raise ValueError(f"Command '{command_id}' not found")
@@ -203,27 +197,27 @@ class DaemonClient:
203
197
  return result
204
198
 
205
199
  def search_commands(self, query: str, limit: int = 10) -> List[Command]:
206
- """Search for commands"""
200
+ """Search for commands."""
207
201
  return self.db.search_commands(query, limit)
208
202
 
209
203
  def find_similar_commands(self, query: str, limit: int = 5) -> List[tuple]:
210
- """Find similar commands using cosine similarity"""
204
+ """Find similar commands using cosine similarity."""
211
205
  return self.db.find_similar_commands(query, limit)
212
206
 
213
207
  def get_all_commands(self) -> List[Command]:
214
- """Get all commands"""
208
+ """Get all commands."""
215
209
  return self.db.get_all_commands()
216
210
 
217
211
  def get_command(self, command_id: str) -> Optional[Command]:
218
- """Get a command by ID"""
212
+ """Get a command by ID."""
219
213
  return self.db.get_command(command_id)
220
214
 
221
215
  def update_command(self, command: Command) -> bool:
222
- """Update a command"""
216
+ """Update a command."""
223
217
  return self.db.update_command(command)
224
218
 
225
219
  def delete_command(self, command_id: str) -> bool:
226
- """Delete a command"""
220
+ """Delete a command."""
227
221
  return self.db.delete_command(command_id)
228
222
 
229
223
 
@@ -241,7 +235,7 @@ class DaemonClient:
241
235
  @click.option("--group", help="Command group")
242
236
  @click.option("--tags", help="Comma-separated tags")
243
237
  def add_file(name: str, file_path: str, description: str, language: str, group: str, tags: str):
244
- """Add a command from a file"""
238
+ """Add a command from a file."""
245
239
  client = DaemonClient()
246
240
 
247
241
  # Parse tags
@@ -273,7 +267,7 @@ def add_file(name: str, file_path: str, description: str, language: str, group:
273
267
  @click.option("--group", help="Command group")
274
268
  @click.option("--tags", help="Comma-separated tags")
275
269
  def add_stdin(name: str, description: str, language: str, group: str, tags: str):
276
- """Add a command from stdin"""
270
+ """Add a command from stdin."""
277
271
  client = DaemonClient()
278
272
 
279
273
  # Parse tags
@@ -290,7 +284,7 @@ def add_stdin(name: str, description: str, language: str, group: str, tags: str)
290
284
 
291
285
  @client.command()
292
286
  def add_interactive():
293
- """Add a command interactively"""
287
+ """Add a command interactively."""
294
288
  client = DaemonClient()
295
289
 
296
290
  try:
@@ -307,7 +301,7 @@ def add_interactive():
307
301
  @click.argument("command_id")
308
302
  @click.argument("args", nargs=-1)
309
303
  def execute(command_id: str, args: List[str]):
310
- """Execute a command"""
304
+ """Execute a command."""
311
305
  client = DaemonClient()
312
306
 
313
307
  try:
@@ -334,7 +328,7 @@ def execute(command_id: str, args: List[str]):
334
328
  @click.option("--limit", default=10, help="Maximum number of results")
335
329
  @click.option("--similar", is_flag=True, help="Use similarity search")
336
330
  def search(query: str, limit: int, similar: bool):
337
- """Search for commands"""
331
+ """Search for commands."""
338
332
  client = DaemonClient()
339
333
 
340
334
  try:
@@ -370,7 +364,7 @@ def search(query: str, limit: int, similar: bool):
370
364
  @click.option("--group", help="Filter by group")
371
365
  @click.option("--language", help="Filter by language")
372
366
  def list(group: str, language: str):
373
- """List all commands"""
367
+ """List all commands."""
374
368
  client = DaemonClient()
375
369
 
376
370
  try:
@@ -403,7 +397,7 @@ def list(group: str, language: str):
403
397
  @client.command()
404
398
  @click.argument("command_id")
405
399
  def show(command_id: str):
406
- """Show command details"""
400
+ """Show command details."""
407
401
  client = DaemonClient()
408
402
 
409
403
  try:
@@ -438,7 +432,7 @@ def show(command_id: str):
438
432
  @client.command()
439
433
  @click.argument("command_id")
440
434
  def delete(command_id: str):
441
- """Delete a command"""
435
+ """Delete a command."""
442
436
  client = DaemonClient()
443
437
 
444
438
  try:
@@ -466,7 +460,7 @@ def delete(command_id: str):
466
460
  @click.option("--group", help="New group")
467
461
  @click.option("--tags", help="New tags (comma-separated)")
468
462
  def edit(command_id: str, name: str, description: str, group: str, tags: str):
469
- """Edit a command"""
463
+ """Edit a command."""
470
464
  client = DaemonClient()
471
465
 
472
466
  try:
@@ -498,7 +492,7 @@ def edit(command_id: str, name: str, description: str, group: str, tags: str):
498
492
 
499
493
  @client.command()
500
494
  def groups():
501
- """List all command groups"""
495
+ """List all command groups."""
502
496
  client = DaemonClient()
503
497
 
504
498
  try: