devops-bot-sdk 1.4.67__tar.gz → 1.4.71__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.67 → devops_bot_sdk-1.4.71}/PKG-INFO +1 -1
- {devops_bot_sdk-1.4.67 → devops_bot_sdk-1.4.71}/devops_bot_sdk.egg-info/PKG-INFO +1 -1
- {devops_bot_sdk-1.4.67 → devops_bot_sdk-1.4.71}/pyproject.toml +1 -1
- {devops_bot_sdk-1.4.67 → devops_bot_sdk-1.4.71}/sdk/__init__.py +2 -2
- {devops_bot_sdk-1.4.67 → devops_bot_sdk-1.4.71}/sdk/client.py +1 -1
- {devops_bot_sdk-1.4.67 → devops_bot_sdk-1.4.71}/sdk/ipc/handlers.py +32 -14
- {devops_bot_sdk-1.4.67 → devops_bot_sdk-1.4.71}/sdk/run_auto.py +50 -1
- {devops_bot_sdk-1.4.67 → devops_bot_sdk-1.4.71}/README.md +0 -0
- {devops_bot_sdk-1.4.67 → devops_bot_sdk-1.4.71}/devops_bot_sdk.egg-info/SOURCES.txt +0 -0
- {devops_bot_sdk-1.4.67 → devops_bot_sdk-1.4.71}/devops_bot_sdk.egg-info/dependency_links.txt +0 -0
- {devops_bot_sdk-1.4.67 → devops_bot_sdk-1.4.71}/devops_bot_sdk.egg-info/entry_points.txt +0 -0
- {devops_bot_sdk-1.4.67 → devops_bot_sdk-1.4.71}/devops_bot_sdk.egg-info/requires.txt +0 -0
- {devops_bot_sdk-1.4.67 → devops_bot_sdk-1.4.71}/devops_bot_sdk.egg-info/top_level.txt +0 -0
- {devops_bot_sdk-1.4.67 → devops_bot_sdk-1.4.71}/sdk/collectors/__init__.py +0 -0
- {devops_bot_sdk-1.4.67 → devops_bot_sdk-1.4.71}/sdk/collectors/files.py +0 -0
- {devops_bot_sdk-1.4.67 → devops_bot_sdk-1.4.71}/sdk/collectors/process.py +0 -0
- {devops_bot_sdk-1.4.67 → devops_bot_sdk-1.4.71}/sdk/collectors/screenshot.py +0 -0
- {devops_bot_sdk-1.4.67 → devops_bot_sdk-1.4.71}/sdk/config.py +0 -0
- {devops_bot_sdk-1.4.67 → devops_bot_sdk-1.4.71}/sdk/crucial.py +0 -0
- {devops_bot_sdk-1.4.67 → devops_bot_sdk-1.4.71}/sdk/exceptions.py +0 -0
- {devops_bot_sdk-1.4.67 → devops_bot_sdk-1.4.71}/sdk/git_ops.py +0 -0
- {devops_bot_sdk-1.4.67 → devops_bot_sdk-1.4.71}/sdk/graphify.py +0 -0
- {devops_bot_sdk-1.4.67 → devops_bot_sdk-1.4.71}/sdk/hooks/__init__.py +0 -0
- {devops_bot_sdk-1.4.67 → devops_bot_sdk-1.4.71}/sdk/hooks/crucial_guard.py +0 -0
- {devops_bot_sdk-1.4.67 → devops_bot_sdk-1.4.71}/sdk/ipc/__init__.py +0 -0
- {devops_bot_sdk-1.4.67 → devops_bot_sdk-1.4.71}/sdk/ipc/electron_bridge.py +0 -0
- {devops_bot_sdk-1.4.67 → devops_bot_sdk-1.4.71}/sdk/local_exec.py +0 -0
- {devops_bot_sdk-1.4.67 → devops_bot_sdk-1.4.71}/sdk/models/__init__.py +0 -0
- {devops_bot_sdk-1.4.67 → devops_bot_sdk-1.4.71}/sdk/models/envelope.py +0 -0
- {devops_bot_sdk-1.4.67 → devops_bot_sdk-1.4.71}/sdk/models/requests.py +0 -0
- {devops_bot_sdk-1.4.67 → devops_bot_sdk-1.4.71}/sdk/models/responses.py +0 -0
- {devops_bot_sdk-1.4.67 → devops_bot_sdk-1.4.71}/sdk/models/snapshots.py +0 -0
- {devops_bot_sdk-1.4.67 → devops_bot_sdk-1.4.71}/sdk/py.typed +0 -0
- {devops_bot_sdk-1.4.67 → devops_bot_sdk-1.4.71}/sdk/sse.py +0 -0
- {devops_bot_sdk-1.4.67 → devops_bot_sdk-1.4.71}/sdk/test.py +0 -0
- {devops_bot_sdk-1.4.67 → devops_bot_sdk-1.4.71}/sdk/test_pipeline.py +0 -0
- {devops_bot_sdk-1.4.67 → devops_bot_sdk-1.4.71}/sdk/updater.py +0 -0
- {devops_bot_sdk-1.4.67 → devops_bot_sdk-1.4.71}/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.71"
|
|
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.71
|
|
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.71"
|
|
34
34
|
__author__ = "AgentOS"
|
|
35
35
|
|
|
36
36
|
from sdk.client import BackendClient
|
|
@@ -521,14 +521,13 @@ def _build_epic_prompt(jira_key: str, summary: str, description: str | None,
|
|
|
521
521
|
' {\n'
|
|
522
522
|
' "summary": "Short imperative story title (a JIRA task summary)",\n'
|
|
523
523
|
' "description": "The story in the USER STORY FORMAT below (Markdown).",\n'
|
|
524
|
-
' "humanInstructions": "Operator instructions to implement THIS story. MUST '
|
|
525
|
-
"repeat the same project location/path and constraints from the epic so the "
|
|
526
|
-
'coding run works in the right place.",\n'
|
|
527
524
|
' "assigneeEmail": "dev@company.com",\n'
|
|
528
525
|
' "points": 5\n'
|
|
529
526
|
" }\n"
|
|
530
527
|
" ]\n"
|
|
531
528
|
"}\n\n"
|
|
529
|
+
"Do NOT produce humanInstructions for the stories — created stories are clean "
|
|
530
|
+
"user-story artifacts; implementation instructions are added later.\n"
|
|
532
531
|
"Create as many stories as the epic genuinely needs (do not pad or truncate "
|
|
533
532
|
"artificially); each story must be independently implementable.\n"
|
|
534
533
|
"assigneeEmail is OPTIONAL per story: set it ONLY when the epic explicitly "
|
|
@@ -548,10 +547,11 @@ def _extract_json_block(text: str | None) -> dict | None:
|
|
|
548
547
|
return None
|
|
549
548
|
import json as _json
|
|
550
549
|
candidates = re.findall(r"```(?:json)?\s*(\{.*?\})\s*```", text, re.S | re.I)
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
550
|
+
# ALWAYS also consider the widest brace span — covers a missing/late closing
|
|
551
|
+
# fence, extra prose around the block, or a fenced capture that fails to parse.
|
|
552
|
+
start, end = text.find("{"), text.rfind("}")
|
|
553
|
+
if start != -1 and end > start:
|
|
554
|
+
candidates.append(text[start:end + 1])
|
|
555
555
|
for c in reversed(candidates):
|
|
556
556
|
try:
|
|
557
557
|
obj = _json.loads(c)
|
|
@@ -806,10 +806,26 @@ async def _handle_epic(
|
|
|
806
806
|
project_path, allowed_tools=_RECON_ALLOWED_TOOLS, # read-only analysis
|
|
807
807
|
github_token=await client.github_token(),
|
|
808
808
|
)
|
|
809
|
-
|
|
809
|
+
# A usage-limit hit must stop and retry later. For ANY other outcome, still try
|
|
810
|
+
# to parse the JSON — the model often produces a valid decomposition even when the
|
|
811
|
+
# run is flagged is_error (e.g. a stray read-only tool denial during exploration),
|
|
812
|
+
# and the result then lands in `error`. Don't discard that work over an is_error flag.
|
|
813
|
+
if gen.get("limit_exceeded"):
|
|
814
|
+
await client.log_activity(f"Epic {jira_key}: usage limit during decomposition — will retry after reset")
|
|
815
|
+
await client.move_to_backlog(tid)
|
|
816
|
+
await send(Envelope(
|
|
817
|
+
type=Envelope.TYPE_ERROR, thread_id=thread_id,
|
|
818
|
+
data={"code": "EPIC_DECOMPOSE_LIMIT", "task_id": tid,
|
|
819
|
+
"message": "Claude usage limit reached during epic decomposition"},
|
|
820
|
+
).model_dump())
|
|
821
|
+
return
|
|
822
|
+
doc = _extract_json_block(gen.get("result") or gen.get("error") or "")
|
|
810
823
|
stories = (doc or {}).get("stories") or []
|
|
811
824
|
if not doc or not stories:
|
|
812
|
-
|
|
825
|
+
had_output = bool(gen.get("result") or gen.get("error"))
|
|
826
|
+
reason = ("model output did not contain a parseable decomposition JSON"
|
|
827
|
+
if had_output else
|
|
828
|
+
(gen.get("error") or "no output from the decomposition run"))[:300]
|
|
813
829
|
await client.log_activity(f"Epic {jira_key}: decomposition failed — {reason}")
|
|
814
830
|
await client.move_to_backlog(tid)
|
|
815
831
|
await send(Envelope(
|
|
@@ -818,12 +834,12 @@ async def _handle_epic(
|
|
|
818
834
|
).model_dump())
|
|
819
835
|
return
|
|
820
836
|
|
|
821
|
-
# 2. Mark the Epic Done
|
|
822
|
-
|
|
837
|
+
# 2. Mark the Epic Done. Do NOT touch the Epic's description — the parent Epic's
|
|
838
|
+
# description stays exactly as the human wrote it; only the status and the AI
|
|
839
|
+
# plan are recorded.
|
|
823
840
|
plan = (doc.get("plan") or "")[:8000]
|
|
824
841
|
await client.update_task_ml(
|
|
825
|
-
tid, {"status": "Done", "
|
|
826
|
-
model_used=_EPIC_MODELS,
|
|
842
|
+
tid, {"status": "Done", "initialAiPlan": plan}, model_used=_EPIC_MODELS,
|
|
827
843
|
)
|
|
828
844
|
await send(Envelope(
|
|
829
845
|
type="step_update", thread_id=thread_id,
|
|
@@ -852,7 +868,9 @@ async def _handle_epic(
|
|
|
852
868
|
"status": "To Do",
|
|
853
869
|
"summary": str(st.get("summary", "")).strip()[:250],
|
|
854
870
|
"description": str(st.get("description", "") or "")[:20000],
|
|
855
|
-
|
|
871
|
+
# NO humanInstructions on AI-created stories — they are clean user-story
|
|
872
|
+
# artifacts; implementation instructions (repos/branch/etc.) are added
|
|
873
|
+
# later at the story/task stage, not baked in by the Epic.
|
|
856
874
|
"parentTaskId": tid,
|
|
857
875
|
}
|
|
858
876
|
if child_email:
|
|
@@ -15,6 +15,7 @@ Commands:
|
|
|
15
15
|
coding; no keys = all To Do Stories (alias: stories)
|
|
16
16
|
agentos-auto stop ask the running loop to pause after the current task
|
|
17
17
|
agentos-auto status show whether the background loop is running / stop pending
|
|
18
|
+
agentos-auto logs [-f] print the loop log (~/.agentos/auto.log); -f to follow live
|
|
18
19
|
agentos-auto update upgrade the SDK to the latest version
|
|
19
20
|
|
|
20
21
|
Options:
|
|
@@ -261,6 +262,50 @@ def _parse_ticket_keys(argv: list[str]) -> list[str]:
|
|
|
261
262
|
return out
|
|
262
263
|
|
|
263
264
|
|
|
265
|
+
def _show_logs(argv: list[str]) -> None:
|
|
266
|
+
"""`agentos-auto logs [-f] [--lines N]` — print the loop's log (~/.agentos/auto.log).
|
|
267
|
+
|
|
268
|
+
Prints the last N lines (default 200); with -f/--follow, then streams new lines
|
|
269
|
+
live (Ctrl-C to stop). Pure-Python tail — works on any platform, no `tail` needed.
|
|
270
|
+
"""
|
|
271
|
+
import time
|
|
272
|
+
|
|
273
|
+
follow = "-f" in argv or "--follow" in argv
|
|
274
|
+
n = 200
|
|
275
|
+
if "--lines" in argv:
|
|
276
|
+
try:
|
|
277
|
+
n = max(1, int(argv[argv.index("--lines") + 1]))
|
|
278
|
+
except (IndexError, ValueError):
|
|
279
|
+
pass
|
|
280
|
+
|
|
281
|
+
if not _LOG_FILE.exists():
|
|
282
|
+
print(f"no log yet at {_LOG_FILE} — start a run with `agentos-auto`.")
|
|
283
|
+
print(f"per-run claude transcripts: {_AGENTOS_DIR / 'logs'}")
|
|
284
|
+
return
|
|
285
|
+
|
|
286
|
+
try:
|
|
287
|
+
tail = _LOG_FILE.read_text(encoding="utf-8", errors="replace").splitlines()[-n:]
|
|
288
|
+
except Exception as exc: # noqa: BLE001
|
|
289
|
+
print(f"could not read {_LOG_FILE}: {exc}")
|
|
290
|
+
return
|
|
291
|
+
for line in tail:
|
|
292
|
+
print(line)
|
|
293
|
+
|
|
294
|
+
if follow:
|
|
295
|
+
print(f"\n— following {_LOG_FILE} (Ctrl-C to stop) —", flush=True)
|
|
296
|
+
try:
|
|
297
|
+
with open(_LOG_FILE, "r", encoding="utf-8", errors="replace") as f:
|
|
298
|
+
f.seek(0, 2) # jump to end; only stream NEW lines
|
|
299
|
+
while True:
|
|
300
|
+
line = f.readline()
|
|
301
|
+
if line:
|
|
302
|
+
print(line, end="", flush=True)
|
|
303
|
+
else:
|
|
304
|
+
time.sleep(0.5)
|
|
305
|
+
except KeyboardInterrupt:
|
|
306
|
+
pass
|
|
307
|
+
|
|
308
|
+
|
|
264
309
|
_current_task: str | None = None
|
|
265
310
|
|
|
266
311
|
|
|
@@ -464,6 +509,10 @@ def main() -> None:
|
|
|
464
509
|
print("stop pending: yes" if _stop_requested() else "stop pending: no")
|
|
465
510
|
return
|
|
466
511
|
|
|
512
|
+
if cmd == "logs":
|
|
513
|
+
_show_logs(argv)
|
|
514
|
+
return
|
|
515
|
+
|
|
467
516
|
if cmd in ("run", "resume", "ticket", "tickets", "story", "stories"):
|
|
468
517
|
# Run modes:
|
|
469
518
|
# run/resume → the whole To Do queue
|
|
@@ -528,7 +577,7 @@ def main() -> None:
|
|
|
528
577
|
_run_loop(workspace_root, only_keys, stories_only)
|
|
529
578
|
return
|
|
530
579
|
|
|
531
|
-
print(f"unknown command '{cmd}'. use: run | resume | ticket | story | stop | status | update")
|
|
580
|
+
print(f"unknown command '{cmd}'. use: run | resume | ticket | story | stop | status | logs | update")
|
|
532
581
|
sys.exit(1)
|
|
533
582
|
|
|
534
583
|
|
|
File without changes
|
|
File without changes
|
{devops_bot_sdk-1.4.67 → devops_bot_sdk-1.4.71}/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
|