wasm-cli 0.15.0__tar.gz → 0.15.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. {wasm_cli-0.15.0/src/wasm_cli.egg-info → wasm_cli-0.15.2}/PKG-INFO +1 -1
  2. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/pyproject.toml +1 -1
  3. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/setup.py +25 -2
  4. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/__init__.py +1 -1
  5. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/cli/commands/webapp.py +12 -5
  6. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/core/logger.py +20 -2
  7. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/deployers/base.py +5 -3
  8. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/deployers/docker_compose.py +31 -1
  9. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/deployers/python.py +3 -2
  10. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/managers/base_manager.py +4 -8
  11. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/web/jobs.py +26 -19
  12. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/web/server.py +12 -11
  13. {wasm_cli-0.15.0 → wasm_cli-0.15.2/src/wasm_cli.egg-info}/PKG-INFO +1 -1
  14. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/LICENSE +0 -0
  15. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/MANIFEST.in +0 -0
  16. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/README.md +0 -0
  17. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/docs/MONITOR.md +0 -0
  18. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/docs/OBS_SETUP.md +0 -0
  19. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/docs/assets/logo.png +0 -0
  20. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/docs/assets/logo_bg.png +0 -0
  21. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/man/wasm.1 +0 -0
  22. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/setup.cfg +0 -0
  23. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/__main__.py +0 -0
  24. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/cli/__init__.py +0 -0
  25. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/cli/commands/__init__.py +0 -0
  26. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/cli/commands/backup.py +0 -0
  27. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/cli/commands/cert.py +0 -0
  28. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/cli/commands/config.py +0 -0
  29. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/cli/commands/db.py +0 -0
  30. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/cli/commands/env.py +0 -0
  31. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/cli/commands/health.py +0 -0
  32. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/cli/commands/monitor.py +0 -0
  33. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/cli/commands/service.py +0 -0
  34. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/cli/commands/setup.py +0 -0
  35. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/cli/commands/site.py +0 -0
  36. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/cli/commands/store.py +0 -0
  37. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/cli/commands/version.py +0 -0
  38. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/cli/commands/web.py +0 -0
  39. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/cli/interactive.py +0 -0
  40. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/cli/parser.py +0 -0
  41. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/completions/__init__.py +0 -0
  42. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/completions/_wasm +0 -0
  43. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/completions/wasm.bash +0 -0
  44. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/completions/wasm.fish +0 -0
  45. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/core/__init__.py +0 -0
  46. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/core/config.py +0 -0
  47. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/core/dependencies.py +0 -0
  48. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/core/exceptions.py +0 -0
  49. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/core/store.py +0 -0
  50. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/core/update_checker.py +0 -0
  51. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/core/utils.py +0 -0
  52. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/deployers/__init__.py +0 -0
  53. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/deployers/helpers/__init__.py +0 -0
  54. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/deployers/helpers/env_manager.py +0 -0
  55. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/deployers/helpers/nginx_config.py +0 -0
  56. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/deployers/helpers/package_manager.py +0 -0
  57. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/deployers/helpers/path_resolver.py +0 -0
  58. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/deployers/helpers/prisma.py +0 -0
  59. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/deployers/helpers/turbo.py +0 -0
  60. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/deployers/helpers/workspace.py +0 -0
  61. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/deployers/monorepo.py +0 -0
  62. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/deployers/nextjs.py +0 -0
  63. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/deployers/nodejs.py +0 -0
  64. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/deployers/registry.py +0 -0
  65. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/deployers/static.py +0 -0
  66. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/deployers/vite.py +0 -0
  67. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/main.py +0 -0
  68. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/managers/__init__.py +0 -0
  69. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/managers/apache_manager.py +0 -0
  70. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/managers/backup_manager.py +0 -0
  71. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/managers/backup_scheduler.py +0 -0
  72. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/managers/cert_manager.py +0 -0
  73. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/managers/database/__init__.py +0 -0
  74. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/managers/database/base.py +0 -0
  75. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/managers/database/mongodb.py +0 -0
  76. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/managers/database/mysql.py +0 -0
  77. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/managers/database/postgres.py +0 -0
  78. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/managers/database/redis.py +0 -0
  79. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/managers/database/registry.py +0 -0
  80. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/managers/nginx_manager.py +0 -0
  81. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/managers/service_manager.py +0 -0
  82. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/managers/source_manager.py +0 -0
  83. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/monitor/__init__.py +0 -0
  84. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/monitor/ai_analyzer.py +0 -0
  85. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/monitor/email_notifier.py +0 -0
  86. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/monitor/process_monitor.py +0 -0
  87. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/monitor/threat_store.py +0 -0
  88. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/templates/__init__.py +0 -0
  89. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/templates/apache/proxy.conf.j2 +0 -0
  90. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/templates/apache/static.conf.j2 +0 -0
  91. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/templates/nginx/advanced.conf.j2 +0 -0
  92. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/templates/nginx/monorepo.conf.j2 +0 -0
  93. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/templates/nginx/proxy.conf.j2 +0 -0
  94. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/templates/nginx/static.conf.j2 +0 -0
  95. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/templates/systemd/app.service.j2 +0 -0
  96. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/templates/systemd/backup-service.j2 +0 -0
  97. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/templates/systemd/backup-timer.j2 +0 -0
  98. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/templates/systemd/docker-compose.service.j2 +0 -0
  99. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/validators/__init__.py +0 -0
  100. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/validators/domain.py +0 -0
  101. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/validators/port.py +0 -0
  102. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/validators/source.py +0 -0
  103. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/validators/ssh.py +0 -0
  104. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/web/__init__.py +0 -0
  105. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/web/api/__init__.py +0 -0
  106. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/web/api/apps.py +0 -0
  107. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/web/api/auth.py +0 -0
  108. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/web/api/backups.py +0 -0
  109. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/web/api/certs.py +0 -0
  110. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/web/api/config.py +0 -0
  111. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/web/api/databases.py +0 -0
  112. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/web/api/jobs.py +0 -0
  113. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/web/api/monitor.py +0 -0
  114. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/web/api/router.py +0 -0
  115. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/web/api/services.py +0 -0
  116. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/web/api/sites.py +0 -0
  117. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/web/api/system.py +0 -0
  118. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/web/auth.py +0 -0
  119. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/web/static/css/main.css +0 -0
  120. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/web/static/index.html +0 -0
  121. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/web/static/js/components/cards.js +0 -0
  122. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/web/static/js/components/jobs.js +0 -0
  123. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/web/static/js/components/metrics.js +0 -0
  124. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/web/static/js/components/skeleton.js +0 -0
  125. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/web/static/js/core/api.js +0 -0
  126. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/web/static/js/core/dialogs.js +0 -0
  127. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/web/static/js/core/notifications.js +0 -0
  128. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/web/static/js/core/router.js +0 -0
  129. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/web/static/js/core/search.js +0 -0
  130. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/web/static/js/core/shortcuts.js +0 -0
  131. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/web/static/js/core/theme.js +0 -0
  132. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/web/static/js/core/ui.js +0 -0
  133. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/web/static/js/core/websocket.js +0 -0
  134. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/web/static/js/main.js +0 -0
  135. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/web/static/js/pages/apps.js +0 -0
  136. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/web/static/js/pages/backups.js +0 -0
  137. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/web/static/js/pages/certs.js +0 -0
  138. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/web/static/js/pages/config.js +0 -0
  139. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/web/static/js/pages/dashboard.js +0 -0
  140. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/web/static/js/pages/databases.js +0 -0
  141. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/web/static/js/pages/jobs.js +0 -0
  142. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/web/static/js/pages/logs.js +0 -0
  143. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/web/static/js/pages/monitor.js +0 -0
  144. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/web/static/js/pages/services.js +0 -0
  145. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/web/static/js/pages/sites.js +0 -0
  146. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/web/static/login.html +0 -0
  147. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/web/static/logo.png +0 -0
  148. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/web/static/logo.webp +0 -0
  149. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/web/websockets/__init__.py +0 -0
  150. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm/web/websockets/router.py +0 -0
  151. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm_cli.egg-info/SOURCES.txt +0 -0
  152. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm_cli.egg-info/dependency_links.txt +0 -0
  153. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm_cli.egg-info/entry_points.txt +0 -0
  154. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm_cli.egg-info/requires.txt +0 -0
  155. {wasm_cli-0.15.0 → wasm_cli-0.15.2}/src/wasm_cli.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wasm-cli
3
- Version: 0.15.0
3
+ Version: 0.15.2
4
4
  Summary: Web App System Management - Deploy and manage web applications on Linux servers
5
5
  Author: Yago López Prado
6
6
  Author-email: Yago López Prado <yago.lopez.adeje@gmail.com>
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "wasm-cli"
7
- version = "0.15.0"
7
+ version = "0.15.2"
8
8
  description = "Web App System Management - Deploy and manage web applications on Linux servers"
9
9
  readme = "README.md"
10
10
  license = { text = "WASM-NCSAL" }
@@ -9,7 +9,7 @@ from setuptools import setup, find_packages
9
9
 
10
10
  setup(
11
11
  name="wasm-cli",
12
- version="0.15.0",
12
+ version="0.15.2",
13
13
  description="Web App System Management - Deploy and manage web applications on Linux servers",
14
14
  author="Yago López Prado",
15
15
  author_email="yago.lopez.adeje@gmail.com",
@@ -24,10 +24,33 @@ setup(
24
24
  ],
25
25
  extras_require={
26
26
  "interactive": ["inquirer>=3.1.0"],
27
+ "web": [
28
+ "fastapi>=0.109.0",
29
+ "uvicorn[standard]>=0.27.0",
30
+ "python-jose[cryptography]>=3.3.0",
31
+ "passlib[bcrypt]>=1.7.4",
32
+ "psutil>=5.9.0",
33
+ "aiofiles>=23.0.0",
34
+ ],
35
+ "monitor": [
36
+ "psutil>=5.9.0",
37
+ "httpx>=0.25.0",
38
+ ],
39
+ "all": [
40
+ "inquirer>=3.1.0",
41
+ "rich>=13.0",
42
+ "psutil>=5.9.0",
43
+ "httpx>=0.25.0",
44
+ "fastapi>=0.109.0",
45
+ "uvicorn[standard]>=0.27.0",
46
+ "python-jose[cryptography]>=3.3.0",
47
+ "passlib[bcrypt]>=1.7.4",
48
+ "aiofiles>=23.0.0",
49
+ ],
27
50
  },
28
51
  entry_points={
29
52
  "console_scripts": [
30
- "wasm=wasm.main:main",
53
+ "wasm=wasm.main:cli",
31
54
  ],
32
55
  },
33
56
  data_files=[
@@ -8,7 +8,7 @@ WASM - Web App System Management
8
8
  A robust CLI tool for deploying and managing web applications on Linux servers.
9
9
  """
10
10
 
11
- __version__ = "0.15.0"
11
+ __version__ = "0.15.2"
12
12
  __author__ = "Yago López Prado"
13
13
  __license__ = "WASM-NCSAL"
14
14
 
@@ -616,12 +616,19 @@ def _handle_update(args: Namespace) -> int:
616
616
 
617
617
  # Step 3: Detect app type and configure deployer
618
618
  logger.step(3, total_steps, "Detecting application type")
619
- app_type = detect_app_type(app_path, verbose=args.verbose)
620
- if not app_type:
621
- app_type = "nodejs"
622
- logger.substep(f"Using default: {app_type}")
623
- else:
619
+
620
+ # Prefer stored app type from database (initial deploy already determined it correctly)
621
+ stored_type = app.app_type if app else None
622
+ if stored_type and stored_type != "unknown":
623
+ app_type = stored_type
624
624
  logger.substep(f"Detected: {app_type}")
625
+ else:
626
+ app_type = detect_app_type(app_path, verbose=args.verbose)
627
+ if not app_type:
628
+ app_type = "nodejs"
629
+ logger.substep(f"Using default: {app_type}")
630
+ else:
631
+ logger.substep(f"Detected: {app_type}")
625
632
 
626
633
  # Handle monorepo updates with dedicated flow
627
634
  if app_type == "monorepo":
@@ -187,16 +187,34 @@ class Logger:
187
187
  def debug(self, message: str) -> None:
188
188
  """
189
189
  Log a debug message (only shown in verbose mode).
190
-
190
+
191
191
  Args:
192
192
  message: Debug message.
193
193
  """
194
194
  if not self.verbose:
195
195
  return
196
-
196
+
197
197
  prefix = self._colorize("[DEBUG]", Colors.GRAY)
198
198
  msg = self._colorize(message, Colors.GRAY)
199
199
  self._write(f" {prefix} {msg}")
200
+
201
+ def command_output(self, stdout: str, stderr: str) -> None:
202
+ """
203
+ Log command stdout/stderr (only shown in verbose mode).
204
+
205
+ Args:
206
+ stdout: Command standard output.
207
+ stderr: Command standard error output.
208
+ """
209
+ if not self.verbose:
210
+ return
211
+
212
+ for stream in (stdout, stderr):
213
+ if not stream or not stream.strip():
214
+ continue
215
+ for line in stream.rstrip("\n").split("\n"):
216
+ text = self._colorize(f" {line}", Colors.GRAY)
217
+ self._write(text)
200
218
 
201
219
  def info(self, message: str) -> None:
202
220
  """
@@ -160,18 +160,20 @@ class BaseDeployer(ABC):
160
160
  ):
161
161
  """Run a command and return result."""
162
162
  self.logger.debug(f"Running: {' '.join(command)}")
163
-
163
+
164
164
  # Merge environment variables
165
165
  run_env = self.env_vars.copy()
166
166
  if env:
167
167
  run_env.update(env)
168
-
169
- return run_command(
168
+
169
+ result = run_command(
170
170
  command,
171
171
  cwd=cwd or self.app_path,
172
172
  env=run_env if run_env else None,
173
173
  timeout=timeout,
174
174
  )
175
+ self.logger.command_output(result.stdout, result.stderr)
176
+ return result
175
177
 
176
178
  def _detect_package_manager(self) -> str:
177
179
  """
@@ -105,6 +105,27 @@ class DockerComposeDeployer:
105
105
  self.services: List[DockerComposeService] = []
106
106
  self.compose_path = None
107
107
 
108
+ # Framework config files that indicate docker-compose.yml is likely
109
+ # just for local development (databases, caches, etc.)
110
+ FRAMEWORK_CONFIG_FILES = [
111
+ # Next.js
112
+ "next.config.js", "next.config.mjs", "next.config.ts",
113
+ # Vite
114
+ "vite.config.js", "vite.config.ts", "vite.config.mjs",
115
+ # Angular
116
+ "angular.json",
117
+ # Nuxt
118
+ "nuxt.config.js", "nuxt.config.ts",
119
+ # Svelte
120
+ "svelte.config.js",
121
+ # Astro
122
+ "astro.config.mjs", "astro.config.ts",
123
+ # Remix
124
+ "remix.config.js", "remix.config.ts",
125
+ # Django
126
+ "manage.py",
127
+ ]
128
+
108
129
  @classmethod
109
130
  def detect(cls, path: Path) -> bool:
110
131
  """
@@ -113,7 +134,8 @@ class DockerComposeDeployer:
113
134
  Detection priority:
114
135
  - If docker-compose.prod.yml exists -> True (strong signal)
115
136
  - If only docker-compose.yml exists AND monorepo signals -> False
116
- - If only docker-compose.yml exists without monorepo -> True
137
+ - If only docker-compose.yml exists AND framework config files -> False
138
+ - If only docker-compose.yml exists without other signals -> True
117
139
 
118
140
  Args:
119
141
  path: Path to check.
@@ -146,6 +168,14 @@ class DockerComposeDeployer:
146
168
  if app_count >= 2:
147
169
  return False
148
170
 
171
+ # Check for framework config files - if present, docker-compose.yml
172
+ # is likely just for local development (databases, caches, etc.)
173
+ has_framework = any(
174
+ (path / f).exists() for f in cls.FRAMEWORK_CONFIG_FILES
175
+ )
176
+ if has_framework:
177
+ return False
178
+
149
179
  return True
150
180
 
151
181
  def configure(
@@ -2,6 +2,7 @@
2
2
  Python deployer for WASM.
3
3
  """
4
4
 
5
+ import os
5
6
  from pathlib import Path
6
7
  from typing import Dict, List
7
8
  import re
@@ -80,7 +81,8 @@ class PythonDeployer(BaseDeployer):
80
81
  # Check for common patterns
81
82
  if self.framework == "django":
82
83
  # Look for wsgi.py or asgi.py
83
- for root, dirs, files in (self.app_path).walk():
84
+ for root, dirs, files in os.walk(self.app_path):
85
+ root = Path(root)
84
86
  if "wsgi.py" in files:
85
87
  # Get module path
86
88
  rel_path = root.relative_to(self.app_path)
@@ -90,7 +92,6 @@ class PythonDeployer(BaseDeployer):
90
92
  rel_path = root.relative_to(self.app_path)
91
93
  module = str(rel_path).replace("/", ".")
92
94
  asgi_app = f"{module}.asgi:application"
93
- break
94
95
 
95
96
  elif self.framework == "flask":
96
97
  # Check for app.py, main.py, or __init__.py
@@ -57,10 +57,8 @@ class BaseManager(ABC):
57
57
  """
58
58
  self.logger.debug(f"Running: {' '.join(command)}")
59
59
  result = run_command(command, cwd=cwd, env=env, timeout=timeout)
60
-
61
- if not result.success:
62
- self.logger.debug(f"Command failed: {result.stderr}")
63
-
60
+ self.logger.command_output(result.stdout, result.stderr)
61
+
64
62
  return result
65
63
 
66
64
  def _run_sudo(
@@ -84,10 +82,8 @@ class BaseManager(ABC):
84
82
  """
85
83
  self.logger.debug(f"Running (sudo): {' '.join(command)}")
86
84
  result = run_command_sudo(command, cwd=cwd, env=env, timeout=timeout)
87
-
88
- if not result.success:
89
- self.logger.debug(f"Command failed: {result.stderr}")
90
-
85
+ self.logger.command_output(result.stdout, result.stderr)
86
+
91
87
  return result
92
88
 
93
89
  @abstractmethod
@@ -17,6 +17,13 @@ from enum import Enum
17
17
  from typing import Dict, List, Optional, Callable, Any
18
18
  from pathlib import Path
19
19
 
20
+ from wasm.core.exceptions import (
21
+ BackupError,
22
+ CertificateError,
23
+ DeploymentError,
24
+ RollbackError,
25
+ )
26
+
20
27
 
21
28
  class JobStatus(str, Enum):
22
29
  """Job execution status."""
@@ -477,12 +484,12 @@ def deploy_app_job(
477
484
 
478
485
  if job_context.is_cancelled:
479
486
  process.terminate()
480
- raise Exception("Job cancelled by user")
481
-
487
+ raise DeploymentError("Job cancelled by user")
488
+
482
489
  process.wait()
483
-
490
+
484
491
  if process.returncode != 0:
485
- raise Exception(f"Deployment failed with exit code {process.returncode}")
492
+ raise DeploymentError(f"Deployment failed with exit code {process.returncode}")
486
493
 
487
494
  job_context.update("Deployment complete", 100)
488
495
 
@@ -523,10 +530,10 @@ def update_app_job(
523
530
  process.wait()
524
531
 
525
532
  if process.returncode != 0:
526
- raise Exception(f"Update failed with exit code {process.returncode}")
527
-
533
+ raise DeploymentError(f"Update failed with exit code {process.returncode}")
534
+
528
535
  job_context.update("Update complete", 100)
529
-
536
+
530
537
  return {"domain": domain, "status": "updated"}
531
538
 
532
539
 
@@ -566,10 +573,10 @@ def delete_app_job(
566
573
  process.wait()
567
574
 
568
575
  if process.returncode != 0:
569
- raise Exception(f"Deletion failed with exit code {process.returncode}")
570
-
576
+ raise DeploymentError(f"Deletion failed with exit code {process.returncode}")
577
+
571
578
  job_context.update("Deletion complete", 100)
572
-
579
+
573
580
  return {"domain": domain, "status": "deleted"}
574
581
 
575
582
 
@@ -605,10 +612,10 @@ def backup_app_job(
605
612
  process.wait()
606
613
 
607
614
  if process.returncode != 0:
608
- raise Exception(f"Backup failed with exit code {process.returncode}")
609
-
615
+ raise BackupError(f"Backup failed with exit code {process.returncode}")
616
+
610
617
  job_context.update("Backup complete", 100)
611
-
618
+
612
619
  return {"domain": domain, "status": "backup_created", "path": backup_path}
613
620
 
614
621
 
@@ -644,10 +651,10 @@ def rollback_app_job(
644
651
  process.wait()
645
652
 
646
653
  if process.returncode != 0:
647
- raise Exception(f"Rollback failed with exit code {process.returncode}")
648
-
654
+ raise RollbackError(f"Rollback failed with exit code {process.returncode}")
655
+
649
656
  job_context.update("Rollback complete", 100)
650
-
657
+
651
658
  return {"domain": domain, "status": "rolled_back"}
652
659
 
653
660
 
@@ -683,8 +690,8 @@ def cert_create_job(
683
690
  process.wait()
684
691
 
685
692
  if process.returncode != 0:
686
- raise Exception(f"Certificate creation failed with exit code {process.returncode}")
687
-
693
+ raise CertificateError(f"Certificate creation failed with exit code {process.returncode}")
694
+
688
695
  job_context.update("Certificate created", 100)
689
-
696
+
690
697
  return {"domain": domain, "status": "certificate_created"}
@@ -6,6 +6,7 @@ API routing, and static file serving.
6
6
  """
7
7
 
8
8
  import asyncio
9
+ import logging
9
10
  import os
10
11
  import signal
11
12
  import socket
@@ -13,6 +14,8 @@ from contextlib import asynccontextmanager
13
14
  from pathlib import Path
14
15
  from typing import Optional
15
16
 
17
+ logger = logging.getLogger(__name__)
18
+
16
19
  from fastapi import FastAPI, Request, Response, HTTPException, Depends
17
20
  from fastapi.middleware.cors import CORSMiddleware
18
21
  from fastapi.responses import HTMLResponse, JSONResponse, FileResponse
@@ -417,18 +420,16 @@ def run_server(
417
420
 
418
421
  if show_token:
419
422
  local_ip = get_local_ip() if host == "0.0.0.0" else host
420
- print("\n" + "=" * 60)
421
- print("🌐 WASM Web Interface")
423
+ print()
422
424
  print("=" * 60)
423
- print(f"\n🔐 Access Token: {master_token}")
424
- print(f"\n📡 Server: http://{local_ip}:{port}")
425
- print(f"🔗 Quick Login: http://{local_ip}:{port}/login?token={master_token}")
426
- print("\n⚠️ Keep this token secure! It grants full access to WASM.")
427
- print("=" * 60 + "\n")
428
-
429
- # Flush stdout to ensure token is displayed before uvicorn starts
430
- import sys
431
- sys.stdout.flush()
425
+ print("WASM Web Interface")
426
+ print("=" * 60)
427
+ print(f"Access Token: {master_token}")
428
+ print(f"Server: http://{local_ip}:{port}")
429
+ print(f"Quick Login: http://{local_ip}:{port}/login?token={master_token}")
430
+ print("Keep this token secure! It grants full access to WASM.")
431
+ print("=" * 60)
432
+ print(flush=True)
432
433
 
433
434
  # Run server
434
435
  uvicorn.run(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wasm-cli
3
- Version: 0.15.0
3
+ Version: 0.15.2
4
4
  Summary: Web App System Management - Deploy and manage web applications on Linux servers
5
5
  Author: Yago López Prado
6
6
  Author-email: Yago López Prado <yago.lopez.adeje@gmail.com>
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes