pulse-coding-agent 0.1.0__py3-none-any.whl

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 (104) hide show
  1. pulse/__init__.py +5 -0
  2. pulse/__main__.py +4 -0
  3. pulse/agent.py +270 -0
  4. pulse/agent_manager.py +335 -0
  5. pulse/audit.py +70 -0
  6. pulse/auth.py +670 -0
  7. pulse/ci/github_client.py +66 -0
  8. pulse/ci/runner.py +28 -0
  9. pulse/cli.py +1075 -0
  10. pulse/cli_ui.py +977 -0
  11. pulse/config.py +167 -0
  12. pulse/context.py +960 -0
  13. pulse/conversations/__init__.py +8 -0
  14. pulse/conversations/manager.py +312 -0
  15. pulse/core/agent.py +188 -0
  16. pulse/core/planner.py +105 -0
  17. pulse/core/protocols.py +37 -0
  18. pulse/edits.py +65 -0
  19. pulse/episodic.py +93 -0
  20. pulse/eval/__init__.py +8 -0
  21. pulse/eval/trajectory_logger.py +91 -0
  22. pulse/eval/verifier.py +133 -0
  23. pulse/execution/__init__.py +5 -0
  24. pulse/execution/remote_task.py +76 -0
  25. pulse/git.py +162 -0
  26. pulse/interactive.py +234 -0
  27. pulse/mcp/__init__.py +4 -0
  28. pulse/mcp/client.py +215 -0
  29. pulse/mcp/local_tools.py +105 -0
  30. pulse/memory.py +212 -0
  31. pulse/mutations.py +283 -0
  32. pulse/orchestration/__init__.py +3 -0
  33. pulse/orchestration/orchestrator.py +162 -0
  34. pulse/patch.py +129 -0
  35. pulse/planner/__init__.py +3 -0
  36. pulse/planner/dag_planner.py +85 -0
  37. pulse/planner/execution_loop.py +159 -0
  38. pulse/production.py +235 -0
  39. pulse/provider.py +59 -0
  40. pulse/provider_keys.py +278 -0
  41. pulse/providers/__init__.py +26 -0
  42. pulse/providers/anthropic.py +65 -0
  43. pulse/providers/base.py +251 -0
  44. pulse/providers/deepseek.py +10 -0
  45. pulse/providers/failover.py +32 -0
  46. pulse/providers/gemini.py +66 -0
  47. pulse/providers/groq.py +10 -0
  48. pulse/providers/manager.py +262 -0
  49. pulse/providers/openai.py +40 -0
  50. pulse/providers/openrouter.py +20 -0
  51. pulse/py.typed +1 -0
  52. pulse/reasoning.py +570 -0
  53. pulse/refactor/__init__.py +3 -0
  54. pulse/refactor/impact_analyzer.py +44 -0
  55. pulse/repository.py +209 -0
  56. pulse/rpc.py +249 -0
  57. pulse/rule_synthesizer.py +54 -0
  58. pulse/runtime.py +217 -0
  59. pulse/safety/__init__.py +3 -0
  60. pulse/safety/safety_manager.py +97 -0
  61. pulse/sandbox/SECURITY.md +57 -0
  62. pulse/sandbox/__init__.py +57 -0
  63. pulse/sandbox/api.py +594 -0
  64. pulse/sandbox/audit.py +153 -0
  65. pulse/sandbox/backend/__init__.py +7 -0
  66. pulse/sandbox/backend/base.py +72 -0
  67. pulse/sandbox/backend/docker.py +498 -0
  68. pulse/sandbox/backend/host.py +140 -0
  69. pulse/sandbox/backend/remote.py +224 -0
  70. pulse/sandbox/errors.py +106 -0
  71. pulse/sandbox/filesystem.py +476 -0
  72. pulse/sandbox/git_safe.py +50 -0
  73. pulse/sandbox/lifecycle.py +88 -0
  74. pulse/sandbox/network.py +205 -0
  75. pulse/sandbox/path_validator.py +280 -0
  76. pulse/sandbox/policy.py +209 -0
  77. pulse/sandbox/process.py +331 -0
  78. pulse/sandbox/project.py +158 -0
  79. pulse/sandbox/python_safe.py +62 -0
  80. pulse/sandbox/remote/__init__.py +1 -0
  81. pulse/sandbox/remote/client.py +389 -0
  82. pulse/sandbox/remote/models.py +167 -0
  83. pulse/sandbox/remote/protocol.py +65 -0
  84. pulse/sandbox/remote/server.py +984 -0
  85. pulse/sandbox/remote/worker.py +175 -0
  86. pulse/sandbox/resources.py +236 -0
  87. pulse/sandbox/secrets.py +241 -0
  88. pulse/session_manager.py +365 -0
  89. pulse/software_engineer.py +189 -0
  90. pulse/storage.py +140 -0
  91. pulse/streaming.py +385 -0
  92. pulse/subprocesses.py +79 -0
  93. pulse/task_manager.py +2005 -0
  94. pulse/telemetry/__init__.py +25 -0
  95. pulse/telemetry/cost_tracker.py +95 -0
  96. pulse/telemetry/logger.py +110 -0
  97. pulse/tool_policy.py +197 -0
  98. pulse/tool_registry.py +163 -0
  99. pulse/tools.py +372 -0
  100. pulse/verification.py +118 -0
  101. pulse_coding_agent-0.1.0.dist-info/METADATA +211 -0
  102. pulse_coding_agent-0.1.0.dist-info/RECORD +104 -0
  103. pulse_coding_agent-0.1.0.dist-info/WHEEL +4 -0
  104. pulse_coding_agent-0.1.0.dist-info/entry_points.txt +4 -0
@@ -0,0 +1,66 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ from typing import Any
5
+
6
+ import httpx
7
+
8
+
9
+ class GitHubClient:
10
+ """Async wrapper around the GitHub REST API for CI operations."""
11
+
12
+ def __init__(self, token: str | None = None, repository: str | None = None) -> None:
13
+ self.token = token or os.getenv("GITHUB_TOKEN")
14
+ if not self.token:
15
+ raise RuntimeError("GitHub token not provided via argument or GITHUB_TOKEN env var")
16
+ self.repository = repository or os.getenv("GITHUB_REPOSITORY")
17
+ if not self.repository:
18
+ raise RuntimeError("GitHub repository not provided via argument or GITHUB_REPOSITORY env var")
19
+ self.owner, self.repo = self.repository.split('/')
20
+ self.base_url = "https://api.github.com"
21
+ self.headers = {
22
+ "Authorization": f"Bearer {self.token}",
23
+ "Accept": "application/vnd.github.v3+json",
24
+ }
25
+ self.client = httpx.AsyncClient(headers=self.headers, timeout=30.0)
26
+
27
+ async def _request(self, method: str, endpoint: str, **kwargs: Any) -> httpx.Response:
28
+ url = f"{self.base_url}{endpoint}"
29
+ response = await self.client.request(method, url, **kwargs)
30
+ response.raise_for_status()
31
+ return response
32
+
33
+ async def get_pr_diff(self, pr_number: int) -> str:
34
+ """Return the unified diff of a pull request as a string."""
35
+ endpoint = f"/repos/{self.owner}/{self.repo}/pulls/{pr_number}/diff"
36
+ resp = await self._request(
37
+ "GET",
38
+ endpoint,
39
+ headers={**self.headers, "Accept": "application/vnd.github.v3.diff"},
40
+ )
41
+ return resp.text
42
+
43
+ async def post_pr_comment(self, pr_number: int, body: str) -> dict[str, Any]:
44
+ """Create a top‑level comment on the PR."""
45
+ endpoint = f"/repos/{self.owner}/{self.repo}/issues/{pr_number}/comments"
46
+ payload = {"body": body}
47
+ resp = await self._request("POST", endpoint, json=payload)
48
+ return resp.json()
49
+
50
+ async def post_inline_review(self, pr_number: int, path: str, line: int, body: str) -> dict[str, Any]:
51
+ """Create an inline review comment on a specific file/line.
52
+
53
+ GitHub expects a review object with an array of comments. For simplicity we create a
54
+ single‑comment review using the "COMMENT" event.
55
+ """
56
+ endpoint = f"/repos/{self.owner}/{self.repo}/pulls/{pr_number}/reviews"
57
+ review_payload = {
58
+ "event": "COMMENT",
59
+ "body": body,
60
+ "comments": [{"path": path, "position": line, "body": body}],
61
+ }
62
+ resp = await self._request("POST", endpoint, json=review_payload)
63
+ return resp.json()
64
+
65
+ async def close(self) -> None:
66
+ await self.client.aclose()
pulse/ci/runner.py ADDED
@@ -0,0 +1,28 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+
5
+ from pulse.ci.github_client import GitHubClient
6
+
7
+
8
+ class CIRunner:
9
+ """Headless CI engine for GitHub Actions.
10
+
11
+ It downloads a PR diff, optionally runs analysis (e.g., PatchVerifier),
12
+ and posts a summary comment to the PR.
13
+ """
14
+
15
+ def __init__(self, client: GitHubClient, workspace: Path) -> None:
16
+ self.client = client
17
+ self.workspace = workspace
18
+
19
+ async def run_pr(self, pr_number: int) -> str:
20
+ """Process a pull request and post a comment.
21
+
22
+ Returns the comment body that was posted.
23
+ """
24
+ diff = await self.client.get_pr_diff(pr_number)
25
+ # Placeholder for analysis – in real implementation we would invoke AutonomousLoop etc.
26
+ comment_body = f"Processed PR #{pr_number}. Diff size: {len(diff)} characters."
27
+ await self.client.post_pr_comment(pr_number, comment_body)
28
+ return comment_body