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.
- {xcorecli-1.1.0 → xcorecli-1.1.1}/PKG-INFO +1 -1
- {xcorecli-1.1.0 → xcorecli-1.1.1}/pyproject.toml +1 -1
- {xcorecli-1.1.0 → xcorecli-1.1.1}/uv.lock +1 -1
- {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/manager/cli.py +74 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/.github/workflows/publish.yml +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/.gitignore +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/.python-version +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/.vscode/configurationCache.log +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/.vscode/dryrun.log +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/.vscode/settings.json +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/.vscode/targets.log +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/README.md +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/docs/commands/health.md +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/docs/commands/init.md +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/docs/config/index.md +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/docs/deploy/index.md +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/docs/getting-started/auth.md +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/docs/getting-started/configuration.md +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/docs/getting-started/install.md +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/docs/index.md +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/docs/manager/index.md +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/docs/manager/monitoring.md +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/docs/manager/services.md +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/docs/migration/index.md +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/docs/plugin/index.md +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/docs/plugin/install.md +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/docs/plugin/local.md +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/docs/plugin/marketplace.md +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/docs/plugin/runtime.md +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/docs/plugin/security.md +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/docs/plugin/update.md +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/docs/reference.md +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/docs/sandbox/index.md +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/docs/worker/index.md +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/docs/worker/process.md +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/makefile +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/mkdocs.yml +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/__init__.py +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/_credentials.py +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/_run.py +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/_xcore.py +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/config/__init__.py +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/config/cli.py +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/config/runtime.py +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/deploy/__init__.py +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/deploy/cli.py +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/deploy/config.py +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/deploy/generate.py +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/deploy/runner.py +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/init/__init__.py +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/init/manager.py +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/init/upgrade.py +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/main.py +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/manager/__init__.py +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/marketplace/__init__.py +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/marketplace/cli.py +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/migrations/__init__.py +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/migrations/cli.py +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/migrations/runtime.py +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/plugin/__init__.py +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/plugin/cli.py +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/plugin/install_commands.py +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/plugin/local_commands.py +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/plugin/marketplace_commands.py +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/plugin/runtime_commands.py +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/plugin/scaffold.py +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/plugin/security_commands.py +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/plugin/shared.py +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/plugin/update_commands.py +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/sandbox/__init__.py +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/sandbox/cli.py +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/worker/__init__.py +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/worker/cli.py +0 -0
- {xcorecli-1.1.0 → xcorecli-1.1.1}/xcli/worker/worker.py +0 -0
|
@@ -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
|
|
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
|