devops-bot-sdk 1.4.74__tar.gz → 1.4.76__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.74 → devops_bot_sdk-1.4.76}/PKG-INFO +1 -1
- {devops_bot_sdk-1.4.74 → devops_bot_sdk-1.4.76}/devops_bot_sdk.egg-info/PKG-INFO +1 -1
- {devops_bot_sdk-1.4.74 → devops_bot_sdk-1.4.76}/pyproject.toml +1 -1
- {devops_bot_sdk-1.4.74 → devops_bot_sdk-1.4.76}/sdk/__init__.py +2 -2
- {devops_bot_sdk-1.4.74 → devops_bot_sdk-1.4.76}/sdk/client.py +1 -1
- {devops_bot_sdk-1.4.74 → devops_bot_sdk-1.4.76}/sdk/ipc/handlers.py +101 -7
- {devops_bot_sdk-1.4.74 → devops_bot_sdk-1.4.76}/README.md +0 -0
- {devops_bot_sdk-1.4.74 → devops_bot_sdk-1.4.76}/devops_bot_sdk.egg-info/SOURCES.txt +0 -0
- {devops_bot_sdk-1.4.74 → devops_bot_sdk-1.4.76}/devops_bot_sdk.egg-info/dependency_links.txt +0 -0
- {devops_bot_sdk-1.4.74 → devops_bot_sdk-1.4.76}/devops_bot_sdk.egg-info/entry_points.txt +0 -0
- {devops_bot_sdk-1.4.74 → devops_bot_sdk-1.4.76}/devops_bot_sdk.egg-info/requires.txt +0 -0
- {devops_bot_sdk-1.4.74 → devops_bot_sdk-1.4.76}/devops_bot_sdk.egg-info/top_level.txt +0 -0
- {devops_bot_sdk-1.4.74 → devops_bot_sdk-1.4.76}/sdk/collectors/__init__.py +0 -0
- {devops_bot_sdk-1.4.74 → devops_bot_sdk-1.4.76}/sdk/collectors/files.py +0 -0
- {devops_bot_sdk-1.4.74 → devops_bot_sdk-1.4.76}/sdk/collectors/process.py +0 -0
- {devops_bot_sdk-1.4.74 → devops_bot_sdk-1.4.76}/sdk/collectors/screenshot.py +0 -0
- {devops_bot_sdk-1.4.74 → devops_bot_sdk-1.4.76}/sdk/config.py +0 -0
- {devops_bot_sdk-1.4.74 → devops_bot_sdk-1.4.76}/sdk/crucial.py +0 -0
- {devops_bot_sdk-1.4.74 → devops_bot_sdk-1.4.76}/sdk/exceptions.py +0 -0
- {devops_bot_sdk-1.4.74 → devops_bot_sdk-1.4.76}/sdk/git_ops.py +0 -0
- {devops_bot_sdk-1.4.74 → devops_bot_sdk-1.4.76}/sdk/graphify.py +0 -0
- {devops_bot_sdk-1.4.74 → devops_bot_sdk-1.4.76}/sdk/hooks/__init__.py +0 -0
- {devops_bot_sdk-1.4.74 → devops_bot_sdk-1.4.76}/sdk/hooks/crucial_guard.py +0 -0
- {devops_bot_sdk-1.4.74 → devops_bot_sdk-1.4.76}/sdk/ipc/__init__.py +0 -0
- {devops_bot_sdk-1.4.74 → devops_bot_sdk-1.4.76}/sdk/ipc/electron_bridge.py +0 -0
- {devops_bot_sdk-1.4.74 → devops_bot_sdk-1.4.76}/sdk/local_exec.py +0 -0
- {devops_bot_sdk-1.4.74 → devops_bot_sdk-1.4.76}/sdk/models/__init__.py +0 -0
- {devops_bot_sdk-1.4.74 → devops_bot_sdk-1.4.76}/sdk/models/envelope.py +0 -0
- {devops_bot_sdk-1.4.74 → devops_bot_sdk-1.4.76}/sdk/models/requests.py +0 -0
- {devops_bot_sdk-1.4.74 → devops_bot_sdk-1.4.76}/sdk/models/responses.py +0 -0
- {devops_bot_sdk-1.4.74 → devops_bot_sdk-1.4.76}/sdk/models/snapshots.py +0 -0
- {devops_bot_sdk-1.4.74 → devops_bot_sdk-1.4.76}/sdk/py.typed +0 -0
- {devops_bot_sdk-1.4.74 → devops_bot_sdk-1.4.76}/sdk/run_auto.py +0 -0
- {devops_bot_sdk-1.4.74 → devops_bot_sdk-1.4.76}/sdk/sse.py +0 -0
- {devops_bot_sdk-1.4.74 → devops_bot_sdk-1.4.76}/sdk/test.py +0 -0
- {devops_bot_sdk-1.4.74 → devops_bot_sdk-1.4.76}/sdk/test_pipeline.py +0 -0
- {devops_bot_sdk-1.4.74 → devops_bot_sdk-1.4.76}/sdk/updater.py +0 -0
- {devops_bot_sdk-1.4.74 → devops_bot_sdk-1.4.76}/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.76"
|
|
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.76
|
|
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.76"
|
|
34
34
|
__author__ = "AgentOS"
|
|
35
35
|
|
|
36
36
|
from sdk.client import BackendClient
|
|
@@ -624,19 +624,17 @@ def _extract_email(text: str | None) -> str | None:
|
|
|
624
624
|
|
|
625
625
|
|
|
626
626
|
def _epic_inherited_fields(task: dict) -> dict:
|
|
627
|
-
"""Parent-Epic fields a child Task should inherit (drops empties).
|
|
628
|
-
def _date(v: object) -> str | None:
|
|
629
|
-
s = str(v or "")
|
|
630
|
-
return s[:10] if s else None # ISO datetime → YYYY-MM-DD
|
|
627
|
+
"""Parent-Epic fields a child Task should inherit (drops empties).
|
|
631
628
|
|
|
629
|
+
Time-related fields (startDate, dueDate, slaTarget) are intentionally NOT
|
|
630
|
+
inherited/sent — they're optional on the POST and left for the backend/board to
|
|
631
|
+
set, so the create call never carries a stale or wrongly-formatted date.
|
|
632
|
+
"""
|
|
632
633
|
fields = {
|
|
633
634
|
"projectKey": task.get("projectKey"),
|
|
634
635
|
"priority": task.get("priority"),
|
|
635
636
|
"assigneeEmail": (task.get("assignee") or {}).get("email"),
|
|
636
637
|
"teamId": task.get("teamId"),
|
|
637
|
-
"startDate": _date(task.get("startDate")),
|
|
638
|
-
"dueDate": _date(task.get("dueDate")),
|
|
639
|
-
"slaTarget": task.get("slaTarget"),
|
|
640
638
|
}
|
|
641
639
|
sprint = task.get("sprint") or {}
|
|
642
640
|
if sprint.get("jiraSprintId"):
|
|
@@ -2995,6 +2993,60 @@ async def _poll_fresh_approval(
|
|
|
2995
2993
|
return "timeout"
|
|
2996
2994
|
|
|
2997
2995
|
|
|
2996
|
+
async def _gate_transform_approval(
|
|
2997
|
+
client: BackendClient, tid: str, jira_key: str, summary: str | None, action: str,
|
|
2998
|
+
send: Callable, thread_id: str, should_stop: Callable[[], bool] | None,
|
|
2999
|
+
) -> str:
|
|
3000
|
+
"""Human-approval gate for a non-coding TRANSFORM (Epic decomposition /
|
|
3001
|
+
Story→Task conversion) when agentMode=True. Sends the WhatsApp request and WAITS
|
|
3002
|
+
for the decision. Returns 'approved' | 'rejected' | 'stopped'. On a 15-min timeout
|
|
3003
|
+
the ticket goes to Backlog and we keep polling for a late reply. Does NOT change
|
|
3004
|
+
ticket status itself — the handler owns that (an Epic marks itself In Progress; a
|
|
3005
|
+
Story never does)."""
|
|
3006
|
+
label = jira_key or tid
|
|
3007
|
+
wa_summary = summary or jira_key or "task"
|
|
3008
|
+
await send(Envelope(
|
|
3009
|
+
type=Envelope.TYPE_AWAITING_APPROVAL, thread_id=thread_id,
|
|
3010
|
+
data={"jira_key": jira_key, "task_id": tid,
|
|
3011
|
+
"current_step": f"{label}: awaiting approval to {action}"},
|
|
3012
|
+
).model_dump())
|
|
3013
|
+
|
|
3014
|
+
async def _send_wa() -> bool:
|
|
3015
|
+
ok = await client.notify_whatsapp(
|
|
3016
|
+
tid, f"Approval needed for {label}: {action} — reply on WhatsApp to approve or reject.",
|
|
3017
|
+
summary=wa_summary,
|
|
3018
|
+
)
|
|
3019
|
+
note = "approval request sent" if ok else "approval request FAILED to send"
|
|
3020
|
+
await send(Envelope(
|
|
3021
|
+
type="step_update", thread_id=thread_id,
|
|
3022
|
+
data={"current_step": f"{label}: {note}"},
|
|
3023
|
+
).model_dump())
|
|
3024
|
+
try:
|
|
3025
|
+
await client.log_activity(f"Task {tid}: {note} ({action})")
|
|
3026
|
+
except Exception: # noqa: BLE001
|
|
3027
|
+
pass
|
|
3028
|
+
return ok
|
|
3029
|
+
|
|
3030
|
+
await _send_wa()
|
|
3031
|
+
decision = await _poll_approval(
|
|
3032
|
+
client, tid, should_stop,
|
|
3033
|
+
fallback_notify=_send_wa, fallback_after_s=_FIRST_GATE_WA_FALLBACK_S,
|
|
3034
|
+
)
|
|
3035
|
+
if decision == "timeout":
|
|
3036
|
+
await client.move_to_backlog(tid)
|
|
3037
|
+
await send(Envelope(
|
|
3038
|
+
type="step_update", thread_id=thread_id,
|
|
3039
|
+
data={"current_step": f"{label}: no approval in 15m — Backlog; polling for late approval"},
|
|
3040
|
+
).model_dump())
|
|
3041
|
+
while True:
|
|
3042
|
+
if should_stop is not None and should_stop():
|
|
3043
|
+
return "stopped"
|
|
3044
|
+
late = await client.approval_status(tid)
|
|
3045
|
+
if late in ("approved", "rejected"):
|
|
3046
|
+
return late
|
|
3047
|
+
await asyncio.sleep(_APPROVAL_POLL_INTERVAL_S)
|
|
3048
|
+
return decision
|
|
3049
|
+
|
|
2998
3050
|
|
|
2999
3051
|
async def handle_orchestrate_auto_local_run(
|
|
3000
3052
|
client: BackendClient, payload: dict, send: Callable,
|
|
@@ -3105,6 +3157,27 @@ async def handle_orchestrate_auto_local_run(
|
|
|
3105
3157
|
if not await _validate_ticket_or_reject(client, task, "epic", payload, send, thread_id):
|
|
3106
3158
|
processed += 1
|
|
3107
3159
|
continue
|
|
3160
|
+
# agentMode gate: wait for human approval before decomposing.
|
|
3161
|
+
if agent_mode:
|
|
3162
|
+
dec = await _gate_transform_approval(
|
|
3163
|
+
client, tid, jira_key, task.get("summary"),
|
|
3164
|
+
"decompose this Epic into user stories",
|
|
3165
|
+
send, thread_id, should_stop,
|
|
3166
|
+
)
|
|
3167
|
+
if dec == "stopped":
|
|
3168
|
+
await send(Envelope(
|
|
3169
|
+
type=Envelope.TYPE_DONE, thread_id=thread_id,
|
|
3170
|
+
data={"mode": "orchestrate-auto-local", "status": "paused",
|
|
3171
|
+
"processed": processed, "task_count": total},
|
|
3172
|
+
).model_dump())
|
|
3173
|
+
return
|
|
3174
|
+
if dec != "approved":
|
|
3175
|
+
await send(Envelope(
|
|
3176
|
+
type="step_update", thread_id=thread_id,
|
|
3177
|
+
data={"current_step": f"{jira_key}: {dec} — Epic not decomposed"},
|
|
3178
|
+
).model_dump())
|
|
3179
|
+
processed += 1
|
|
3180
|
+
continue
|
|
3108
3181
|
await _handle_epic(client, task, payload, send, thread_id)
|
|
3109
3182
|
except Exception as exc: # noqa: BLE001
|
|
3110
3183
|
logger.warning("auto_local.epic_failed task=%s err=%s", tid, exc)
|
|
@@ -3127,6 +3200,27 @@ async def handle_orchestrate_auto_local_run(
|
|
|
3127
3200
|
):
|
|
3128
3201
|
processed += 1
|
|
3129
3202
|
continue
|
|
3203
|
+
# agentMode gate: wait for human approval before converting Story→Task.
|
|
3204
|
+
if agent_mode:
|
|
3205
|
+
dec = await _gate_transform_approval(
|
|
3206
|
+
client, tid, jira_key, task.get("summary"),
|
|
3207
|
+
"convert this Story into a Task",
|
|
3208
|
+
send, thread_id, should_stop,
|
|
3209
|
+
)
|
|
3210
|
+
if dec == "stopped":
|
|
3211
|
+
await send(Envelope(
|
|
3212
|
+
type=Envelope.TYPE_DONE, thread_id=thread_id,
|
|
3213
|
+
data={"mode": "orchestrate-auto-local", "status": "paused",
|
|
3214
|
+
"processed": processed, "task_count": total},
|
|
3215
|
+
).model_dump())
|
|
3216
|
+
return
|
|
3217
|
+
if dec != "approved":
|
|
3218
|
+
await send(Envelope(
|
|
3219
|
+
type="step_update", thread_id=thread_id,
|
|
3220
|
+
data={"current_step": f"{jira_key}: {dec} — Story not converted"},
|
|
3221
|
+
).model_dump())
|
|
3222
|
+
processed += 1
|
|
3223
|
+
continue
|
|
3130
3224
|
new_desc = await _handle_story(client, task, payload, send, thread_id)
|
|
3131
3225
|
except Exception as exc: # noqa: BLE001
|
|
3132
3226
|
logger.warning("auto_local.story_failed task=%s err=%s", tid, exc)
|
|
File without changes
|
|
File without changes
|
{devops_bot_sdk-1.4.74 → devops_bot_sdk-1.4.76}/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
|