devops-bot-sdk 1.4.65__tar.gz → 1.4.67__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.
Files changed (38) hide show
  1. {devops_bot_sdk-1.4.65 → devops_bot_sdk-1.4.67}/PKG-INFO +1 -1
  2. {devops_bot_sdk-1.4.65 → devops_bot_sdk-1.4.67}/devops_bot_sdk.egg-info/PKG-INFO +1 -1
  3. {devops_bot_sdk-1.4.65 → devops_bot_sdk-1.4.67}/pyproject.toml +1 -1
  4. {devops_bot_sdk-1.4.65 → devops_bot_sdk-1.4.67}/sdk/__init__.py +2 -2
  5. {devops_bot_sdk-1.4.65 → devops_bot_sdk-1.4.67}/sdk/client.py +1 -1
  6. {devops_bot_sdk-1.4.65 → devops_bot_sdk-1.4.67}/sdk/ipc/handlers.py +92 -20
  7. {devops_bot_sdk-1.4.65 → devops_bot_sdk-1.4.67}/README.md +0 -0
  8. {devops_bot_sdk-1.4.65 → devops_bot_sdk-1.4.67}/devops_bot_sdk.egg-info/SOURCES.txt +0 -0
  9. {devops_bot_sdk-1.4.65 → devops_bot_sdk-1.4.67}/devops_bot_sdk.egg-info/dependency_links.txt +0 -0
  10. {devops_bot_sdk-1.4.65 → devops_bot_sdk-1.4.67}/devops_bot_sdk.egg-info/entry_points.txt +0 -0
  11. {devops_bot_sdk-1.4.65 → devops_bot_sdk-1.4.67}/devops_bot_sdk.egg-info/requires.txt +0 -0
  12. {devops_bot_sdk-1.4.65 → devops_bot_sdk-1.4.67}/devops_bot_sdk.egg-info/top_level.txt +0 -0
  13. {devops_bot_sdk-1.4.65 → devops_bot_sdk-1.4.67}/sdk/collectors/__init__.py +0 -0
  14. {devops_bot_sdk-1.4.65 → devops_bot_sdk-1.4.67}/sdk/collectors/files.py +0 -0
  15. {devops_bot_sdk-1.4.65 → devops_bot_sdk-1.4.67}/sdk/collectors/process.py +0 -0
  16. {devops_bot_sdk-1.4.65 → devops_bot_sdk-1.4.67}/sdk/collectors/screenshot.py +0 -0
  17. {devops_bot_sdk-1.4.65 → devops_bot_sdk-1.4.67}/sdk/config.py +0 -0
  18. {devops_bot_sdk-1.4.65 → devops_bot_sdk-1.4.67}/sdk/crucial.py +0 -0
  19. {devops_bot_sdk-1.4.65 → devops_bot_sdk-1.4.67}/sdk/exceptions.py +0 -0
  20. {devops_bot_sdk-1.4.65 → devops_bot_sdk-1.4.67}/sdk/git_ops.py +0 -0
  21. {devops_bot_sdk-1.4.65 → devops_bot_sdk-1.4.67}/sdk/graphify.py +0 -0
  22. {devops_bot_sdk-1.4.65 → devops_bot_sdk-1.4.67}/sdk/hooks/__init__.py +0 -0
  23. {devops_bot_sdk-1.4.65 → devops_bot_sdk-1.4.67}/sdk/hooks/crucial_guard.py +0 -0
  24. {devops_bot_sdk-1.4.65 → devops_bot_sdk-1.4.67}/sdk/ipc/__init__.py +0 -0
  25. {devops_bot_sdk-1.4.65 → devops_bot_sdk-1.4.67}/sdk/ipc/electron_bridge.py +0 -0
  26. {devops_bot_sdk-1.4.65 → devops_bot_sdk-1.4.67}/sdk/local_exec.py +0 -0
  27. {devops_bot_sdk-1.4.65 → devops_bot_sdk-1.4.67}/sdk/models/__init__.py +0 -0
  28. {devops_bot_sdk-1.4.65 → devops_bot_sdk-1.4.67}/sdk/models/envelope.py +0 -0
  29. {devops_bot_sdk-1.4.65 → devops_bot_sdk-1.4.67}/sdk/models/requests.py +0 -0
  30. {devops_bot_sdk-1.4.65 → devops_bot_sdk-1.4.67}/sdk/models/responses.py +0 -0
  31. {devops_bot_sdk-1.4.65 → devops_bot_sdk-1.4.67}/sdk/models/snapshots.py +0 -0
  32. {devops_bot_sdk-1.4.65 → devops_bot_sdk-1.4.67}/sdk/py.typed +0 -0
  33. {devops_bot_sdk-1.4.65 → devops_bot_sdk-1.4.67}/sdk/run_auto.py +0 -0
  34. {devops_bot_sdk-1.4.65 → devops_bot_sdk-1.4.67}/sdk/sse.py +0 -0
  35. {devops_bot_sdk-1.4.65 → devops_bot_sdk-1.4.67}/sdk/test.py +0 -0
  36. {devops_bot_sdk-1.4.65 → devops_bot_sdk-1.4.67}/sdk/test_pipeline.py +0 -0
  37. {devops_bot_sdk-1.4.65 → devops_bot_sdk-1.4.67}/sdk/updater.py +0 -0
  38. {devops_bot_sdk-1.4.65 → devops_bot_sdk-1.4.67}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devops-bot-sdk
3
- Version: 1.4.65
3
+ Version: 1.4.67
4
4
  Summary: DevOps Bot Desktop SDK — thin client for the AgentOS Electron desktop app
5
5
  Author: noumanaziz2128
6
6
  License-Expression: LicenseRef-Proprietary
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devops-bot-sdk
3
- Version: 1.4.65
3
+ Version: 1.4.67
4
4
  Summary: DevOps Bot Desktop SDK — thin client for the AgentOS Electron desktop app
5
5
  Author: noumanaziz2128
6
6
  License-Expression: LicenseRef-Proprietary
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "devops-bot-sdk"
7
- version = "1.4.65"
7
+ version = "1.4.67"
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.65
3
+ Version: 1.4.67
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.65"
33
+ __version__ = "1.4.67"
34
34
  __author__ = "AgentOS"
35
35
 
36
36
  from sdk.client import BackendClient
@@ -58,7 +58,7 @@ def _notify_status(task_id: str, status: str) -> None:
58
58
  pass
59
59
 
60
60
 
61
- SDK_VERSION = "1.4.65"
61
+ SDK_VERSION = "1.4.67"
62
62
  _POLL_INTERVAL = 3.0
63
63
  _POLL_TIMEOUT = 600.0
64
64
  _ORCHESTRATE_TIMEOUT = 2700.0 # 45 min — covers approval wait + VPS execution time
@@ -594,6 +594,34 @@ def _epic_inherited_fields(task: dict) -> dict:
594
594
  return {k: v for k, v in fields.items() if v}
595
595
 
596
596
 
597
+ # Lines that name a directory to WRITE the generated user stories into (distinct
598
+ # from a code repo path). Matches story/file/folder/directory/mkdir/write hints
599
+ # and skips repo lines (github URL / "path:").
600
+ _STORIES_DIR_HINT = re.compile(
601
+ r"\b(user\s+stor|stories|mkdir|directory|folder|write|\.md)\b", re.I,
602
+ )
603
+
604
+
605
+ def _extract_stories_dir(text: str | None) -> str | None:
606
+ """A directory the instructions ask the user stories to be WRITTEN into, or None.
607
+
608
+ Scans lines that mention stories/files/a directory (but not code-repo lines that
609
+ carry a GitHub URL or a "path:" repo label) and returns the first filesystem path
610
+ found — e.g. "Create a new directory at /home/me/new_tasks and write the stories".
611
+ """
612
+ if not text:
613
+ return None
614
+ for line in text.splitlines():
615
+ low = line.lower()
616
+ if "github.com" in low or "path:" in low:
617
+ continue # a code repo line, not a stories-output directory
618
+ if _STORIES_DIR_HINT.search(line):
619
+ p = _extract_path_from_text(line)
620
+ if p:
621
+ return p
622
+ return None
623
+
624
+
597
625
  # ── Ticket validation gate (Epics + USER-driven Stories) ────────────────────
598
626
  # A strict quality gate: before the bot actions an Epic or a USER-created Story it
599
627
  # checks the ticket meets the required standard. On failure it posts a harsh,
@@ -616,30 +644,42 @@ def _build_validation_prompt(kind: str, jira_key: str, summary: str,
616
644
  "Description:\n" + (_clip_text(description.strip()) if description and description.strip() else "(none provided)"),
617
645
  "Human Instructions:\n" + (human.strip() if human and human.strip() else "(none provided)"),
618
646
  ]
647
+ is_epic = kind == "epic"
619
648
  parts.append(
620
- "Judge the ticket in the context of what it ACTUALLY asks for — it may be "
621
- "software, documentation, analysis, Finance, HR or operations work. Do NOT "
622
- "impose software requirements on a non-software ticket.\n\n"
649
+ "Judge the ticket for what it ACTUALLY asks for — software, documentation, "
650
+ "analysis, Finance, HR or operations. Do NOT impose requirements the ticket "
651
+ "does not need.\n\n"
623
652
  "A VALID ticket MUST have:\n"
624
653
  "- A clear, unambiguous goal and scope (no hand-waving).\n"
625
- "- A clearly-defined deliverable or outcome, and when a location matters "
626
- "WHERE to produce it (a folder path, a repository, or a document).\n"
627
- "- Observable, testable acceptance criteria (or an equally concrete definition of done).\n"
628
- "- ONLY IF the work requires CODE CHANGES to a software project: the target "
629
- "repository link(s) and/or file path(s), the branch/PR convention, and "
630
- "build/run/test steps. Do NOT demand these for documentation, content, analysis "
631
- "or other non-code deliverables.\n"
632
- + ("- Enough concrete detail to decompose into independent user stories.\n"
633
- if kind == "epic" else
634
- "- A clear 'As a <role>, I want <capability>, so that <benefit>' intent plus "
635
- "testable acceptance criteria.\n")
654
+ "- A clearly-defined deliverable/outcome (and where to produce it when a "
655
+ "location matters).\n"
656
+ "- Observable acceptance criteria (or an equally concrete definition of done).\n"
657
+ + (
658
+ # EPIC: a decomposition container NEVER require code-execution details.
659
+ "- Enough substance to DECOMPOSE into user stories.\n"
660
+ "IMPORTANT: this is an EPIC — a high-level container the system decomposes "
661
+ "into user stories. Do NOT require a repository URL, file paths, branch/PR "
662
+ "convention, or build/run/test commands at the epic level; those are "
663
+ "established LATER at the story/task stage, never in the epic. Even when the "
664
+ "epic describes software features, judge it ONLY on goal, scope, user "
665
+ "stories and epic-level acceptance criteria. NEVER reject an epic for missing "
666
+ "repository, branch, PR, build, or test details.\n"
667
+ if is_epic else
668
+ # STORY: repo details help but the PRD/coding stage grounds them.
669
+ "- A clear 'As a <role>, I want <capability>, so that <benefit>' intent plus "
670
+ "testable acceptance criteria.\n"
671
+ "For a code story, a target repo/path is helpful but NOT mandatory here — the "
672
+ "PRD/coding stage grounds it against the codebase. Do NOT reject solely for a "
673
+ "missing branch/PR convention or build/test steps.\n"
674
+ )
636
675
  + "- Any THIRD-PARTY INTEGRATION or human-effort dependency the work GENUINELY "
637
- "needs (API keys, OAuth credentials, external accounts, secrets, manual "
638
- "provisioning, DNS, billing) MUST be named WITH who provides it; if such a "
639
- "REQUIRED dependency is undefined, REJECT.\n\n"
640
- "A ticket that clearly states its deliverable and where to produce it is VALID "
641
- "even without repository/branch details. Reject only for genuinely missing or "
642
- "ambiguous information — not for absent software details the task does not need.\n\n"
676
+ "needs (API keys, OAuth credentials, external accounts, secrets, provisioning) "
677
+ "MUST be named WITH who provides it; if a REQUIRED dependency is undefined, REJECT.\n\n"
678
+ "Unrendered template placeholders an EMPTY `{{...}}` or `<...>` with no real "
679
+ "content are a valid reason to reject. But if a section contains real content "
680
+ "merely wrapped in stray markers, treat it as PRESENT, not missing.\n"
681
+ "Reject only for genuinely missing or ambiguous information — not for absent "
682
+ "execution details the ticket does not need at this stage.\n\n"
643
683
  "Output ONLY a fenced ```json block, nothing else:\n"
644
684
  "{\n"
645
685
  ' "valid": true or false,\n'
@@ -827,6 +867,38 @@ async def _handle_epic(
827
867
  data={"current_step": f" ↳ created To Do task: {fields['summary']}"},
828
868
  ).model_dump())
829
869
 
870
+ # 3b. Optionally ALSO write each story as a Markdown file to a directory named in
871
+ # the instructions (e.g. "create /home/me/new_tasks and write the user stories
872
+ # there"). This is IN ADDITION to the Story tickets. Best-effort — a file-write
873
+ # failure never fails the Epic.
874
+ stories_dir = _extract_stories_dir(human)
875
+ if stories_dir:
876
+ from pathlib import Path
877
+ try:
878
+ d = Path(stories_dir).expanduser()
879
+ d.mkdir(parents=True, exist_ok=True) # create from scratch
880
+ written = 0
881
+ for i, st in enumerate(stories[:_MAX_EPIC_STORIES], 1):
882
+ if not isinstance(st, dict) or not (st.get("summary") or "").strip():
883
+ continue
884
+ title = str(st.get("summary", "")).strip()
885
+ slug = re.sub(r"[^a-z0-9]+", "-", title.lower()).strip("-")[:50] or f"story-{i}"
886
+ content = f"# {title}\n\n{str(st.get('description', '') or '').strip()}\n"
887
+ (d / f"{i:02d}-{slug}.md").write_text(content, encoding="utf-8")
888
+ written += 1
889
+ await client.log_activity(f"Epic {jira_key}: wrote {written} user-story file(s) to {stories_dir}")
890
+ await send(Envelope(
891
+ type="step_update", thread_id=thread_id,
892
+ data={"jira_task_id": tid,
893
+ "current_step": f"Epic {jira_key}: wrote {written} user-story file(s) to {stories_dir}"},
894
+ ).model_dump())
895
+ except Exception as exc: # noqa: BLE001
896
+ await send(Envelope(
897
+ type="step_update", thread_id=thread_id,
898
+ data={"jira_task_id": tid,
899
+ "current_step": f"Epic {jira_key}: could not write story files to {stories_dir} — {str(exc)[:120]}"},
900
+ ).model_dump())
901
+
830
902
  await client.log_activity(
831
903
  f"Epic {jira_key}: Done — created {len(created)}/{len(stories)} To Do user Story(ies)"
832
904
  )