devops-bot-sdk 1.4.145__tar.gz → 1.4.146__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.145 → devops_bot_sdk-1.4.146}/PKG-INFO +1 -1
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/devops_bot_sdk.egg-info/PKG-INFO +1 -1
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/__init__.py +2 -2
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/agents/inventory.py +2 -2
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/local_exec.py +76 -2
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/ui/service.py +28 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/ui/setup_manager.py +14 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/README.md +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/devops_bot_sdk.egg-info/SOURCES.txt +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/devops_bot_sdk.egg-info/dependency_links.txt +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/devops_bot_sdk.egg-info/entry_points.txt +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/devops_bot_sdk.egg-info/requires.txt +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/devops_bot_sdk.egg-info/top_level.txt +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/pyproject.toml +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/agentd.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/agents/__init__.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/agents/builder.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/agents/chat.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/agents/connectors.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/agents/engines/__init__.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/agents/engines/claude_code.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/agents/engines/http.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/agents/engines/mcp.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/agents/engines/n8n.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/agents/engines/shell.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/agents/integrations.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/agents/library/__init__.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/agents/manifest.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/agents/prompt_studio.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/agents/prompt_template.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/agents/prompt_vars.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/agents/run_log.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/agents/secrets.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/agents/usage.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/agents/varstore.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/cli.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/client.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/collectors/__init__.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/collectors/files.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/collectors/process.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/collectors/screenshot.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/config.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/crucial.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/design_verify/__init__.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/design_verify/assets.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/design_verify/bootstrap.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/design_verify/browser.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/design_verify/compare.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/design_verify/loop.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/exceptions.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/git_ops.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/graphify.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/hooks/__init__.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/hooks/crucial_guard.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/ipc/__init__.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/ipc/electron_bridge.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/ipc/handlers.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/models/__init__.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/models/envelope.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/models/requests.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/models/responses.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/models/snapshots.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/platform_compat.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/py.typed +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/run_auto.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/sse.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/test.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/test_pipeline.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/ui/__init__.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/ui/api.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/ui/dashboard.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/ui/health.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/ui/ip_allowlist.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/ui/jobs.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/ui/models.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/ui/runner.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/ui/security.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/ui/server.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/ui/static/agents.html +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/ui/static/app.js +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/ui/static/custom-agents.html +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/ui/static/default-agents.html +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/ui/static/index.html +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/ui/static/runs.html +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/ui/static/setup.html +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/ui/static/styles.css +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/ui/static/tickets.html +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/sdk/updater.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/setup.cfg +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/tests/test_agent_chat_features.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/tests/test_agent_prompt_models.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/tests/test_agents_connectors_builder.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/tests/test_git_action.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/tests/test_health.py +0 -0
- {devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/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.146
|
|
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.146" # 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
|
|
@@ -11,7 +11,6 @@ from __future__ import annotations
|
|
|
11
11
|
|
|
12
12
|
import json
|
|
13
13
|
import logging
|
|
14
|
-
import shutil
|
|
15
14
|
import subprocess
|
|
16
15
|
from pathlib import Path
|
|
17
16
|
|
|
@@ -70,7 +69,8 @@ def _connectors() -> list[dict]:
|
|
|
70
69
|
|
|
71
70
|
def _mcp_servers() -> list[dict]:
|
|
72
71
|
"""Installed MCP servers / Claude plugins, parsed from ``claude mcp list``."""
|
|
73
|
-
|
|
72
|
+
from sdk.local_exec import claude_cli_path
|
|
73
|
+
cli = claude_cli_path()
|
|
74
74
|
if not cli:
|
|
75
75
|
return []
|
|
76
76
|
try:
|
|
@@ -22,6 +22,7 @@ import json
|
|
|
22
22
|
import os
|
|
23
23
|
import re
|
|
24
24
|
import shutil
|
|
25
|
+
import subprocess
|
|
25
26
|
import sys
|
|
26
27
|
from datetime import datetime, timedelta
|
|
27
28
|
from pathlib import Path
|
|
@@ -240,7 +241,21 @@ EventHandler = Callable[[dict], Awaitable[None]]
|
|
|
240
241
|
|
|
241
242
|
|
|
242
243
|
def claude_cli_path() -> str | None:
|
|
243
|
-
"""Absolute path to the `claude` CLI if
|
|
244
|
+
"""Absolute path to the `claude` CLI, or None if it isn't on PATH.
|
|
245
|
+
|
|
246
|
+
Resolution order:
|
|
247
|
+
1. ``AGENTOS_CLAUDE_CLI`` env var — explicit path override (escape hatch for
|
|
248
|
+
an install in a non-standard location).
|
|
249
|
+
2. ``PATH`` (``shutil.which``) — cross-platform, no guessing.
|
|
250
|
+
|
|
251
|
+
The service must therefore RUN with a PATH that includes the CLI. The install
|
|
252
|
+
step bakes that in (see ``sdk.ui.service`` — systemd ``Environment=PATH`` /
|
|
253
|
+
launchd ``EnvironmentVariables``; Windows tasks inherit the user's PATH), so
|
|
254
|
+
``engine=claude_code`` works without anyone editing a unit file.
|
|
255
|
+
"""
|
|
256
|
+
override = os.environ.get("AGENTOS_CLAUDE_CLI", "").strip()
|
|
257
|
+
if override and Path(override).exists():
|
|
258
|
+
return override
|
|
244
259
|
return shutil.which("claude")
|
|
245
260
|
|
|
246
261
|
|
|
@@ -249,6 +264,54 @@ def is_available() -> bool:
|
|
|
249
264
|
return claude_cli_path() is not None
|
|
250
265
|
|
|
251
266
|
|
|
267
|
+
def claude_status(timeout: float = 15.0) -> dict:
|
|
268
|
+
"""Readiness of the local Claude Code CLI: installed AND logged in.
|
|
269
|
+
|
|
270
|
+
Runs ``claude auth status`` (which prints structured JSON) so the panel /
|
|
271
|
+
health surface can show a non-technical operator one clear signal — "connected
|
|
272
|
+
as you@org" vs "not logged in" — instead of a raw CLI error surfacing only when
|
|
273
|
+
a job runs. All failures degrade to ``logged_in: False`` with an ``error`` note;
|
|
274
|
+
this never raises.
|
|
275
|
+
|
|
276
|
+
Returns::
|
|
277
|
+
|
|
278
|
+
{"installed": bool, "logged_in": bool, "path": str|None,
|
|
279
|
+
"auth_method": str|None, "email": str|None, "org": str|None,
|
|
280
|
+
"error": str|None}
|
|
281
|
+
"""
|
|
282
|
+
cli = claude_cli_path()
|
|
283
|
+
if not cli:
|
|
284
|
+
return {"installed": False, "logged_in": False, "path": None,
|
|
285
|
+
"auth_method": None, "email": None, "org": None,
|
|
286
|
+
"error": "Claude Code CLI not found. Install it or set AGENTOS_CLAUDE_CLI."}
|
|
287
|
+
try:
|
|
288
|
+
proc = subprocess.run([cli, "auth", "status"], capture_output=True,
|
|
289
|
+
text=True, timeout=timeout)
|
|
290
|
+
except Exception as exc: # noqa: BLE001 — timeout / OSError; never raise to caller
|
|
291
|
+
return {"installed": True, "logged_in": False, "path": cli, "auth_method": None,
|
|
292
|
+
"email": None, "org": None, "error": f"`claude auth status` failed: {exc}"}
|
|
293
|
+
|
|
294
|
+
out = (proc.stdout or "").strip()
|
|
295
|
+
try:
|
|
296
|
+
data = json.loads(out)
|
|
297
|
+
except Exception: # noqa: BLE001 — older CLIs may print human text, not JSON
|
|
298
|
+
logged = "logged in" in out.lower()
|
|
299
|
+
return {"installed": True, "logged_in": logged, "path": cli, "auth_method": None,
|
|
300
|
+
"email": None, "org": None,
|
|
301
|
+
"error": None if logged else ((proc.stderr or out or "not logged in").strip()[:200])}
|
|
302
|
+
|
|
303
|
+
logged = bool(data.get("loggedIn"))
|
|
304
|
+
return {
|
|
305
|
+
"installed": True,
|
|
306
|
+
"logged_in": logged,
|
|
307
|
+
"path": cli,
|
|
308
|
+
"auth_method": data.get("authMethod"),
|
|
309
|
+
"email": data.get("email"),
|
|
310
|
+
"org": data.get("orgName") or data.get("orgId"),
|
|
311
|
+
"error": None if logged else "Not logged in — run `claude` on the VPS to sign in.",
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
|
|
252
315
|
# Cache the discovered MCP allow-entries for the process lifetime — the set of
|
|
253
316
|
# configured servers doesn't change mid-run, and `claude mcp list` does a network
|
|
254
317
|
# health check (~seconds) we don't want to repeat per ticket.
|
|
@@ -396,7 +459,9 @@ async def run_claude_local(
|
|
|
396
459
|
cli = claude_cli_path()
|
|
397
460
|
if not cli:
|
|
398
461
|
return {
|
|
399
|
-
"ok": False, "result": "",
|
|
462
|
+
"ok": False, "result": "",
|
|
463
|
+
"error": ("Claude Code CLI not found. Install it, or if it is installed "
|
|
464
|
+
"in a non-standard location set AGENTOS_CLAUDE_CLI to its full path."),
|
|
400
465
|
"input_tokens": 0, "output_tokens": 0, "total_tokens": 0,
|
|
401
466
|
"cost_usd": 0.0, "files_changed": [],
|
|
402
467
|
}
|
|
@@ -461,6 +526,15 @@ async def run_claude_local(
|
|
|
461
526
|
# the user's global git config. Tokens stay in the subprocess env only.
|
|
462
527
|
env = dict(os.environ)
|
|
463
528
|
|
|
529
|
+
# Make sure the CLI's own directory is on the subprocess PATH: node/gh and the
|
|
530
|
+
# CLI's sibling tools usually live alongside it, and under a minimal service
|
|
531
|
+
# PATH they'd otherwise be missing. Prepend the resolved binary's dir only —
|
|
532
|
+
# no guessing beyond that — so anything the operator exported still wins.
|
|
533
|
+
_cli_dir = str(Path(cli).resolve().parent)
|
|
534
|
+
_cur_path = env.get("PATH", "")
|
|
535
|
+
if _cli_dir not in _cur_path.split(os.pathsep):
|
|
536
|
+
env["PATH"] = _cli_dir + (os.pathsep + _cur_path if _cur_path else "")
|
|
537
|
+
|
|
464
538
|
# A custom agent's persisted API keys (sdk.agents.secrets) are overlaid here
|
|
465
539
|
# so they reach the subprocess (and any MCP servers it spawns) WITHOUT ever
|
|
466
540
|
# touching the ambient os.environ of this process — same "subprocess env only"
|
|
@@ -51,6 +51,30 @@ def _systemd_available() -> bool:
|
|
|
51
51
|
return bool(shutil.which("systemctl")) and Path("/run/systemd/system").exists()
|
|
52
52
|
|
|
53
53
|
|
|
54
|
+
def _service_path_env() -> str:
|
|
55
|
+
"""PATH for the service environment.
|
|
56
|
+
|
|
57
|
+
A service (systemd/launchd) runs with a minimal PATH that omits ~/.local/bin,
|
|
58
|
+
nvm/Homebrew, etc. — exactly where the ``claude`` CLI and its node/git/gh
|
|
59
|
+
runtime live. Prepend the resolved CLI's own directory and ~/.local/bin to the
|
|
60
|
+
standard system dirs so ``engine=claude_code`` works with no manual PATH edits.
|
|
61
|
+
"""
|
|
62
|
+
base = ["/usr/local/sbin", "/usr/local/bin", "/usr/sbin", "/usr/bin", "/sbin", "/bin"]
|
|
63
|
+
extra = [str(Path.home() / ".local" / "bin")]
|
|
64
|
+
try:
|
|
65
|
+
from sdk.local_exec import claude_cli_path
|
|
66
|
+
cli = claude_cli_path()
|
|
67
|
+
if cli:
|
|
68
|
+
extra.append(str(Path(cli).resolve().parent))
|
|
69
|
+
except Exception: # noqa: BLE001 — discovery must never break install
|
|
70
|
+
pass
|
|
71
|
+
ordered: list[str] = []
|
|
72
|
+
for d in extra + base:
|
|
73
|
+
if d and d not in ordered:
|
|
74
|
+
ordered.append(d)
|
|
75
|
+
return ":".join(ordered)
|
|
76
|
+
|
|
77
|
+
|
|
54
78
|
def _unit_text(host: str, port: int, home: str) -> str:
|
|
55
79
|
exec_line = f"{_exe()} --host {host} --port {port} --no-browser"
|
|
56
80
|
return (
|
|
@@ -64,6 +88,7 @@ def _unit_text(host: str, port: int, home: str) -> str:
|
|
|
64
88
|
"Restart=always\n"
|
|
65
89
|
"RestartSec=5\n"
|
|
66
90
|
f"Environment=HOME={home}\n"
|
|
91
|
+
f"Environment=PATH={_service_path_env()}\n"
|
|
67
92
|
f"WorkingDirectory={home}\n\n"
|
|
68
93
|
"[Install]\n"
|
|
69
94
|
f"WantedBy={{target}}\n"
|
|
@@ -145,6 +170,9 @@ def _install_launchd(host: str, port: int) -> tuple[bool, str]:
|
|
|
145
170
|
f' <string>{exe}</string><string>--host</string><string>{host}</string>\n'
|
|
146
171
|
f' <string>--port</string><string>{port}</string><string>--no-browser</string>\n'
|
|
147
172
|
' </array>\n'
|
|
173
|
+
' <key>EnvironmentVariables</key><dict>\n'
|
|
174
|
+
f' <key>PATH</key><string>{_service_path_env()}</string>\n'
|
|
175
|
+
' </dict>\n'
|
|
148
176
|
' <key>RunAtLoad</key><true/>\n'
|
|
149
177
|
' <key>KeepAlive</key><true/>\n'
|
|
150
178
|
'</dict></plist>\n'
|
|
@@ -64,6 +64,19 @@ def sdk_version() -> str:
|
|
|
64
64
|
return "unknown"
|
|
65
65
|
|
|
66
66
|
|
|
67
|
+
def claude_readiness() -> dict:
|
|
68
|
+
"""Claude Code CLI readiness (installed + logged in) for the /status surface.
|
|
69
|
+
|
|
70
|
+
Guarded: any failure degrades to a not-ready dict rather than breaking /status.
|
|
71
|
+
"""
|
|
72
|
+
try:
|
|
73
|
+
from sdk.local_exec import claude_status
|
|
74
|
+
return claude_status()
|
|
75
|
+
except Exception as exc: # noqa: BLE001
|
|
76
|
+
return {"installed": False, "logged_in": False, "path": None,
|
|
77
|
+
"auth_method": None, "email": None, "org": None, "error": str(exc)}
|
|
78
|
+
|
|
79
|
+
|
|
67
80
|
def environment_info() -> dict:
|
|
68
81
|
"""Env snapshot for the /status endpoint and setup wizard."""
|
|
69
82
|
vp = running_venv()
|
|
@@ -78,6 +91,7 @@ def environment_info() -> dict:
|
|
|
78
91
|
"expected_agentsystem_root": str(root),
|
|
79
92
|
"agentsystem_exists": root.exists(),
|
|
80
93
|
"sdk_version": sdk_version(),
|
|
94
|
+
"claude": claude_readiness(),
|
|
81
95
|
}
|
|
82
96
|
|
|
83
97
|
|
|
File without changes
|
|
File without changes
|
{devops_bot_sdk-1.4.145 → devops_bot_sdk-1.4.146}/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
|