devops-bot-sdk 1.4.60__tar.gz → 1.4.62__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.60 → devops_bot_sdk-1.4.62}/PKG-INFO +1 -1
- {devops_bot_sdk-1.4.60 → devops_bot_sdk-1.4.62}/devops_bot_sdk.egg-info/PKG-INFO +1 -1
- {devops_bot_sdk-1.4.60 → devops_bot_sdk-1.4.62}/pyproject.toml +1 -1
- {devops_bot_sdk-1.4.60 → devops_bot_sdk-1.4.62}/sdk/__init__.py +2 -2
- {devops_bot_sdk-1.4.60 → devops_bot_sdk-1.4.62}/sdk/client.py +1 -1
- {devops_bot_sdk-1.4.60 → devops_bot_sdk-1.4.62}/sdk/ipc/handlers.py +96 -45
- {devops_bot_sdk-1.4.60 → devops_bot_sdk-1.4.62}/README.md +0 -0
- {devops_bot_sdk-1.4.60 → devops_bot_sdk-1.4.62}/devops_bot_sdk.egg-info/SOURCES.txt +0 -0
- {devops_bot_sdk-1.4.60 → devops_bot_sdk-1.4.62}/devops_bot_sdk.egg-info/dependency_links.txt +0 -0
- {devops_bot_sdk-1.4.60 → devops_bot_sdk-1.4.62}/devops_bot_sdk.egg-info/entry_points.txt +0 -0
- {devops_bot_sdk-1.4.60 → devops_bot_sdk-1.4.62}/devops_bot_sdk.egg-info/requires.txt +0 -0
- {devops_bot_sdk-1.4.60 → devops_bot_sdk-1.4.62}/devops_bot_sdk.egg-info/top_level.txt +0 -0
- {devops_bot_sdk-1.4.60 → devops_bot_sdk-1.4.62}/sdk/collectors/__init__.py +0 -0
- {devops_bot_sdk-1.4.60 → devops_bot_sdk-1.4.62}/sdk/collectors/files.py +0 -0
- {devops_bot_sdk-1.4.60 → devops_bot_sdk-1.4.62}/sdk/collectors/process.py +0 -0
- {devops_bot_sdk-1.4.60 → devops_bot_sdk-1.4.62}/sdk/collectors/screenshot.py +0 -0
- {devops_bot_sdk-1.4.60 → devops_bot_sdk-1.4.62}/sdk/config.py +0 -0
- {devops_bot_sdk-1.4.60 → devops_bot_sdk-1.4.62}/sdk/crucial.py +0 -0
- {devops_bot_sdk-1.4.60 → devops_bot_sdk-1.4.62}/sdk/exceptions.py +0 -0
- {devops_bot_sdk-1.4.60 → devops_bot_sdk-1.4.62}/sdk/git_ops.py +0 -0
- {devops_bot_sdk-1.4.60 → devops_bot_sdk-1.4.62}/sdk/graphify.py +0 -0
- {devops_bot_sdk-1.4.60 → devops_bot_sdk-1.4.62}/sdk/hooks/__init__.py +0 -0
- {devops_bot_sdk-1.4.60 → devops_bot_sdk-1.4.62}/sdk/hooks/crucial_guard.py +0 -0
- {devops_bot_sdk-1.4.60 → devops_bot_sdk-1.4.62}/sdk/ipc/__init__.py +0 -0
- {devops_bot_sdk-1.4.60 → devops_bot_sdk-1.4.62}/sdk/ipc/electron_bridge.py +0 -0
- {devops_bot_sdk-1.4.60 → devops_bot_sdk-1.4.62}/sdk/local_exec.py +0 -0
- {devops_bot_sdk-1.4.60 → devops_bot_sdk-1.4.62}/sdk/models/__init__.py +0 -0
- {devops_bot_sdk-1.4.60 → devops_bot_sdk-1.4.62}/sdk/models/envelope.py +0 -0
- {devops_bot_sdk-1.4.60 → devops_bot_sdk-1.4.62}/sdk/models/requests.py +0 -0
- {devops_bot_sdk-1.4.60 → devops_bot_sdk-1.4.62}/sdk/models/responses.py +0 -0
- {devops_bot_sdk-1.4.60 → devops_bot_sdk-1.4.62}/sdk/models/snapshots.py +0 -0
- {devops_bot_sdk-1.4.60 → devops_bot_sdk-1.4.62}/sdk/py.typed +0 -0
- {devops_bot_sdk-1.4.60 → devops_bot_sdk-1.4.62}/sdk/run_auto.py +0 -0
- {devops_bot_sdk-1.4.60 → devops_bot_sdk-1.4.62}/sdk/sse.py +0 -0
- {devops_bot_sdk-1.4.60 → devops_bot_sdk-1.4.62}/sdk/test.py +0 -0
- {devops_bot_sdk-1.4.60 → devops_bot_sdk-1.4.62}/sdk/test_pipeline.py +0 -0
- {devops_bot_sdk-1.4.60 → devops_bot_sdk-1.4.62}/sdk/updater.py +0 -0
- {devops_bot_sdk-1.4.60 → devops_bot_sdk-1.4.62}/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.62"
|
|
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.62
|
|
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.62"
|
|
34
34
|
__author__ = "AgentOS"
|
|
35
35
|
|
|
36
36
|
from sdk.client import BackendClient
|
|
@@ -854,10 +854,14 @@ def _build_prd_prompt(jira_key: str, summary: str, user_story: str | None,
|
|
|
854
854
|
|
|
855
855
|
async def _handle_story(
|
|
856
856
|
client: BackendClient, task: dict, payload: dict, send: Callable, thread_id: str,
|
|
857
|
-
) -> None:
|
|
857
|
+
) -> str | None:
|
|
858
858
|
"""Run a Story: optionally generate a PRD (when instructed) into the description,
|
|
859
859
|
then convert the ticket to a Task (To Do) for the coding run.
|
|
860
860
|
|
|
861
|
+
Returns the effective (PRD-enriched) description on success, or None on failure.
|
|
862
|
+
The caller uses the returned description to code the now-Task in the SAME run
|
|
863
|
+
(default `agentos-auto`); the `story` command discards it (convert-only).
|
|
864
|
+
|
|
861
865
|
Best-effort. If a PRD was explicitly instructed but generation fails, the ticket
|
|
862
866
|
goes to Backlog for retry (so the PRD requirement isn't silently dropped); a
|
|
863
867
|
conversion failure likewise backlogs it.
|
|
@@ -955,9 +959,11 @@ async def _handle_story(
|
|
|
955
959
|
type="step_update", thread_id=thread_id,
|
|
956
960
|
data={"jira_task_id": tid,
|
|
957
961
|
"current_step": f"Story {jira_key} → Task (To Do)"
|
|
958
|
-
+ (" + PRD in description" if prd_in_desc else "")
|
|
959
|
-
+ " — run again to implement"},
|
|
962
|
+
+ (" + PRD in description" if prd_in_desc else "")},
|
|
960
963
|
).model_dump())
|
|
964
|
+
# The effective description (PRD-enriched when generated/present) so the caller
|
|
965
|
+
# can code the now-Task in the same run.
|
|
966
|
+
return new_description or user_story
|
|
961
967
|
|
|
962
968
|
|
|
963
969
|
async def _run_local_pipeline(
|
|
@@ -1298,35 +1304,55 @@ async def _code_one_repo(
|
|
|
1298
1304
|
except Exception: # noqa: BLE001
|
|
1299
1305
|
branch_info = None
|
|
1300
1306
|
|
|
1301
|
-
# 3a. Technical PRD
|
|
1302
|
-
#
|
|
1303
|
-
#
|
|
1304
|
-
#
|
|
1305
|
-
# (
|
|
1306
|
-
#
|
|
1307
|
-
#
|
|
1308
|
-
if
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1307
|
+
# 3a. Technical PRD grounding (codebase tasks). The BACKEND converts a Story to a
|
|
1308
|
+
# Task and adds a FIRST-PASS PRD to the description; here we GROUND that PRD
|
|
1309
|
+
# against the REAL codebase (correcting file paths, contracts, data models to
|
|
1310
|
+
# what actually exists) before building to it. If no PRD is present at all
|
|
1311
|
+
# (edge case), we generate one. Reuses the recon session (already understands
|
|
1312
|
+
# the codebase), persists the result to the ticket + pending (shared → other
|
|
1313
|
+
# repos reuse it), and runs once per ticket. Skipped on a resume / non-git.
|
|
1314
|
+
if is_git and recon_session and not resume_session_id and not pending.get("_prd_grounded"):
|
|
1315
|
+
current = pending.get("user_input") or ""
|
|
1316
|
+
has_prd = _PRD_MARKER in current
|
|
1317
|
+
if has_prd:
|
|
1318
|
+
before, _, existing_prd = current.partition(_PRD_MARKER)
|
|
1319
|
+
await send(Envelope(
|
|
1320
|
+
type="step_update", thread_id=thread_id,
|
|
1321
|
+
data={"status": "running",
|
|
1322
|
+
"current_step": f"[{name}] Grounding the PRD against the current codebase"},
|
|
1323
|
+
).model_dump())
|
|
1324
|
+
instruction = (
|
|
1325
|
+
"The task description contains a PRD (below), drafted by the planner and "
|
|
1326
|
+
"NOT necessarily written against THIS exact codebase. Using your "
|
|
1327
|
+
"exploration above, REFINE it so every file path, module, API contract, "
|
|
1328
|
+
"data model and integration matches what ACTUALLY exists in this repo. "
|
|
1329
|
+
"Keep the same PRD sections/format; correct anything inaccurate; do NOT "
|
|
1330
|
+
"invent. Output ONLY the refined PRD as Markdown.\n\n"
|
|
1331
|
+
"=== Current PRD ===\n" + existing_prd.strip()
|
|
1332
|
+
)
|
|
1333
|
+
else:
|
|
1334
|
+
before = current.rstrip() + "\n\n---\n\n"
|
|
1335
|
+
await send(Envelope(
|
|
1336
|
+
type="step_update", thread_id=thread_id,
|
|
1337
|
+
data={"status": "running",
|
|
1338
|
+
"current_step": f"[{name}] Codebase task — writing a technical PRD from the codebase"},
|
|
1339
|
+
).model_dump())
|
|
1340
|
+
instruction = (
|
|
1341
|
+
"Using your exploration above, write a TECHNICAL PRD for this task that "
|
|
1342
|
+
"fully specifies the mechanism (how it works end-to-end) against the REAL "
|
|
1343
|
+
"code you found. Output ONLY the PRD as Markdown, following this format "
|
|
1344
|
+
"exactly:\n\n" + _PRD_FORMAT
|
|
1345
|
+
)
|
|
1315
1346
|
prd_res = await local_exec.run_claude_local(
|
|
1316
|
-
|
|
1317
|
-
"specifies the mechanism (how it works end-to-end) against the REAL code you "
|
|
1318
|
-
"found. Output ONLY the PRD as Markdown, following this format exactly:\n\n"
|
|
1319
|
-
+ _PRD_FORMAT,
|
|
1320
|
-
repo_path, allowed_tools=_RECON_ALLOWED_TOOLS, # read-only
|
|
1347
|
+
instruction, repo_path, allowed_tools=_RECON_ALLOWED_TOOLS, # read-only
|
|
1321
1348
|
github_token=gh_token, resume_session_id=recon_session,
|
|
1322
1349
|
)
|
|
1323
1350
|
recon_session = prd_res.get("session_id") or recon_session
|
|
1324
1351
|
prd = (prd_res.get("result") or "").strip() if prd_res.get("ok") else ""
|
|
1325
1352
|
if prd:
|
|
1326
|
-
enriched =
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
pending["user_input"] = enriched # shared across repos → reused, not regenerated
|
|
1353
|
+
enriched = f"{before}{_PRD_MARKER}\n\n{prd}"[:20000]
|
|
1354
|
+
pending["user_input"] = enriched # shared across repos → reused
|
|
1355
|
+
pending["_prd_grounded"] = True # ground once per ticket
|
|
1330
1356
|
try:
|
|
1331
1357
|
await client.update_task_ml(task_id, {"description": enriched}, model_used=_EPIC_MODELS)
|
|
1332
1358
|
except Exception: # noqa: BLE001 — persisting the PRD is best-effort
|
|
@@ -2846,38 +2872,63 @@ async def handle_orchestrate_auto_local_run(
|
|
|
2846
2872
|
# never marked In Progress/Done — only ever converted
|
|
2847
2873
|
# Task → implemented by the normal pipeline below (In Progress → Done)
|
|
2848
2874
|
# Each is isolated: a failure must not abort the remaining queue.
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
driven_by = str(task.get("drivenBy") or "").strip().upper()
|
|
2856
|
-
needs_validation = (ttype == "epic") or (ttype == "story" and driven_by != "SYSTEM")
|
|
2875
|
+
# Validation gate: Epics always; a Story only when USER-driven (a
|
|
2876
|
+
# SYSTEM/bot-created Story is trusted). A rejected ticket is commented +
|
|
2877
|
+
# moved to Backlog inside the gate — skip it here.
|
|
2878
|
+
driven_by = str(task.get("drivenBy") or "").strip().upper()
|
|
2879
|
+
|
|
2880
|
+
if ttype == "epic":
|
|
2857
2881
|
try:
|
|
2858
|
-
if
|
|
2859
|
-
client, task, ttype, payload, send, thread_id
|
|
2860
|
-
):
|
|
2882
|
+
if not await _validate_ticket_or_reject(client, task, "epic", payload, send, thread_id):
|
|
2861
2883
|
processed += 1
|
|
2862
2884
|
continue
|
|
2863
|
-
await
|
|
2885
|
+
await _handle_epic(client, task, payload, send, thread_id)
|
|
2864
2886
|
except Exception as exc: # noqa: BLE001
|
|
2865
|
-
logger.warning("auto_local
|
|
2887
|
+
logger.warning("auto_local.epic_failed task=%s err=%s", tid, exc)
|
|
2866
2888
|
try:
|
|
2867
|
-
await client.log_activity(f"Task {tid}:
|
|
2868
|
-
|
|
2869
|
-
# marked In Progress/Done/Backlog) so developers keep it.
|
|
2870
|
-
if ttype == "epic":
|
|
2871
|
-
await client.move_to_backlog(tid)
|
|
2889
|
+
await client.log_activity(f"Task {tid}: epic handling errored — {str(exc)[:200]}")
|
|
2890
|
+
await client.move_to_backlog(tid)
|
|
2872
2891
|
except Exception: # noqa: BLE001
|
|
2873
2892
|
pass
|
|
2874
2893
|
await send(Envelope(
|
|
2875
2894
|
type=Envelope.TYPE_ERROR, thread_id=thread_id,
|
|
2876
|
-
data={"code":
|
|
2895
|
+
data={"code": "EPIC_DECOMPOSE_FAILED", "task_id": tid, "message": str(exc)[:200]},
|
|
2877
2896
|
).model_dump())
|
|
2878
2897
|
processed += 1
|
|
2879
2898
|
continue
|
|
2880
2899
|
|
|
2900
|
+
if ttype == "story":
|
|
2901
|
+
try:
|
|
2902
|
+
if driven_by != "SYSTEM" and not await _validate_ticket_or_reject(
|
|
2903
|
+
client, task, "story", payload, send, thread_id
|
|
2904
|
+
):
|
|
2905
|
+
processed += 1
|
|
2906
|
+
continue
|
|
2907
|
+
new_desc = await _handle_story(client, task, payload, send, thread_id)
|
|
2908
|
+
except Exception as exc: # noqa: BLE001
|
|
2909
|
+
logger.warning("auto_local.story_failed task=%s err=%s", tid, exc)
|
|
2910
|
+
await client.log_activity(f"Task {tid}: story handling errored — {str(exc)[:200]}")
|
|
2911
|
+
await send(Envelope(
|
|
2912
|
+
type=Envelope.TYPE_ERROR, thread_id=thread_id,
|
|
2913
|
+
data={"code": "STORY_HANDLE_FAILED", "task_id": tid, "message": str(exc)[:200]},
|
|
2914
|
+
).model_dump())
|
|
2915
|
+
processed += 1
|
|
2916
|
+
continue
|
|
2917
|
+
# `agentos-auto story` (stories_only) = convert-only, stop here.
|
|
2918
|
+
# Conversion failure (new_desc None) also stops. Otherwise fall
|
|
2919
|
+
# through and code the now-Task IN THE SAME RUN (default agentos-auto).
|
|
2920
|
+
if stories_only or not new_desc:
|
|
2921
|
+
processed += 1
|
|
2922
|
+
continue
|
|
2923
|
+
task = {**task, "type": "Task", "description": new_desc}
|
|
2924
|
+
ttype = "task"
|
|
2925
|
+
await send(Envelope(
|
|
2926
|
+
type="step_update", thread_id=thread_id,
|
|
2927
|
+
data={"jira_task_id": tid,
|
|
2928
|
+
"current_step": f"{jira_key}: implementing the converted Task now (In Progress → Done)"},
|
|
2929
|
+
).model_dump())
|
|
2930
|
+
# ↓ falls through to the normal Task pipeline below
|
|
2931
|
+
|
|
2881
2932
|
task_payload = {
|
|
2882
2933
|
"thread_id": thread_id,
|
|
2883
2934
|
"jira_task_id": tid,
|
|
File without changes
|
|
File without changes
|
{devops_bot_sdk-1.4.60 → devops_bot_sdk-1.4.62}/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
|