devops-bot-sdk 1.4.47__tar.gz → 1.4.55__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.47 → devops_bot_sdk-1.4.55}/PKG-INFO +1 -1
- {devops_bot_sdk-1.4.47 → devops_bot_sdk-1.4.55}/devops_bot_sdk.egg-info/PKG-INFO +1 -1
- {devops_bot_sdk-1.4.47 → devops_bot_sdk-1.4.55}/pyproject.toml +1 -1
- {devops_bot_sdk-1.4.47 → devops_bot_sdk-1.4.55}/sdk/__init__.py +2 -2
- {devops_bot_sdk-1.4.47 → devops_bot_sdk-1.4.55}/sdk/client.py +1 -1
- {devops_bot_sdk-1.4.47 → devops_bot_sdk-1.4.55}/sdk/ipc/handlers.py +189 -24
- {devops_bot_sdk-1.4.47 → devops_bot_sdk-1.4.55}/README.md +0 -0
- {devops_bot_sdk-1.4.47 → devops_bot_sdk-1.4.55}/devops_bot_sdk.egg-info/SOURCES.txt +0 -0
- {devops_bot_sdk-1.4.47 → devops_bot_sdk-1.4.55}/devops_bot_sdk.egg-info/dependency_links.txt +0 -0
- {devops_bot_sdk-1.4.47 → devops_bot_sdk-1.4.55}/devops_bot_sdk.egg-info/entry_points.txt +0 -0
- {devops_bot_sdk-1.4.47 → devops_bot_sdk-1.4.55}/devops_bot_sdk.egg-info/requires.txt +0 -0
- {devops_bot_sdk-1.4.47 → devops_bot_sdk-1.4.55}/devops_bot_sdk.egg-info/top_level.txt +0 -0
- {devops_bot_sdk-1.4.47 → devops_bot_sdk-1.4.55}/sdk/collectors/__init__.py +0 -0
- {devops_bot_sdk-1.4.47 → devops_bot_sdk-1.4.55}/sdk/collectors/files.py +0 -0
- {devops_bot_sdk-1.4.47 → devops_bot_sdk-1.4.55}/sdk/collectors/process.py +0 -0
- {devops_bot_sdk-1.4.47 → devops_bot_sdk-1.4.55}/sdk/collectors/screenshot.py +0 -0
- {devops_bot_sdk-1.4.47 → devops_bot_sdk-1.4.55}/sdk/config.py +0 -0
- {devops_bot_sdk-1.4.47 → devops_bot_sdk-1.4.55}/sdk/crucial.py +0 -0
- {devops_bot_sdk-1.4.47 → devops_bot_sdk-1.4.55}/sdk/exceptions.py +0 -0
- {devops_bot_sdk-1.4.47 → devops_bot_sdk-1.4.55}/sdk/git_ops.py +0 -0
- {devops_bot_sdk-1.4.47 → devops_bot_sdk-1.4.55}/sdk/graphify.py +0 -0
- {devops_bot_sdk-1.4.47 → devops_bot_sdk-1.4.55}/sdk/hooks/__init__.py +0 -0
- {devops_bot_sdk-1.4.47 → devops_bot_sdk-1.4.55}/sdk/hooks/crucial_guard.py +0 -0
- {devops_bot_sdk-1.4.47 → devops_bot_sdk-1.4.55}/sdk/ipc/__init__.py +0 -0
- {devops_bot_sdk-1.4.47 → devops_bot_sdk-1.4.55}/sdk/ipc/electron_bridge.py +0 -0
- {devops_bot_sdk-1.4.47 → devops_bot_sdk-1.4.55}/sdk/local_exec.py +0 -0
- {devops_bot_sdk-1.4.47 → devops_bot_sdk-1.4.55}/sdk/models/__init__.py +0 -0
- {devops_bot_sdk-1.4.47 → devops_bot_sdk-1.4.55}/sdk/models/envelope.py +0 -0
- {devops_bot_sdk-1.4.47 → devops_bot_sdk-1.4.55}/sdk/models/requests.py +0 -0
- {devops_bot_sdk-1.4.47 → devops_bot_sdk-1.4.55}/sdk/models/responses.py +0 -0
- {devops_bot_sdk-1.4.47 → devops_bot_sdk-1.4.55}/sdk/models/snapshots.py +0 -0
- {devops_bot_sdk-1.4.47 → devops_bot_sdk-1.4.55}/sdk/py.typed +0 -0
- {devops_bot_sdk-1.4.47 → devops_bot_sdk-1.4.55}/sdk/run_auto.py +0 -0
- {devops_bot_sdk-1.4.47 → devops_bot_sdk-1.4.55}/sdk/sse.py +0 -0
- {devops_bot_sdk-1.4.47 → devops_bot_sdk-1.4.55}/sdk/test.py +0 -0
- {devops_bot_sdk-1.4.47 → devops_bot_sdk-1.4.55}/sdk/test_pipeline.py +0 -0
- {devops_bot_sdk-1.4.47 → devops_bot_sdk-1.4.55}/sdk/updater.py +0 -0
- {devops_bot_sdk-1.4.47 → devops_bot_sdk-1.4.55}/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.55"
|
|
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.55
|
|
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.55"
|
|
34
34
|
__author__ = "AgentOS"
|
|
35
35
|
|
|
36
36
|
from sdk.client import BackendClient
|
|
@@ -210,6 +210,17 @@ def _build_local_prompt(
|
|
|
210
210
|
"before changing it.\n\n"
|
|
211
211
|
+ human_instructions.strip()
|
|
212
212
|
)
|
|
213
|
+
# 1b. If a PRD is present (a dev Story was converted to this Task with its PRD
|
|
214
|
+
# folded into the description), it is the AUTHORITATIVE spec — build the
|
|
215
|
+
# whole feature to satisfy it end-to-end.
|
|
216
|
+
if user_input and _PRD_MARKER in user_input:
|
|
217
|
+
parts.append(
|
|
218
|
+
"This task includes a PRD (Product Requirements Document) in its description "
|
|
219
|
+
"below. Treat the PRD as the AUTHORITATIVE specification: implement the WHOLE "
|
|
220
|
+
"feature to satisfy its Functional Requirements, Non-Functional Requirements, "
|
|
221
|
+
"and Acceptance Criteria, following the PRD end-to-end. Do not narrow or skip "
|
|
222
|
+
"any part of the PRD's scope."
|
|
223
|
+
)
|
|
213
224
|
# 2. Distilled plan (acceptance criteria + steps) — the compact, actionable
|
|
214
225
|
# content the backend planner derived from the full description.
|
|
215
226
|
sp = structured_plan or {}
|
|
@@ -231,6 +242,15 @@ def _build_local_prompt(
|
|
|
231
242
|
"above are authoritative if anything conflicts) ===\n"
|
|
232
243
|
+ _clip_text(user_input.strip())
|
|
233
244
|
)
|
|
245
|
+
# House standards — if this task produces a PRD document, hold it to the
|
|
246
|
+
# same standard format the bot uses everywhere else (a Task converted from a
|
|
247
|
+
# Story keeps its PRD directive in the instructions).
|
|
248
|
+
if _wants_prd(human_instructions) or _wants_prd(user_input):
|
|
249
|
+
parts.append(
|
|
250
|
+
"If you create a PRD / product-requirements document (e.g. a PRD.md), "
|
|
251
|
+
"write it in this STANDARD PRD FORMAT (keep the numbered headings):\n"
|
|
252
|
+
+ _PRD_FORMAT
|
|
253
|
+
)
|
|
234
254
|
if git_managed:
|
|
235
255
|
# The target is a git repo the SDK manages — it branches before and
|
|
236
256
|
# commits/pushes/opens the PR after, so the agent must not touch git here.
|
|
@@ -360,13 +380,78 @@ _MAX_EPIC_STORIES = int(os.getenv("AGENTOS_MAX_EPIC_STORIES", "") or 8)
|
|
|
360
380
|
# Label recorded in the ticket's modelUsed on Epic completion.
|
|
361
381
|
_EPIC_MODELS = [m.strip() for m in (os.getenv("AGENTOS_EPIC_MODELS", "") or "claude-code").split(",") if m.strip()]
|
|
362
382
|
|
|
383
|
+
# ── Standard output formats ─────────────────────────────────────────────────
|
|
384
|
+
# One house style for every generated artifact so Epics, Stories and PRDs read
|
|
385
|
+
# consistently across tickets. Referenced by the generation prompts below.
|
|
386
|
+
_EPIC_FORMAT = (
|
|
387
|
+
"## Epic\n<concise epic title>\n\n"
|
|
388
|
+
"## Overview\n<1-2 paragraph summary of the goal and context>\n\n"
|
|
389
|
+
"## Business Value / Goal\n<why this matters; the outcome it drives>\n\n"
|
|
390
|
+
"## Scope\n**In scope:** <what is included>\n**Out of scope:** <what is not>\n\n"
|
|
391
|
+
"## User Stories\n1. <story title> — <one-line summary>\n2. <story title> — <one-line summary>\n\n"
|
|
392
|
+
"## Epic-level Acceptance Criteria\n- <observable, high-level pass/fail criteria>\n\n"
|
|
393
|
+
"## Dependencies & Risks\n- <key dependencies, assumptions, risks>"
|
|
394
|
+
)
|
|
395
|
+
_USER_STORY_FORMAT = (
|
|
396
|
+
"## User Story\n"
|
|
397
|
+
"As a <role>, I want <capability>, so that <benefit>.\n\n"
|
|
398
|
+
"## Acceptance Criteria\n"
|
|
399
|
+
"- Given <context>, when <action>, then <expected outcome>.\n"
|
|
400
|
+
"- <list every testable criterion, Gherkin Given/When/Then style>\n\n"
|
|
401
|
+
"## Notes & Constraints\n"
|
|
402
|
+
"- <context, dependencies, constraints; for software work: affected files/modules & patterns to follow>\n\n"
|
|
403
|
+
"## Definition of Done\n"
|
|
404
|
+
"- Delivered against the acceptance criteria above\n"
|
|
405
|
+
"- Reviewed / validated (for software: tests added & passing)\n"
|
|
406
|
+
"- Documentation updated where relevant"
|
|
407
|
+
)
|
|
408
|
+
_PRD_FORMAT = (
|
|
409
|
+
"# PRD: <title>\n\n"
|
|
410
|
+
"## 1. Overview\n<what the feature is and why, in brief>\n\n"
|
|
411
|
+
"## 2. Goals & Non-Goals\n<what it must achieve; what is explicitly out of scope>\n\n"
|
|
412
|
+
"## 3. Current Behaviour & Context\n<the existing system/modules this touches — "
|
|
413
|
+
"grounded in the REAL codebase: files, components, current flow>\n\n"
|
|
414
|
+
"## 4. How It Works — Mechanism\n<the core mechanism end-to-end: the exact flow of "
|
|
415
|
+
"control and data, step by step, from trigger/input to output/persistence. Describe "
|
|
416
|
+
"how the feature actually functions, not just what it does>\n\n"
|
|
417
|
+
"## 5. Architecture & Components\n<components/modules/services involved and their "
|
|
418
|
+
"responsibilities; where new code lives; how they interact>\n\n"
|
|
419
|
+
"## 6. Data Model & Schema\n<entities, fields + types, relationships, indexes, and "
|
|
420
|
+
"any migrations / schema changes>\n\n"
|
|
421
|
+
"## 7. API / Interface Contracts\n<each endpoint or interface: HTTP method + path, "
|
|
422
|
+
"request shape, response shape, status codes, auth. Include example payloads>\n\n"
|
|
423
|
+
"## 8. Detailed Logic & Business Rules\n<algorithms, validation rules, state "
|
|
424
|
+
"transitions, sequence of operations, ordering/idempotency, concurrency>\n\n"
|
|
425
|
+
"## 9. Data Flow & Integrations\n<how data moves between components/services; "
|
|
426
|
+
"external systems, events, queues, third-party APIs>\n\n"
|
|
427
|
+
"## 10. Error Handling & Edge Cases\n<failure modes, validation errors, retries, "
|
|
428
|
+
"timeouts, boundary conditions, empty/duplicate/large inputs>\n\n"
|
|
429
|
+
"## 11. Security & Performance (Non-Functional)\n<authn/authz, input hardening, "
|
|
430
|
+
"secrets, rate limits, performance/scale targets, accessibility where relevant>\n\n"
|
|
431
|
+
"## 12. Testing Strategy\n<unit / integration / e2e coverage and the key test cases "
|
|
432
|
+
"that prove each requirement>\n\n"
|
|
433
|
+
"## 13. Acceptance Criteria\n<observable, testable pass/fail tied to the mechanism>\n\n"
|
|
434
|
+
"## 14. Dependencies, Risks & Rollout\n<dependencies, assumptions, risks, migration "
|
|
435
|
+
"and rollout/phasing>"
|
|
436
|
+
)
|
|
437
|
+
|
|
363
438
|
|
|
364
439
|
def _build_epic_prompt(jira_key: str, summary: str, description: str | None,
|
|
365
440
|
human_instructions: str | None) -> str:
|
|
366
441
|
"""Read-only prompt that turns an Epic into a decomposition JSON."""
|
|
367
442
|
parts: list[str] = [
|
|
368
|
-
"You are decomposing a JIRA EPIC into implementable
|
|
369
|
-
"ONLY — do NOT create, edit, or delete any file.",
|
|
443
|
+
"You are decomposing a JIRA EPIC into implementable user stories. This is "
|
|
444
|
+
"ANALYSIS ONLY — do NOT create, edit, or delete any file.",
|
|
445
|
+
"Faithfulness (read first — this prevents hallucinated stories):\n"
|
|
446
|
+
"- Derive stories ONLY from what the epic actually states or clearly implies. "
|
|
447
|
+
"Do NOT invent features, scope, integrations, tools, or requirements that are "
|
|
448
|
+
"not grounded in the epic (or, for software, in the REAL codebase you inspect).\n"
|
|
449
|
+
"- If something needed is missing or ambiguous, capture it as an open question "
|
|
450
|
+
"in that story's Notes — do NOT fabricate a solution.\n"
|
|
451
|
+
"- Prefer fewer, well-grounded stories over many speculative ones. Every story "
|
|
452
|
+
"must trace back to something in the epic.\n"
|
|
453
|
+
"- This epic may be for ANY domain (software, Finance, HR, operations, …). Match "
|
|
454
|
+
"the stories to the epic's actual domain; do not assume it is software.",
|
|
370
455
|
f"=== EPIC {jira_key} ===\nSummary: {summary}",
|
|
371
456
|
]
|
|
372
457
|
if description and description.strip():
|
|
@@ -378,18 +463,20 @@ def _build_epic_prompt(jira_key: str, summary: str, description: str | None,
|
|
|
378
463
|
+ human_instructions.strip()
|
|
379
464
|
)
|
|
380
465
|
parts.append(
|
|
381
|
-
"
|
|
382
|
-
"use graphify / Read / Glob / Grep)
|
|
383
|
-
"
|
|
466
|
+
"Ground your work first: if this is a SOFTWARE project, inspect the existing "
|
|
467
|
+
"codebase in this directory (read CLAUDE.md, use graphify / Read / Glob / Grep) "
|
|
468
|
+
"so the stories fit the REAL architecture. For a NON-software epic (Finance, HR, "
|
|
469
|
+
"operations, …), ground the stories in the epic's stated details and any "
|
|
470
|
+
"reference material present — never in invented facts. Then produce the "
|
|
471
|
+
"decomposition.\n\n"
|
|
384
472
|
"Output ONLY a single fenced ```json block and nothing after it, with shape:\n"
|
|
385
473
|
"{\n"
|
|
386
|
-
' "epic_description": "
|
|
387
|
-
"write-up covering goal, the user stories, acceptance criteria and scope.\",\n"
|
|
474
|
+
' "epic_description": "The epic write-up in the EPIC FORMAT below (Markdown).",\n'
|
|
388
475
|
' "plan": "An ordered, numbered high-level implementation plan.",\n'
|
|
389
476
|
' "stories": [\n'
|
|
390
477
|
' {\n'
|
|
391
478
|
' "summary": "Short imperative story title (a JIRA task summary)",\n'
|
|
392
|
-
' "description": "
|
|
479
|
+
' "description": "The story in the USER STORY FORMAT below (Markdown).",\n'
|
|
393
480
|
' "humanInstructions": "Operator instructions to implement THIS story. MUST '
|
|
394
481
|
"repeat the same project location/path and constraints from the epic so the "
|
|
395
482
|
'coding run works in the right place.",\n'
|
|
@@ -397,12 +484,16 @@ def _build_epic_prompt(jira_key: str, summary: str, description: str | None,
|
|
|
397
484
|
' "points": 5\n'
|
|
398
485
|
" }\n"
|
|
399
486
|
" ]\n"
|
|
400
|
-
"}\n"
|
|
487
|
+
"}\n\n"
|
|
401
488
|
"Create as many stories as the epic genuinely needs (do not pad or truncate "
|
|
402
489
|
"artificially); each story must be independently implementable.\n"
|
|
403
490
|
"assigneeEmail is OPTIONAL per story: set it ONLY when the epic explicitly "
|
|
404
491
|
"assigns that specific work to a named person/email (e.g. 'assign the API to "
|
|
405
|
-
"alice@x.com'); otherwise omit it
|
|
492
|
+
"alice@x.com'); otherwise omit it.\n\n"
|
|
493
|
+
"=== EPIC FORMAT (epic_description MUST follow this exactly) ===\n"
|
|
494
|
+
+ _EPIC_FORMAT
|
|
495
|
+
+ "\n\n=== USER STORY FORMAT (every story.description MUST follow this exactly) ===\n"
|
|
496
|
+
+ _USER_STORY_FORMAT
|
|
406
497
|
)
|
|
407
498
|
return "\n\n".join(parts)
|
|
408
499
|
|
|
@@ -582,12 +673,34 @@ def _wants_prd(text: str | None) -> bool:
|
|
|
582
673
|
return bool(text and _PRD_RE.search(text))
|
|
583
674
|
|
|
584
675
|
|
|
676
|
+
# Signals that a ticket is DEVELOPMENT work (→ always gets a PRD). Deliberately
|
|
677
|
+
# code-specific so Finance/HR/ops tickets don't false-positive (they get a PRD
|
|
678
|
+
# only when explicitly requested).
|
|
679
|
+
_DEV_RE = re.compile(
|
|
680
|
+
r"github\.com/|gitlab\.com/|bitbucket\.org/|\b(?:repo(?:sitory)?|codebase|"
|
|
681
|
+
r"source\s*code|frontend|front-end|back-?end|pull\s+requests?|merge\s+requests?|"
|
|
682
|
+
r"\bPRs?\b|feature\s+branch|create\s+a?\s*branch|commit|deploy(?:ment)?|compile|"
|
|
683
|
+
r"build\s+pipeline|microservice|endpoint|api\s+contract|database\s+migration|"
|
|
684
|
+
r"unit\s+test)\b",
|
|
685
|
+
re.I,
|
|
686
|
+
)
|
|
687
|
+
|
|
688
|
+
|
|
689
|
+
def _is_dev_task(text: str | None) -> bool:
|
|
690
|
+
"""True when the text clearly describes software-development work."""
|
|
691
|
+
return bool(text and _DEV_RE.search(text))
|
|
692
|
+
|
|
693
|
+
|
|
585
694
|
def _build_prd_prompt(jira_key: str, summary: str, user_story: str | None,
|
|
586
695
|
human_instructions: str | None) -> str:
|
|
587
|
-
"""Read-only prompt that produces a PRD (Markdown) for a user story."""
|
|
696
|
+
"""Read-only prompt that produces a TECHNICAL PRD (Markdown) for a user story."""
|
|
588
697
|
parts: list[str] = [
|
|
589
|
-
"Write a PRD (Product Requirements Document) for the user story below.
|
|
590
|
-
"
|
|
698
|
+
"Write a TECHNICAL PRD (Product Requirements Document) for the user story below. "
|
|
699
|
+
"It must fully specify the MECHANISM — how the feature works end-to-end "
|
|
700
|
+
"(architecture, components, data model, API/interface contracts, control & data "
|
|
701
|
+
"flow, business logic, error handling) — in enough detail that a developer can "
|
|
702
|
+
"implement it directly from the PRD without guessing. This is ANALYSIS ONLY — do "
|
|
703
|
+
"NOT create, edit, or delete any file.",
|
|
591
704
|
f"=== USER STORY {jira_key} ===\nSummary: {summary}",
|
|
592
705
|
]
|
|
593
706
|
if user_story and user_story.strip():
|
|
@@ -595,11 +708,17 @@ def _build_prd_prompt(jira_key: str, summary: str, user_story: str | None,
|
|
|
595
708
|
if human_instructions and human_instructions.strip():
|
|
596
709
|
parts.append("Operator instructions:\n" + human_instructions.strip())
|
|
597
710
|
parts.append(
|
|
598
|
-
"
|
|
599
|
-
"
|
|
600
|
-
"
|
|
601
|
-
"
|
|
602
|
-
"
|
|
711
|
+
"Ground the PRD in reality — for software, FIRST understand the current codebase "
|
|
712
|
+
"STRUCTURE (folder layout, key modules, existing patterns, data models, APIs) via "
|
|
713
|
+
"CLAUDE.md, graphify and Read/Glob/Grep, then specify the mechanism against the "
|
|
714
|
+
"REAL files, modules, data models and APIs that exist; for a non-software task, "
|
|
715
|
+
"ground it in "
|
|
716
|
+
"the story's stated details and mark technical sections that don't apply as "
|
|
717
|
+
"'N/A'. Do NOT invent requirements, systems, endpoints, or facts not supported by "
|
|
718
|
+
"the story or the code you inspect. Output ONLY the PRD as Markdown — no preamble, "
|
|
719
|
+
"no code edits — following this PRD FORMAT exactly (keep the numbered section "
|
|
720
|
+
"headings):\n\n"
|
|
721
|
+
+ _PRD_FORMAT
|
|
603
722
|
)
|
|
604
723
|
return "\n\n".join(parts)
|
|
605
724
|
|
|
@@ -621,14 +740,25 @@ async def _handle_story(
|
|
|
621
740
|
summary = task.get("summary", "") or ""
|
|
622
741
|
user_story = task.get("description") or ""
|
|
623
742
|
human = task.get("humanInstructions")
|
|
624
|
-
|
|
625
|
-
|
|
743
|
+
# STEP 1 — validate whether this is a CODEBASE (development) task: repo links /
|
|
744
|
+
# file paths in the instructions, or dev signals (PRs, branches, endpoints,
|
|
745
|
+
# deploy, …). A codebase task ALWAYS gets a technical PRD built from the current
|
|
746
|
+
# codebase; other domains (Finance, HR, …) get one only when explicitly asked.
|
|
747
|
+
has_repo = bool(_extract_repo_targets(human)) or bool(_extract_repo_targets(user_story))
|
|
748
|
+
is_codebase_task = has_repo or _is_dev_task(human) or _is_dev_task(user_story)
|
|
749
|
+
wants_prd = is_codebase_task or _wants_prd(human) or _wants_prd(user_story)
|
|
750
|
+
|
|
751
|
+
if is_codebase_task:
|
|
752
|
+
step = ("validated as a codebase task — building a technical PRD from the "
|
|
753
|
+
"current codebase, then converting to Task")
|
|
754
|
+
elif wants_prd:
|
|
755
|
+
step = "generating the requested PRD, then converting to Task"
|
|
756
|
+
else:
|
|
757
|
+
step = "converting to Task"
|
|
626
758
|
await send(Envelope(
|
|
627
759
|
type="step_update", thread_id=thread_id,
|
|
628
760
|
data={"jira_task_id": tid, "task_id": tid,
|
|
629
|
-
"current_step": f"Story {jira_key}: "
|
|
630
|
-
+ ("generating PRD, then " if wants_prd else "")
|
|
631
|
-
+ "converting to Task"},
|
|
761
|
+
"current_step": f"Story {jira_key}: {step}"},
|
|
632
762
|
).model_dump())
|
|
633
763
|
|
|
634
764
|
# Idempotent: if a PRD is already in the description, don't regenerate it or
|
|
@@ -1039,6 +1169,40 @@ async def _code_one_repo(
|
|
|
1039
1169
|
except Exception: # noqa: BLE001
|
|
1040
1170
|
branch_info = None
|
|
1041
1171
|
|
|
1172
|
+
# 3a. Technical PRD for a CODEBASE task that doesn't have one yet. A Task created
|
|
1173
|
+
# directly (not via a Story) may carry only a user-story/feature description —
|
|
1174
|
+
# for codebase work we first turn the recon understanding into a technical PRD
|
|
1175
|
+
# and build to it, exactly like a Story-derived Task. Resumes the recon session
|
|
1176
|
+
# (already understands the codebase) so it's cheap; persists the PRD to the
|
|
1177
|
+
# ticket and to pending (shared → other repos reuse it and skip regeneration).
|
|
1178
|
+
# Skipped when a PRD is already present, on a resume, or for non-git targets.
|
|
1179
|
+
if (is_git and recon_session and not resume_session_id
|
|
1180
|
+
and _PRD_MARKER not in (pending.get("user_input") or "")):
|
|
1181
|
+
await send(Envelope(
|
|
1182
|
+
type="step_update", thread_id=thread_id,
|
|
1183
|
+
data={"status": "running",
|
|
1184
|
+
"current_step": f"[{name}] Codebase task — writing a technical PRD from the codebase"},
|
|
1185
|
+
).model_dump())
|
|
1186
|
+
prd_res = await local_exec.run_claude_local(
|
|
1187
|
+
"Using your exploration above, write a TECHNICAL PRD for this task that fully "
|
|
1188
|
+
"specifies the mechanism (how it works end-to-end) against the REAL code you "
|
|
1189
|
+
"found. Output ONLY the PRD as Markdown, following this format exactly:\n\n"
|
|
1190
|
+
+ _PRD_FORMAT,
|
|
1191
|
+
repo_path, allowed_tools=_RECON_ALLOWED_TOOLS, # read-only
|
|
1192
|
+
github_token=gh_token, resume_session_id=recon_session,
|
|
1193
|
+
)
|
|
1194
|
+
recon_session = prd_res.get("session_id") or recon_session
|
|
1195
|
+
prd = (prd_res.get("result") or "").strip() if prd_res.get("ok") else ""
|
|
1196
|
+
if prd:
|
|
1197
|
+
enriched = (
|
|
1198
|
+
f"{pending.get('user_input') or ''}\n\n---\n\n{_PRD_MARKER}\n\n{prd}"
|
|
1199
|
+
)[:20000]
|
|
1200
|
+
pending["user_input"] = enriched # shared across repos → reused, not regenerated
|
|
1201
|
+
try:
|
|
1202
|
+
await client.update_task_ml(task_id, {"description": enriched}, model_used=_EPIC_MODELS)
|
|
1203
|
+
except Exception: # noqa: BLE001 — persisting the PRD is best-effort
|
|
1204
|
+
pass
|
|
1205
|
+
|
|
1042
1206
|
await send(Envelope(
|
|
1043
1207
|
type="step_update", thread_id=thread_id,
|
|
1044
1208
|
data={"status": "running", "current_step": f"Executing locally in {name} (claude_code)"},
|
|
@@ -1047,7 +1211,8 @@ async def _code_one_repo(
|
|
|
1047
1211
|
# Build the prompt with framing that matches the target: a git repo we manage
|
|
1048
1212
|
# (branch + PR) vs a plain local folder (BA/analyst deliverables, no git/PR).
|
|
1049
1213
|
# When recon ran, the implementation resumes that session so its grounded plan
|
|
1050
|
-
# stays in context;
|
|
1214
|
+
# (and the technical PRD, if generated) stays in context; if a PRD is present the
|
|
1215
|
+
# prompt makes it the authoritative spec.
|
|
1051
1216
|
prompt = _build_local_prompt(
|
|
1052
1217
|
pending["user_input"], pending.get("structured_plan"),
|
|
1053
1218
|
pending.get("human_instructions"),
|
|
File without changes
|
|
File without changes
|
{devops_bot_sdk-1.4.47 → devops_bot_sdk-1.4.55}/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
|