devops-bot-sdk 1.4.27__tar.gz → 1.4.31__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.27 → devops_bot_sdk-1.4.31}/PKG-INFO +1 -1
- {devops_bot_sdk-1.4.27 → devops_bot_sdk-1.4.31}/devops_bot_sdk.egg-info/PKG-INFO +1 -1
- {devops_bot_sdk-1.4.27 → devops_bot_sdk-1.4.31}/pyproject.toml +1 -1
- {devops_bot_sdk-1.4.27 → devops_bot_sdk-1.4.31}/sdk/__init__.py +2 -2
- {devops_bot_sdk-1.4.27 → devops_bot_sdk-1.4.31}/sdk/client.py +28 -1
- {devops_bot_sdk-1.4.27 → devops_bot_sdk-1.4.31}/sdk/ipc/handlers.py +28 -14
- {devops_bot_sdk-1.4.27 → devops_bot_sdk-1.4.31}/sdk/run_auto.py +122 -16
- {devops_bot_sdk-1.4.27 → devops_bot_sdk-1.4.31}/README.md +0 -0
- {devops_bot_sdk-1.4.27 → devops_bot_sdk-1.4.31}/devops_bot_sdk.egg-info/SOURCES.txt +0 -0
- {devops_bot_sdk-1.4.27 → devops_bot_sdk-1.4.31}/devops_bot_sdk.egg-info/dependency_links.txt +0 -0
- {devops_bot_sdk-1.4.27 → devops_bot_sdk-1.4.31}/devops_bot_sdk.egg-info/entry_points.txt +0 -0
- {devops_bot_sdk-1.4.27 → devops_bot_sdk-1.4.31}/devops_bot_sdk.egg-info/requires.txt +0 -0
- {devops_bot_sdk-1.4.27 → devops_bot_sdk-1.4.31}/devops_bot_sdk.egg-info/top_level.txt +0 -0
- {devops_bot_sdk-1.4.27 → devops_bot_sdk-1.4.31}/sdk/collectors/__init__.py +0 -0
- {devops_bot_sdk-1.4.27 → devops_bot_sdk-1.4.31}/sdk/collectors/files.py +0 -0
- {devops_bot_sdk-1.4.27 → devops_bot_sdk-1.4.31}/sdk/collectors/process.py +0 -0
- {devops_bot_sdk-1.4.27 → devops_bot_sdk-1.4.31}/sdk/collectors/screenshot.py +0 -0
- {devops_bot_sdk-1.4.27 → devops_bot_sdk-1.4.31}/sdk/config.py +0 -0
- {devops_bot_sdk-1.4.27 → devops_bot_sdk-1.4.31}/sdk/crucial.py +0 -0
- {devops_bot_sdk-1.4.27 → devops_bot_sdk-1.4.31}/sdk/exceptions.py +0 -0
- {devops_bot_sdk-1.4.27 → devops_bot_sdk-1.4.31}/sdk/git_ops.py +0 -0
- {devops_bot_sdk-1.4.27 → devops_bot_sdk-1.4.31}/sdk/graphify.py +0 -0
- {devops_bot_sdk-1.4.27 → devops_bot_sdk-1.4.31}/sdk/hooks/__init__.py +0 -0
- {devops_bot_sdk-1.4.27 → devops_bot_sdk-1.4.31}/sdk/hooks/crucial_guard.py +0 -0
- {devops_bot_sdk-1.4.27 → devops_bot_sdk-1.4.31}/sdk/ipc/__init__.py +0 -0
- {devops_bot_sdk-1.4.27 → devops_bot_sdk-1.4.31}/sdk/ipc/electron_bridge.py +0 -0
- {devops_bot_sdk-1.4.27 → devops_bot_sdk-1.4.31}/sdk/local_exec.py +0 -0
- {devops_bot_sdk-1.4.27 → devops_bot_sdk-1.4.31}/sdk/models/__init__.py +0 -0
- {devops_bot_sdk-1.4.27 → devops_bot_sdk-1.4.31}/sdk/models/envelope.py +0 -0
- {devops_bot_sdk-1.4.27 → devops_bot_sdk-1.4.31}/sdk/models/requests.py +0 -0
- {devops_bot_sdk-1.4.27 → devops_bot_sdk-1.4.31}/sdk/models/responses.py +0 -0
- {devops_bot_sdk-1.4.27 → devops_bot_sdk-1.4.31}/sdk/models/snapshots.py +0 -0
- {devops_bot_sdk-1.4.27 → devops_bot_sdk-1.4.31}/sdk/py.typed +0 -0
- {devops_bot_sdk-1.4.27 → devops_bot_sdk-1.4.31}/sdk/sse.py +0 -0
- {devops_bot_sdk-1.4.27 → devops_bot_sdk-1.4.31}/sdk/test.py +0 -0
- {devops_bot_sdk-1.4.27 → devops_bot_sdk-1.4.31}/sdk/test_pipeline.py +0 -0
- {devops_bot_sdk-1.4.27 → devops_bot_sdk-1.4.31}/sdk/updater.py +0 -0
- {devops_bot_sdk-1.4.27 → devops_bot_sdk-1.4.31}/setup.cfg +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "devops-bot-sdk"
|
|
7
|
-
version = "1.4.
|
|
7
|
+
version = "1.4.31"
|
|
8
8
|
description = "DevOps Bot Desktop SDK — thin client for the AgentOS Electron desktop app"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "LicenseRef-Proprietary"
|
|
@@ -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.31
|
|
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.31"
|
|
34
34
|
__author__ = "AgentOS"
|
|
35
35
|
|
|
36
36
|
from sdk.client import BackendClient
|
|
@@ -36,7 +36,7 @@ from sdk.sse import _check_status, stream_with_reconnect
|
|
|
36
36
|
|
|
37
37
|
logger = logging.getLogger(__name__)
|
|
38
38
|
|
|
39
|
-
SDK_VERSION = "1.4.
|
|
39
|
+
SDK_VERSION = "1.4.31"
|
|
40
40
|
_POLL_INTERVAL = 3.0
|
|
41
41
|
_POLL_TIMEOUT = 600.0
|
|
42
42
|
_ORCHESTRATE_TIMEOUT = 2700.0 # 45 min — covers approval wait + VPS execution time
|
|
@@ -691,6 +691,33 @@ class BackendClient:
|
|
|
691
691
|
logger.warning("client.move_to_backlog error task=%s err=%s", task_id, exc)
|
|
692
692
|
return False
|
|
693
693
|
|
|
694
|
+
async def move_to_todo(self, task_id: str) -> bool:
|
|
695
|
+
"""PUT {BE}/tasks-ml/{id} status="To Do" (best-effort).
|
|
696
|
+
|
|
697
|
+
Used by `agentos-auto stop` to return the in-flight ticket to the unstarted
|
|
698
|
+
queue so a later run re-picks it up from scratch (rather than leaving it
|
|
699
|
+
In Progress). Returns True on success; logs and returns False otherwise.
|
|
700
|
+
"""
|
|
701
|
+
from sdk.config import BE_DEFAULT_URL
|
|
702
|
+
|
|
703
|
+
url = f"{BE_DEFAULT_URL.rstrip('/')}/tasks-ml/{task_id}"
|
|
704
|
+
headers = {
|
|
705
|
+
k: v for k, v in self._headers.items() if k.lower() != "content-type"
|
|
706
|
+
}
|
|
707
|
+
headers.update({"accept": "*/*", "developer-name": "null", "product": ""})
|
|
708
|
+
try:
|
|
709
|
+
async with httpx.AsyncClient(timeout=20.0) as client:
|
|
710
|
+
resp = await client.put(url, files={"status": (None, "To Do")}, headers=headers)
|
|
711
|
+
if resp.status_code >= 400:
|
|
712
|
+
logger.warning("client.move_to_todo failed task=%s status=%s body=%s",
|
|
713
|
+
task_id, resp.status_code, resp.text[:200])
|
|
714
|
+
return False
|
|
715
|
+
await self.log_activity(f"Task {task_id}: status → To Do")
|
|
716
|
+
return True
|
|
717
|
+
except Exception as exc: # noqa: BLE001
|
|
718
|
+
logger.warning("client.move_to_todo error task=%s err=%s", task_id, exc)
|
|
719
|
+
return False
|
|
720
|
+
|
|
694
721
|
async def mark_in_progress(self, task_id: str) -> bool:
|
|
695
722
|
"""PUT {BE}/tasks-ml/{id} status=In Progress (best-effort).
|
|
696
723
|
|
|
@@ -1845,31 +1845,45 @@ async def handle_orchestrate_auto_local_run(
|
|
|
1845
1845
|
"current_step": f"{jira_key}: awaiting approval"},
|
|
1846
1846
|
).model_dump())
|
|
1847
1847
|
|
|
1848
|
-
# Safety net for the gate-1 WhatsApp. The backend sends it
|
|
1849
|
-
# when planning opens the gate; if that send failed the
|
|
1850
|
-
# approver would get nothing and the ticket would silently
|
|
1851
|
-
# time out to Backlog. Re-send it ourselves once, only after
|
|
1852
|
-
# the grace window, so a healthy backend doesn't duplicate.
|
|
1853
1848
|
_wa_summary = task.get("summary") or jira_key or "task"
|
|
1854
1849
|
|
|
1855
|
-
async def
|
|
1850
|
+
async def _send_first_gate_wa(
|
|
1856
1851
|
tid=tid, jira_key=jira_key, _wa_summary=_wa_summary,
|
|
1857
|
-
) ->
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
await client.notify_whatsapp(
|
|
1852
|
+
) -> bool:
|
|
1853
|
+
# approver_role defaults to TEAM_LEAD (matches the ML
|
|
1854
|
+
# backend's /approvals-ml routing that is known to work).
|
|
1855
|
+
# Log the outcome to the daemon log + activity DB so a
|
|
1856
|
+
# failed send is visible instead of silently swallowed.
|
|
1857
|
+
ok = await client.notify_whatsapp(
|
|
1864
1858
|
tid,
|
|
1865
1859
|
f"Approval needed for {jira_key or tid}: {_wa_summary} — "
|
|
1866
1860
|
"reply on WhatsApp to approve or reject so the work can start.",
|
|
1867
1861
|
summary=_wa_summary,
|
|
1868
1862
|
)
|
|
1863
|
+
note = ("WhatsApp approval request sent" if ok
|
|
1864
|
+
else "WhatsApp approval request FAILED to send "
|
|
1865
|
+
"(check /approvals-ml + approver phone on file)")
|
|
1866
|
+
await send(Envelope(
|
|
1867
|
+
type="step_update", thread_id=thread_id,
|
|
1868
|
+
data={"current_step": f"{jira_key}: {note}"},
|
|
1869
|
+
).model_dump())
|
|
1870
|
+
try:
|
|
1871
|
+
await client.log_activity(f"Task {tid}: {note}")
|
|
1872
|
+
except Exception: # noqa: BLE001
|
|
1873
|
+
pass
|
|
1874
|
+
return ok
|
|
1875
|
+
|
|
1876
|
+
# Send the gate-1 WhatsApp NOW via /approvals-ml (the ML
|
|
1877
|
+
# backend actually delivers it). Owning the send here makes
|
|
1878
|
+
# it reliable regardless of whether the AI backend's own
|
|
1879
|
+
# M5.2 send fired — the previous "no WhatsApp at all" bug.
|
|
1880
|
+
await _send_first_gate_wa()
|
|
1869
1881
|
|
|
1882
|
+
# Re-send once, after the grace window, only if still unanswered
|
|
1883
|
+
# (covers a transient failure of the send above).
|
|
1870
1884
|
decision = await _poll_approval(
|
|
1871
1885
|
client, tid, should_stop,
|
|
1872
|
-
fallback_notify=
|
|
1886
|
+
fallback_notify=_send_first_gate_wa,
|
|
1873
1887
|
fallback_after_s=_FIRST_GATE_WA_FALLBACK_S,
|
|
1874
1888
|
)
|
|
1875
1889
|
|
|
@@ -28,11 +28,11 @@ Auto-update: on `run`/`resume`, the SDK checks for a newer version and upgrades
|
|
|
28
28
|
itself (then re-runs on the new code) BEFORE detaching, so non-technical users
|
|
29
29
|
never reinstall.
|
|
30
30
|
|
|
31
|
-
Stop
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
whatever is still To Do.
|
|
31
|
+
Stop model: `stop` is immediate — it kills the loop's whole process group (the
|
|
32
|
+
daemon and any child `claude`) and returns the in-flight ticket to "To Do" so a
|
|
33
|
+
later run restarts it cleanly, rather than pausing after the current task. The
|
|
34
|
+
tracked in-flight ticket id is kept in ~/.agentos/auto.current. `resume` (or just
|
|
35
|
+
re-running) starts fresh over whatever is still To Do.
|
|
36
36
|
"""
|
|
37
37
|
from __future__ import annotations
|
|
38
38
|
|
|
@@ -46,6 +46,9 @@ _AGENTOS_DIR = Path.home() / ".agentos"
|
|
|
46
46
|
_STOP_FILE = _AGENTOS_DIR / "auto.stop"
|
|
47
47
|
_PID_FILE = _AGENTOS_DIR / "auto.pid"
|
|
48
48
|
_LOG_FILE = _AGENTOS_DIR / "auto.log"
|
|
49
|
+
# Backend id (UUID) of the ticket currently being processed. `stop` reads it to
|
|
50
|
+
# return the in-flight ticket to "To Do" before killing the loop.
|
|
51
|
+
_CURRENT_FILE = _AGENTOS_DIR / "auto.current"
|
|
49
52
|
|
|
50
53
|
|
|
51
54
|
def _stop_requested() -> bool:
|
|
@@ -64,6 +67,29 @@ def _clear_stop() -> None:
|
|
|
64
67
|
pass
|
|
65
68
|
|
|
66
69
|
|
|
70
|
+
def _write_current(task_id: str) -> None:
|
|
71
|
+
try:
|
|
72
|
+
_AGENTOS_DIR.mkdir(parents=True, exist_ok=True)
|
|
73
|
+
_CURRENT_FILE.write_text(task_id)
|
|
74
|
+
except Exception: # noqa: BLE001
|
|
75
|
+
pass
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def _read_current() -> str | None:
|
|
79
|
+
try:
|
|
80
|
+
val = _CURRENT_FILE.read_text().strip()
|
|
81
|
+
return val or None
|
|
82
|
+
except FileNotFoundError:
|
|
83
|
+
return None
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _clear_current() -> None:
|
|
87
|
+
try:
|
|
88
|
+
_CURRENT_FILE.unlink()
|
|
89
|
+
except FileNotFoundError:
|
|
90
|
+
pass
|
|
91
|
+
|
|
92
|
+
|
|
67
93
|
# ── Background-daemon support ─────────────────────────────────────────────
|
|
68
94
|
# `agentos-auto` must keep running after the terminal is closed and stop ONLY on
|
|
69
95
|
# `agentos-auto stop`. We fully detach from the controlling terminal (double-fork
|
|
@@ -134,6 +160,14 @@ def _daemonize() -> bool:
|
|
|
134
160
|
os.close(devnull)
|
|
135
161
|
os.close(logfd)
|
|
136
162
|
|
|
163
|
+
# CRITICAL: when stdout is a file (not a tty) Python block-buffers it, so
|
|
164
|
+
# progress printed via _send() would sit in the buffer and never reach the
|
|
165
|
+
# log until the process exits — making the daemon look idle. Replace the
|
|
166
|
+
# streams with line-buffered writers so every progress line is flushed live,
|
|
167
|
+
# exactly like the foreground run.
|
|
168
|
+
sys.stdout = open(_LOG_FILE, "a", buffering=1, encoding="utf-8")
|
|
169
|
+
sys.stderr = sys.stdout
|
|
170
|
+
|
|
137
171
|
_PID_FILE.write_text(str(os.getpid()))
|
|
138
172
|
return True
|
|
139
173
|
|
|
@@ -149,9 +183,24 @@ def _parse_workspace_root(argv: list[str]) -> str | None:
|
|
|
149
183
|
return None
|
|
150
184
|
|
|
151
185
|
|
|
186
|
+
_current_task: str | None = None
|
|
187
|
+
|
|
188
|
+
|
|
152
189
|
async def _send(env: dict) -> None:
|
|
153
190
|
etype = env.get("type", "")
|
|
154
191
|
data = env.get("data", {}) or {}
|
|
192
|
+
|
|
193
|
+
# Track the in-flight ticket (backend UUID) so `stop` can return it to To Do.
|
|
194
|
+
# The handler tags per-task envelopes with jira_task_id / task_id (both = the
|
|
195
|
+
# backend UUID here). Persist only on change to avoid churning the file.
|
|
196
|
+
global _current_task
|
|
197
|
+
tid = data.get("jira_task_id") or data.get("task_id")
|
|
198
|
+
if tid and tid != _current_task:
|
|
199
|
+
_current_task = tid
|
|
200
|
+
_write_current(tid)
|
|
201
|
+
if etype == "done":
|
|
202
|
+
_clear_current()
|
|
203
|
+
|
|
155
204
|
if etype == "pipeline_started":
|
|
156
205
|
print(f"\n▶ orchestrate-auto (local) — {data.get('task_count', 0)} task(s)\n")
|
|
157
206
|
elif etype == "step_update":
|
|
@@ -205,12 +254,14 @@ def _run_loop(workspace_root: str | None) -> None:
|
|
|
205
254
|
print("\n⏸ interrupted — stop flag set. run `agentos-auto resume` to continue.")
|
|
206
255
|
finally:
|
|
207
256
|
# Whether the loop finished, paused, or crashed, drop our PID file so
|
|
208
|
-
# `status` doesn't report a dead daemon as running
|
|
257
|
+
# `status` doesn't report a dead daemon as running, and clear the
|
|
258
|
+
# in-flight marker (the queue is drained on a clean finish).
|
|
209
259
|
if _read_pid() == os.getpid():
|
|
210
260
|
try:
|
|
211
261
|
_PID_FILE.unlink()
|
|
212
262
|
except FileNotFoundError:
|
|
213
263
|
pass
|
|
264
|
+
_clear_current()
|
|
214
265
|
|
|
215
266
|
|
|
216
267
|
def main() -> None:
|
|
@@ -225,13 +276,63 @@ def main() -> None:
|
|
|
225
276
|
return
|
|
226
277
|
|
|
227
278
|
if cmd == "stop":
|
|
279
|
+
# Hard stop: halt the current task immediately, return it to To Do so it
|
|
280
|
+
# restarts cleanly next run, and kill the whole loop (not a cooperative
|
|
281
|
+
# pause after the current task).
|
|
228
282
|
_set_stop()
|
|
229
283
|
pid = _daemon_running()
|
|
284
|
+
cur = _read_current()
|
|
285
|
+
|
|
286
|
+
# 1. Kill the loop's ENTIRE process group first (daemon + any child
|
|
287
|
+
# `claude` it spawned) so nothing keeps mutating the ticket. The daemon
|
|
288
|
+
# is a session leader (setsid), so its PGID == its PID.
|
|
230
289
|
if pid:
|
|
231
|
-
|
|
232
|
-
|
|
290
|
+
import signal
|
|
291
|
+
import time as _t
|
|
292
|
+
# Kill the whole process group ONLY when pid is its own group leader
|
|
293
|
+
# (the daemon, via setsid) — that also reaps the child `claude`. For a
|
|
294
|
+
# foreground run (shares the shell's group) fall back to a single kill
|
|
295
|
+
# so we don't take down the user's terminal.
|
|
296
|
+
try:
|
|
297
|
+
is_group_leader = os.getpgid(pid) == pid
|
|
298
|
+
except ProcessLookupError:
|
|
299
|
+
is_group_leader = False
|
|
300
|
+
killed = False
|
|
301
|
+
for sig in (signal.SIGTERM, signal.SIGKILL):
|
|
302
|
+
try:
|
|
303
|
+
if is_group_leader:
|
|
304
|
+
os.killpg(pid, sig)
|
|
305
|
+
else:
|
|
306
|
+
os.kill(pid, sig)
|
|
307
|
+
except ProcessLookupError:
|
|
308
|
+
killed = True
|
|
309
|
+
break
|
|
310
|
+
except Exception: # noqa: BLE001
|
|
311
|
+
pass
|
|
312
|
+
_t.sleep(1.5)
|
|
313
|
+
if not _pid_alive(pid):
|
|
314
|
+
killed = True
|
|
315
|
+
break
|
|
316
|
+
print(f"stopped background loop (pid {pid})" if killed
|
|
317
|
+
else f"sent stop signals to pid {pid}")
|
|
233
318
|
else:
|
|
234
|
-
print("
|
|
319
|
+
print("no background loop running — stop flag set for any foreground run.")
|
|
320
|
+
|
|
321
|
+
# 2. Now that the loop is dead, move the in-flight ticket back to To Do.
|
|
322
|
+
if cur:
|
|
323
|
+
try:
|
|
324
|
+
from sdk.client import BackendClient
|
|
325
|
+
ok = asyncio.run(BackendClient.from_config().move_to_todo(cur))
|
|
326
|
+
print(f"in-flight ticket → To Do ({'ok' if ok else 'failed'})")
|
|
327
|
+
except Exception as exc: # noqa: BLE001
|
|
328
|
+
print(f"warning: could not move in-flight ticket to To Do ({exc})")
|
|
329
|
+
|
|
330
|
+
# 3. Clean up state files.
|
|
331
|
+
for f in (_PID_FILE, _CURRENT_FILE):
|
|
332
|
+
try:
|
|
333
|
+
f.unlink()
|
|
334
|
+
except FileNotFoundError:
|
|
335
|
+
pass
|
|
235
336
|
return
|
|
236
337
|
|
|
237
338
|
if cmd == "status":
|
|
@@ -239,12 +340,24 @@ def main() -> None:
|
|
|
239
340
|
if pid:
|
|
240
341
|
print(f"background loop: running (pid {pid})")
|
|
241
342
|
print(f"logs: {_LOG_FILE}")
|
|
343
|
+
cur = _read_current()
|
|
344
|
+
if cur:
|
|
345
|
+
print(f"current ticket: {cur}")
|
|
242
346
|
else:
|
|
243
347
|
print("background loop: not running")
|
|
244
348
|
print("stop pending: yes" if _stop_requested() else "stop pending: no")
|
|
245
349
|
return
|
|
246
350
|
|
|
247
351
|
if cmd in ("run", "resume"):
|
|
352
|
+
# Self-update FIRST (before the already-running check) so the installed
|
|
353
|
+
# package is refreshed even when a daemon is already running — otherwise a
|
|
354
|
+
# long-lived old daemon would pin `stop`/`status` to a stale version. Runs
|
|
355
|
+
# in the FOREGROUND so the user sees update output; re-execs on the new
|
|
356
|
+
# code. Skipped with --no-update or AGENTOS_NO_UPDATE=1.
|
|
357
|
+
if "--no-update" not in argv:
|
|
358
|
+
from sdk.updater import auto_update_and_reexec
|
|
359
|
+
auto_update_and_reexec("sdk.run_auto", sys.argv[1:])
|
|
360
|
+
|
|
248
361
|
# Refuse to start a second loop — one background daemon owns the To Do queue.
|
|
249
362
|
pid = _daemon_running()
|
|
250
363
|
if pid:
|
|
@@ -253,13 +366,6 @@ def main() -> None:
|
|
|
253
366
|
print(" stop: agentos-auto stop")
|
|
254
367
|
return
|
|
255
368
|
|
|
256
|
-
# Keep non-technical users current: self-update, then re-run on the new
|
|
257
|
-
# code. Runs in the FOREGROUND (before detaching) so the user sees update
|
|
258
|
-
# output. Skipped with --no-update or AGENTOS_NO_UPDATE=1.
|
|
259
|
-
if "--no-update" not in argv:
|
|
260
|
-
from sdk.updater import auto_update_and_reexec
|
|
261
|
-
auto_update_and_reexec("sdk.run_auto", sys.argv[1:])
|
|
262
|
-
|
|
263
369
|
workspace_root = _parse_workspace_root(argv)
|
|
264
370
|
|
|
265
371
|
# Background by default: detach so closing the terminal (SIGHUP) can't kill
|
|
File without changes
|
|
File without changes
|
{devops_bot_sdk-1.4.27 → devops_bot_sdk-1.4.31}/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
|