xcorecli 1.1.0__tar.gz → 1.1.1__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 (74) hide show
  1. {xcorecli-1.1.0 → xcorecli-1.1.1}/PKG-INFO +1 -1
  2. {xcorecli-1.1.0 → xcorecli-1.1.1}/pyproject.toml +1 -1
  3. {xcorecli-1.1.0 → xcorecli-1.1.1}/uv.lock +1 -1
  4. {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/manager/cli.py +74 -0
  5. {xcorecli-1.1.0 → xcorecli-1.1.1}/.github/workflows/publish.yml +0 -0
  6. {xcorecli-1.1.0 → xcorecli-1.1.1}/.gitignore +0 -0
  7. {xcorecli-1.1.0 → xcorecli-1.1.1}/.python-version +0 -0
  8. {xcorecli-1.1.0 → xcorecli-1.1.1}/.vscode/configurationCache.log +0 -0
  9. {xcorecli-1.1.0 → xcorecli-1.1.1}/.vscode/dryrun.log +0 -0
  10. {xcorecli-1.1.0 → xcorecli-1.1.1}/.vscode/settings.json +0 -0
  11. {xcorecli-1.1.0 → xcorecli-1.1.1}/.vscode/targets.log +0 -0
  12. {xcorecli-1.1.0 → xcorecli-1.1.1}/README.md +0 -0
  13. {xcorecli-1.1.0 → xcorecli-1.1.1}/docs/commands/health.md +0 -0
  14. {xcorecli-1.1.0 → xcorecli-1.1.1}/docs/commands/init.md +0 -0
  15. {xcorecli-1.1.0 → xcorecli-1.1.1}/docs/config/index.md +0 -0
  16. {xcorecli-1.1.0 → xcorecli-1.1.1}/docs/deploy/index.md +0 -0
  17. {xcorecli-1.1.0 → xcorecli-1.1.1}/docs/getting-started/auth.md +0 -0
  18. {xcorecli-1.1.0 → xcorecli-1.1.1}/docs/getting-started/configuration.md +0 -0
  19. {xcorecli-1.1.0 → xcorecli-1.1.1}/docs/getting-started/install.md +0 -0
  20. {xcorecli-1.1.0 → xcorecli-1.1.1}/docs/index.md +0 -0
  21. {xcorecli-1.1.0 → xcorecli-1.1.1}/docs/manager/index.md +0 -0
  22. {xcorecli-1.1.0 → xcorecli-1.1.1}/docs/manager/monitoring.md +0 -0
  23. {xcorecli-1.1.0 → xcorecli-1.1.1}/docs/manager/services.md +0 -0
  24. {xcorecli-1.1.0 → xcorecli-1.1.1}/docs/migration/index.md +0 -0
  25. {xcorecli-1.1.0 → xcorecli-1.1.1}/docs/plugin/index.md +0 -0
  26. {xcorecli-1.1.0 → xcorecli-1.1.1}/docs/plugin/install.md +0 -0
  27. {xcorecli-1.1.0 → xcorecli-1.1.1}/docs/plugin/local.md +0 -0
  28. {xcorecli-1.1.0 → xcorecli-1.1.1}/docs/plugin/marketplace.md +0 -0
  29. {xcorecli-1.1.0 → xcorecli-1.1.1}/docs/plugin/runtime.md +0 -0
  30. {xcorecli-1.1.0 → xcorecli-1.1.1}/docs/plugin/security.md +0 -0
  31. {xcorecli-1.1.0 → xcorecli-1.1.1}/docs/plugin/update.md +0 -0
  32. {xcorecli-1.1.0 → xcorecli-1.1.1}/docs/reference.md +0 -0
  33. {xcorecli-1.1.0 → xcorecli-1.1.1}/docs/sandbox/index.md +0 -0
  34. {xcorecli-1.1.0 → xcorecli-1.1.1}/docs/worker/index.md +0 -0
  35. {xcorecli-1.1.0 → xcorecli-1.1.1}/docs/worker/process.md +0 -0
  36. {xcorecli-1.1.0 → xcorecli-1.1.1}/makefile +0 -0
  37. {xcorecli-1.1.0 → xcorecli-1.1.1}/mkdocs.yml +0 -0
  38. {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/__init__.py +0 -0
  39. {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/_credentials.py +0 -0
  40. {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/_run.py +0 -0
  41. {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/_xcore.py +0 -0
  42. {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/config/__init__.py +0 -0
  43. {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/config/cli.py +0 -0
  44. {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/config/runtime.py +0 -0
  45. {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/deploy/__init__.py +0 -0
  46. {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/deploy/cli.py +0 -0
  47. {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/deploy/config.py +0 -0
  48. {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/deploy/generate.py +0 -0
  49. {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/deploy/runner.py +0 -0
  50. {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/init/__init__.py +0 -0
  51. {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/init/manager.py +0 -0
  52. {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/init/upgrade.py +0 -0
  53. {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/main.py +0 -0
  54. {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/manager/__init__.py +0 -0
  55. {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/marketplace/__init__.py +0 -0
  56. {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/marketplace/cli.py +0 -0
  57. {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/migrations/__init__.py +0 -0
  58. {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/migrations/cli.py +0 -0
  59. {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/migrations/runtime.py +0 -0
  60. {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/plugin/__init__.py +0 -0
  61. {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/plugin/cli.py +0 -0
  62. {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/plugin/install_commands.py +0 -0
  63. {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/plugin/local_commands.py +0 -0
  64. {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/plugin/marketplace_commands.py +0 -0
  65. {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/plugin/runtime_commands.py +0 -0
  66. {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/plugin/scaffold.py +0 -0
  67. {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/plugin/security_commands.py +0 -0
  68. {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/plugin/shared.py +0 -0
  69. {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/plugin/update_commands.py +0 -0
  70. {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/sandbox/__init__.py +0 -0
  71. {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/sandbox/cli.py +0 -0
  72. {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/worker/__init__.py +0 -0
  73. {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/worker/cli.py +0 -0
  74. {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/worker/worker.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: xcorecli
3
- Version: 1.1.0
3
+ Version: 1.1.1
4
4
  Summary: CLI for xcore — configuration, plugins, deployment
5
5
  Requires-Python: >=3.12
6
6
  Requires-Dist: alembic>=1.18.0
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "xcorecli"
7
- version = "1.1.0"
7
+ version = "1.1.1"
8
8
  description = "CLI for xcore — configuration, plugins, deployment"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -773,7 +773,7 @@ wheels = [
773
773
 
774
774
  [[package]]
775
775
  name = "xcorecli"
776
- version = "1.1.0"
776
+ version = "1.1.1"
777
777
  source = { editable = "." }
778
778
  dependencies = [
779
779
  { name = "alembic" },
@@ -138,6 +138,57 @@ def _build_resources_table() -> Table:
138
138
  except (psutil.NoSuchProcess, psutil.AccessDenied):
139
139
  pass
140
140
 
141
+ # Plugins en mode "trusted"/"sandboxed(threaded)" tournent DANS le
142
+ # process API principal (pas de sous-process dédié) — donc pas de PID
143
+ # à eux. Plutôt que d'afficher des tirets, on retombe sur le process
144
+ # API (retrouvé via le PID file écrit par `xcli manager start`, ou à
145
+ # défaut par scan cmdline) et on l'affiche comme ressource *partagée*.
146
+ main_proc: psutil.Process | None = None
147
+ try:
148
+ from xcli.worker.worker import PID_API, _is_running, _read_pid
149
+
150
+ main_pid = _read_pid(PID_API)
151
+ if main_pid and _is_running(main_pid):
152
+ main_proc = psutil.Process(main_pid)
153
+ except Exception:
154
+ main_proc = None
155
+
156
+ if main_proc is None:
157
+ # Pas de PID file (démarrage en foreground sans --detach, ou
158
+ # process lancé hors xcli) — on cherche le process uvicorn qui
159
+ # sert l'app, en excluant les sandbox workers déjà identifiés.
160
+ sandboxed_pids = {p.pid for p in sandbox_pids.values()}
161
+ for proc in psutil.process_iter(["pid", "cmdline"]):
162
+ if proc.pid in sandboxed_pids:
163
+ continue
164
+ try:
165
+ cmd = proc.info["cmdline"] or []
166
+ if any("uvicorn" in str(c) for c in cmd):
167
+ main_proc = proc
168
+ break
169
+ except (psutil.NoSuchProcess, psutil.AccessDenied):
170
+ pass
171
+
172
+ main_cpu_str = main_mem_str = main_conn_str = "—"
173
+ main_pid_str = "—"
174
+ if main_proc is not None:
175
+ try:
176
+ main_pid_str = str(main_proc.pid)
177
+ cpu = main_proc.cpu_percent(interval=0.05)
178
+ cpu_color = "red" if cpu > 80 else ("yellow" if cpu > 40 else "green")
179
+ main_cpu_str = f"[{cpu_color}]{cpu:.1f}[/{cpu_color}]"
180
+
181
+ mem = main_proc.memory_info().rss / 1024**2
182
+ mem_color = "red" if mem > 400 else ("yellow" if mem > 200 else "magenta")
183
+ main_mem_str = f"[{mem_color}]{mem:.1f}[/{mem_color}]"
184
+
185
+ try:
186
+ main_conn_str = str(len(main_proc.net_connections()))
187
+ except (psutil.AccessDenied, AttributeError):
188
+ main_conn_str = "?"
189
+ except (psutil.NoSuchProcess, psutil.AccessDenied):
190
+ main_proc = None
191
+
141
192
  table = Table(title=f"Plugin Resources [dim]{plugins_root}[/dim]", show_lines=True)
142
193
  table.add_column("Plugin", style="cyan", no_wrap=True)
143
194
  table.add_column("Mode", justify="center")
@@ -196,9 +247,25 @@ def _build_resources_table() -> Table:
196
247
  state_str = "[green]running[/green]" if state == "running" else f"[yellow]{state}[/yellow]"
197
248
  except (psutil.NoSuchProcess, psutil.AccessDenied):
198
249
  state_str = "[red]gone[/red]"
250
+ elif main_proc is not None:
251
+ # Plugin en process partagé (trusted / non-sandboxé) : on
252
+ # affiche les métriques du process API, avec un marqueur "~"
253
+ # pour signaler que c'est une valeur partagée entre plugins,
254
+ # pas exclusive à celui-ci.
255
+ pid_str = f"~{main_pid_str}"
256
+ cpu_str = main_cpu_str
257
+ mem_str = main_mem_str
258
+ conn_str = main_conn_str
259
+ state_str = "[cyan]in-process[/cyan] [dim](partagé)[/dim]"
199
260
 
200
261
  table.add_row(name, mode, pid_str, cpu_str, mem_str, disk_str, conn_str, state_str)
201
262
 
263
+ if main_proc is not None and any(name not in sandbox_pids for name in plugin_names):
264
+ table.caption = (
265
+ "[dim]~PID = process API partagé entre plugins \"in-process (partagé)\" — "
266
+ "CPU/Mem/Net Conn reflètent le process entier, pas ce plugin seul.[/dim]"
267
+ )
268
+
202
269
  return table
203
270
 
204
271
 
@@ -595,12 +662,19 @@ def start(
595
662
 
596
663
  console.print(f"[dim]→ uvicorn {app_path} --host {resolved_host} --port {resolved_port}[/dim]")
597
664
  console.print("[dim]Ctrl+C to stop[/dim]\n")
665
+ PID_DIR.mkdir(parents=True, exist_ok=True)
598
666
  try:
599
667
  proc = subprocess.Popen(cmd)
668
+ # Écrit le PID même en foreground : `xcli manager resources`/`top`
669
+ # dans un autre terminal en a besoin pour retrouver le process API
670
+ # (plugins "trusted" partagent ce process, pas de PID dédié).
671
+ _write_pid(PID_API, proc.pid)
600
672
  proc.wait()
601
673
  except KeyboardInterrupt:
602
674
  proc.terminate()
603
675
  proc.wait()
676
+ finally:
677
+ PID_API.unlink(missing_ok=True)
604
678
 
605
679
 
606
680
  @app.command("stop")
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes