devops-bot-sdk 1.4.146__tar.gz → 1.4.147__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.
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/PKG-INFO +1 -1
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/devops_bot_sdk.egg-info/PKG-INFO +1 -1
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/__init__.py +2 -2
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/ui/service.py +172 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/updater.py +36 -1
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/README.md +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/devops_bot_sdk.egg-info/SOURCES.txt +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/devops_bot_sdk.egg-info/dependency_links.txt +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/devops_bot_sdk.egg-info/entry_points.txt +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/devops_bot_sdk.egg-info/requires.txt +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/devops_bot_sdk.egg-info/top_level.txt +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/pyproject.toml +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/agentd.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/agents/__init__.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/agents/builder.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/agents/chat.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/agents/connectors.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/agents/engines/__init__.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/agents/engines/claude_code.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/agents/engines/http.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/agents/engines/mcp.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/agents/engines/n8n.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/agents/engines/shell.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/agents/integrations.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/agents/inventory.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/agents/library/__init__.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/agents/manifest.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/agents/prompt_studio.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/agents/prompt_template.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/agents/prompt_vars.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/agents/run_log.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/agents/secrets.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/agents/usage.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/agents/varstore.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/cli.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/client.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/collectors/__init__.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/collectors/files.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/collectors/process.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/collectors/screenshot.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/config.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/crucial.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/design_verify/__init__.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/design_verify/assets.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/design_verify/bootstrap.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/design_verify/browser.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/design_verify/compare.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/design_verify/loop.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/exceptions.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/git_ops.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/graphify.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/hooks/__init__.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/hooks/crucial_guard.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/ipc/__init__.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/ipc/electron_bridge.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/ipc/handlers.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/local_exec.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/models/__init__.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/models/envelope.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/models/requests.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/models/responses.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/models/snapshots.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/platform_compat.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/py.typed +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/run_auto.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/sse.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/test.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/test_pipeline.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/ui/__init__.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/ui/api.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/ui/dashboard.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/ui/health.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/ui/ip_allowlist.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/ui/jobs.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/ui/models.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/ui/runner.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/ui/security.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/ui/server.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/ui/setup_manager.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/ui/static/agents.html +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/ui/static/app.js +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/ui/static/custom-agents.html +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/ui/static/default-agents.html +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/ui/static/index.html +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/ui/static/runs.html +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/ui/static/setup.html +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/ui/static/styles.css +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/sdk/ui/static/tickets.html +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/setup.cfg +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/tests/test_agent_chat_features.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/tests/test_agent_prompt_models.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/tests/test_agents_connectors_builder.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/tests/test_git_action.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/tests/test_health.py +0 -0
- {devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/tests/test_updater_extras.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""AgentOS Desktop SDK — thin HTTPS/SSE client for the Electron app.
|
|
2
2
|
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.147
|
|
4
4
|
|
|
5
5
|
Public surface:
|
|
6
6
|
BackendClient.from_config() — create client from ~/.agentos/config.toml
|
|
@@ -30,7 +30,7 @@ Rules:
|
|
|
30
30
|
- All data egress through submit_webhook only
|
|
31
31
|
"""
|
|
32
32
|
|
|
33
|
-
__version__ = "1.4.
|
|
33
|
+
__version__ = "1.4.147" # SINGLE SOURCE OF TRUTH — bump on every change; pyproject,
|
|
34
34
|
__author__ = "AgentOS" # sdk.client.SDK_VERSION and the UI server version all read this.
|
|
35
35
|
|
|
36
36
|
from sdk.client import BackendClient
|
|
@@ -17,6 +17,7 @@ Everything is best-effort and returns ``(ok, message)`` so the caller (the
|
|
|
17
17
|
from __future__ import annotations
|
|
18
18
|
|
|
19
19
|
import os
|
|
20
|
+
import re
|
|
20
21
|
import shutil
|
|
21
22
|
import subprocess
|
|
22
23
|
import sys
|
|
@@ -285,3 +286,174 @@ def restart() -> tuple[bool, str]:
|
|
|
285
286
|
return (rc == 0), (f"restarted systemd service '{SERVICE_NAME}'." if rc == 0
|
|
286
287
|
else out or f"systemctl restart {SERVICE_NAME} failed")
|
|
287
288
|
return False, "no supported service manager found — restart the panel manually (`agentos-ui`)."
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
def _systemd_unit_candidates() -> list[Path]:
|
|
292
|
+
"""Both places a systemd unit can live, system scope first."""
|
|
293
|
+
return [
|
|
294
|
+
Path("/etc/systemd/system") / f"{SERVICE_NAME}.service",
|
|
295
|
+
Path.home() / ".config" / "systemd" / "user" / f"{SERVICE_NAME}.service",
|
|
296
|
+
]
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
def _existing_systemd_unit() -> Path | None:
|
|
300
|
+
"""The installed unit file, checking BOTH system and user scope regardless of
|
|
301
|
+
the current privilege — so a non-root ``agentos-auto update`` still finds a
|
|
302
|
+
system service installed via ``sudo agentos-ui install`` (and vice-versa)."""
|
|
303
|
+
for p in _systemd_unit_candidates():
|
|
304
|
+
try:
|
|
305
|
+
if p.exists():
|
|
306
|
+
return p
|
|
307
|
+
except OSError:
|
|
308
|
+
continue
|
|
309
|
+
return None
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
def _service_definition_path() -> Path:
|
|
313
|
+
"""On-disk service definition — an EXISTING unit if there is one (either scope),
|
|
314
|
+
else the path we would CREATE at the current privilege."""
|
|
315
|
+
if IS_WINDOWS: # schtasks has no file; handled separately
|
|
316
|
+
return Path()
|
|
317
|
+
if IS_MAC:
|
|
318
|
+
return _mac_plist_path()
|
|
319
|
+
existing = _existing_systemd_unit()
|
|
320
|
+
if existing:
|
|
321
|
+
return existing
|
|
322
|
+
is_root = hasattr(os, "geteuid") and os.geteuid() == 0
|
|
323
|
+
base = Path("/etc/systemd/system") if is_root else Path.home() / ".config" / "systemd" / "user"
|
|
324
|
+
return base / f"{SERVICE_NAME}.service"
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
def _needs_root_for_existing() -> bool:
|
|
328
|
+
"""True when a SYSTEM unit is installed but we're not root — so we must not
|
|
329
|
+
silently create a conflicting *user* unit; the caller should ask for sudo."""
|
|
330
|
+
if IS_WINDOWS or IS_MAC:
|
|
331
|
+
return False
|
|
332
|
+
is_root = hasattr(os, "geteuid") and os.geteuid() == 0
|
|
333
|
+
existing = _existing_systemd_unit()
|
|
334
|
+
return (existing is not None
|
|
335
|
+
and existing.parent == Path("/etc/systemd/system")
|
|
336
|
+
and not is_root)
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
def is_installed() -> bool:
|
|
340
|
+
"""True when a managed agentos-ui service/unit exists (any platform, any scope).
|
|
341
|
+
|
|
342
|
+
Best-effort and never raises — used by the updater to decide whether an upgrade
|
|
343
|
+
should create, regenerate, or restart the service.
|
|
344
|
+
"""
|
|
345
|
+
try:
|
|
346
|
+
if IS_WINDOWS:
|
|
347
|
+
rc, _ = _run(["schtasks", "/Query", "/TN", WIN_TASK])
|
|
348
|
+
return rc == 0
|
|
349
|
+
if IS_MAC:
|
|
350
|
+
return _mac_plist_path().exists()
|
|
351
|
+
return _existing_systemd_unit() is not None
|
|
352
|
+
except Exception: # noqa: BLE001
|
|
353
|
+
return False
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
def _is_active() -> bool:
|
|
357
|
+
"""True when the managed service is currently running (read-only query)."""
|
|
358
|
+
try:
|
|
359
|
+
if IS_WINDOWS:
|
|
360
|
+
_, out = _run(["schtasks", "/Query", "/TN", WIN_TASK, "/FO", "LIST", "/V"])
|
|
361
|
+
return "Running" in out
|
|
362
|
+
if IS_MAC:
|
|
363
|
+
rc, out = _run(["launchctl", "list", _MAC_LABEL])
|
|
364
|
+
return rc == 0 and bool(out.strip())
|
|
365
|
+
existing = _existing_systemd_unit()
|
|
366
|
+
user = existing is not None and existing.parent.name == "user"
|
|
367
|
+
sysctl = ["systemctl", "--user"] if user else ["systemctl"]
|
|
368
|
+
_, out = _run([*sysctl, "is-active", SERVICE_NAME])
|
|
369
|
+
return out.strip() == "active"
|
|
370
|
+
except Exception: # noqa: BLE001
|
|
371
|
+
return False
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
def _installed_host_port() -> tuple[str, int]:
|
|
375
|
+
"""Read the host/port the service was installed with, so a refresh preserves
|
|
376
|
+
them instead of resetting to the install() defaults. Falls back to 0.0.0.0:8765.
|
|
377
|
+
"""
|
|
378
|
+
host, port = "0.0.0.0", 8765
|
|
379
|
+
text = ""
|
|
380
|
+
try:
|
|
381
|
+
if IS_WINDOWS:
|
|
382
|
+
_, text = _run(["schtasks", "/Query", "/TN", WIN_TASK, "/V", "/FO", "LIST"])
|
|
383
|
+
else:
|
|
384
|
+
p = _service_definition_path()
|
|
385
|
+
text = p.read_text() if p and p.exists() else ""
|
|
386
|
+
except Exception: # noqa: BLE001
|
|
387
|
+
text = ""
|
|
388
|
+
clean = re.sub(r"<[^>]+>", " ", text) # flatten plist <string> tags to spaces
|
|
389
|
+
m = re.search(r"--host\s+(\S+)", clean)
|
|
390
|
+
if m:
|
|
391
|
+
host = m.group(1).strip().strip('"')
|
|
392
|
+
m = re.search(r"--port\s+(\d+)", clean)
|
|
393
|
+
if m:
|
|
394
|
+
port = int(m.group(1))
|
|
395
|
+
return host, port
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
def refresh() -> tuple[bool, str]:
|
|
399
|
+
"""Regenerate the service definition and restart it after an SDK upgrade.
|
|
400
|
+
|
|
401
|
+
``agentos-auto update`` only pip-upgrades the package; the on-disk unit and the
|
|
402
|
+
running process are untouched. So a change to the generated unit (e.g. the
|
|
403
|
+
baked-in PATH that lets the service find the ``claude`` CLI) or to the code
|
|
404
|
+
never takes effect until this runs. Regenerating rewrites the unit with the
|
|
405
|
+
upgraded SDK's definition (preserving the installed host/port), and the restart
|
|
406
|
+
both applies the new unit and loads the new code.
|
|
407
|
+
|
|
408
|
+
No-op returning ``(False, msg)`` when no managed service is installed, so a
|
|
409
|
+
manually-launched panel is left alone.
|
|
410
|
+
"""
|
|
411
|
+
if not is_installed():
|
|
412
|
+
return False, "no managed service installed — nothing to refresh."
|
|
413
|
+
if _needs_root_for_existing():
|
|
414
|
+
return False, ("the panel runs as a system service — re-run with sudo "
|
|
415
|
+
"(`sudo agentos-ui install`) to apply the update.")
|
|
416
|
+
host, port = _installed_host_port()
|
|
417
|
+
ok, msg = install(host, port) # rewrites unit/plist/task + daemon-reload
|
|
418
|
+
if not ok:
|
|
419
|
+
return False, f"could not regenerate service: {msg}"
|
|
420
|
+
# `enable --now` / launchctl load won't restart an ALREADY-running unit, so
|
|
421
|
+
# force a restart to apply the regenerated definition and load the new code.
|
|
422
|
+
rok, rmsg = restart()
|
|
423
|
+
return (True, f"service refreshed ({host}:{port}); {rmsg}" if rok
|
|
424
|
+
else f"service definition regenerated ({host}:{port}) but restart needs attention: {rmsg}")
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+
def _service_disabled() -> bool:
|
|
428
|
+
return os.environ.get("AGENTOS_NO_SERVICE", "").strip().lower() in ("1", "true", "yes", "on")
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
def ensure(restart_running: bool = False) -> tuple[bool, str]:
|
|
432
|
+
"""Make sure the panel service EXISTS and is running the current SDK.
|
|
433
|
+
|
|
434
|
+
This is what lets ``agentos-auto update`` yield a working 24/7 service without a
|
|
435
|
+
separate ``agentos-ui install`` step:
|
|
436
|
+
|
|
437
|
+
* not installed → create it (``install``)
|
|
438
|
+
* installed + code changed → ``refresh`` (regenerate unit + restart)
|
|
439
|
+
(pass ``restart_running=True`` after a real upgrade)
|
|
440
|
+
* installed + unchanged + running → leave it alone
|
|
441
|
+
* installed + unchanged + stopped → start it
|
|
442
|
+
|
|
443
|
+
Best-effort; opt out entirely with ``AGENTOS_NO_SERVICE=1`` (e.g. a box that
|
|
444
|
+
runs the panel manually or only uses the SDK as a library).
|
|
445
|
+
"""
|
|
446
|
+
if _service_disabled():
|
|
447
|
+
return False, "AGENTOS_NO_SERVICE set — leaving the service unmanaged."
|
|
448
|
+
if not is_installed():
|
|
449
|
+
ok, msg = install() # create at the current privilege
|
|
450
|
+
return ok, (f"service created — {msg}" if ok else f"could not create service: {msg}")
|
|
451
|
+
if _needs_root_for_existing():
|
|
452
|
+
return False, ("a system service is installed — run `sudo agentos-ui install` "
|
|
453
|
+
"to apply updates and manage it.")
|
|
454
|
+
if restart_running:
|
|
455
|
+
return refresh()
|
|
456
|
+
if _is_active():
|
|
457
|
+
return True, "service already running."
|
|
458
|
+
rok, rmsg = restart() # installed but down → bring it back up
|
|
459
|
+
return rok, (f"service was down — started; {rmsg}" if rok else rmsg)
|
|
@@ -273,6 +273,37 @@ def self_update() -> bool:
|
|
|
273
273
|
return False
|
|
274
274
|
|
|
275
275
|
|
|
276
|
+
def _ensure_service(quiet: bool = False, *, restart: bool = False) -> None:
|
|
277
|
+
"""Ensure the panel service exists and runs the current SDK, after an update check.
|
|
278
|
+
|
|
279
|
+
Without this, ``agentos-auto update`` pip-upgrades the code but leaves the old
|
|
280
|
+
systemd unit / launchd plist and the old running process in place — so unit
|
|
281
|
+
changes (e.g. the baked-in PATH that lets the service find ``claude``) and new
|
|
282
|
+
code silently never take effect, and a box that never ran ``agentos-ui install``
|
|
283
|
+
has no service at all. ``service.ensure`` creates it when missing, refreshes it
|
|
284
|
+
after a real upgrade (``restart=True``), and starts it if it's down — so a plain
|
|
285
|
+
``agentos-auto update`` reliably leaves ``systemctl status agentos-ui`` running.
|
|
286
|
+
|
|
287
|
+
Best-effort and never raises. Silent on a box without the ``[ui]`` extra (no
|
|
288
|
+
panel to manage) and opt-out via ``AGENTOS_NO_SERVICE=1``.
|
|
289
|
+
|
|
290
|
+
Safe here because ``auto_update`` runs from the short-lived ``agentos-auto``
|
|
291
|
+
process, not inside the long-running panel — restarting the panel can't kill
|
|
292
|
+
the updater mid-run.
|
|
293
|
+
"""
|
|
294
|
+
try:
|
|
295
|
+
from sdk.ui import service
|
|
296
|
+
except Exception: # noqa: BLE001 — no [ui] extra installed → no panel service
|
|
297
|
+
return
|
|
298
|
+
try:
|
|
299
|
+
ok, msg = service.ensure(restart_running=restart)
|
|
300
|
+
if not quiet and msg:
|
|
301
|
+
print(f"↻ {msg}" if ok else f"(service: {msg})")
|
|
302
|
+
except Exception as exc: # noqa: BLE001 — an update must never fail on the service step
|
|
303
|
+
if not quiet:
|
|
304
|
+
print(f"(service check failed: {exc})")
|
|
305
|
+
|
|
306
|
+
|
|
276
307
|
def auto_update(quiet: bool = False) -> tuple[bool, str, str | None]:
|
|
277
308
|
"""Check for a newer version and upgrade if one exists.
|
|
278
309
|
|
|
@@ -292,13 +323,16 @@ def auto_update(quiet: bool = False) -> tuple[bool, str, str | None]:
|
|
|
292
323
|
if not is_github:
|
|
293
324
|
latest = latest_pypi_version()
|
|
294
325
|
if not latest or _vtuple(latest) <= _vtuple(cur):
|
|
326
|
+
_ensure_service(quiet, restart=False) # already current — just self-heal the service
|
|
295
327
|
return (False, cur, latest)
|
|
296
328
|
if not quiet:
|
|
297
329
|
print(f"updating {_DIST} {cur} → {latest} …")
|
|
298
330
|
ok = self_update()
|
|
299
331
|
if not quiet and ok:
|
|
300
332
|
print("✓ updated.")
|
|
301
|
-
#
|
|
333
|
+
# Ensure the service exists + runs the new code (restart only on a real
|
|
334
|
+
# upgrade); also self-heals a missing/down service when already current.
|
|
335
|
+
_ensure_service(quiet, restart=ok)
|
|
302
336
|
return (ok, cur, latest if ok else None)
|
|
303
337
|
|
|
304
338
|
# GitHub path
|
|
@@ -313,6 +347,7 @@ def auto_update(quiet: bool = False) -> tuple[bool, str, str | None]:
|
|
|
313
347
|
elif ok:
|
|
314
348
|
print(f"✓ already up to date (v{cur}).")
|
|
315
349
|
# silent on failure — continue on the existing version without noise
|
|
350
|
+
_ensure_service(quiet, restart=updated)
|
|
316
351
|
return (updated, cur, after if updated else None)
|
|
317
352
|
|
|
318
353
|
|
|
File without changes
|
|
File without changes
|
{devops_bot_sdk-1.4.146 → devops_bot_sdk-1.4.147}/devops_bot_sdk.egg-info/dependency_links.txt
RENAMED
|
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
|
|
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
|