bamboo-coding 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 (62) hide show
  1. agent/__init__.py +0 -0
  2. agent/bamboo_git_agent/__init__.py +0 -0
  3. agent/bamboo_git_agent/capabilities/__init__.py +0 -0
  4. agent/bamboo_git_agent/capabilities/repo.py +189 -0
  5. agent/bamboo_git_agent/config.py +76 -0
  6. agent/bamboo_git_agent/controller_client.py +73 -0
  7. agent/bamboo_git_agent/journal.py +209 -0
  8. agent/bamboo_git_agent/main.py +164 -0
  9. agent/bamboo_git_agent/protocol.py +21 -0
  10. agent/bamboo_git_agent/status.py +59 -0
  11. api/__init__.py +2 -0
  12. api/commit.py +82 -0
  13. api/repository.py +592 -0
  14. bamboo_coding/__init__.py +3 -0
  15. bamboo_coding/client/__init__.py +3 -0
  16. bamboo_coding/client/capabilities/__init__.py +1 -0
  17. bamboo_coding/client/capabilities/repo.py +279 -0
  18. bamboo_coding/client/config.py +179 -0
  19. bamboo_coding/client/controller_client.py +112 -0
  20. bamboo_coding/client/journal.py +1 -0
  21. bamboo_coding/client/main.py +425 -0
  22. bamboo_coding/client/status.py +59 -0
  23. bamboo_coding/client/terminal_runtime.py +251 -0
  24. bamboo_coding/server/__init__.py +3 -0
  25. bamboo_coding/server/core/__init__.py +1 -0
  26. bamboo_coding/server/core/config.py +1 -0
  27. bamboo_coding/server/main.py +39 -0
  28. bamboo_coding/shared/__init__.py +39 -0
  29. bamboo_coding/shared/protocol.py +1 -0
  30. bamboo_coding-0.1.0.dist-info/METADATA +284 -0
  31. bamboo_coding-0.1.0.dist-info/RECORD +62 -0
  32. bamboo_coding-0.1.0.dist-info/WHEEL +5 -0
  33. bamboo_coding-0.1.0.dist-info/entry_points.txt +3 -0
  34. bamboo_coding-0.1.0.dist-info/top_level.txt +6 -0
  35. controller/__init__.py +0 -0
  36. controller/app/__init__.py +0 -0
  37. controller/app/api/__init__.py +0 -0
  38. controller/app/api/agents/__init__.py +3 -0
  39. controller/app/api/agents/ws.py +133 -0
  40. controller/app/api/public/__init__.py +11 -0
  41. controller/app/api/public/repos.py +207 -0
  42. controller/app/api/public/terminals.py +64 -0
  43. controller/app/core/__init__.py +0 -0
  44. controller/app/core/config.py +20 -0
  45. controller/app/core/errors.py +14 -0
  46. controller/app/db/__init__.py +0 -0
  47. controller/app/db/models.py +42 -0
  48. controller/app/db/session.py +74 -0
  49. controller/app/main.py +71 -0
  50. controller/app/schemas/__init__.py +23 -0
  51. controller/app/schemas/agent_messages.py +21 -0
  52. controller/app/schemas/public.py +3 -0
  53. controller/app/services/__init__.py +0 -0
  54. controller/app/services/agents.py +108 -0
  55. controller/app/services/registrations.py +17 -0
  56. controller/app/services/repositories.py +85 -0
  57. controller/app/services/router.py +140 -0
  58. controller/app/services/tasks.py +104 -0
  59. controller/app/services/terminals.py +148 -0
  60. git_utils.py +2238 -0
  61. shared/__init__.py +39 -0
  62. shared/protocol.py +253 -0
shared/__init__.py ADDED
@@ -0,0 +1,39 @@
1
+ from .protocol import (
2
+ AgentRegisterMessage,
3
+ CapabilityDescriptor,
4
+ ClientInfo,
5
+ ClientStatusMessage,
6
+ PublicRepositorySummary,
7
+ PublicRootSummary,
8
+ RepositoryDescriptor,
9
+ RootDescriptor,
10
+ RuntimeHealth,
11
+ TaskMessage,
12
+ TerminalCloseMessage,
13
+ TerminalClosedMessage,
14
+ TerminalInputMessage,
15
+ TerminalOpenMessage,
16
+ TerminalOutputMessage,
17
+ TerminalResizeMessage,
18
+ TerminalStatusMessage,
19
+ )
20
+
21
+ __all__ = [
22
+ "AgentRegisterMessage",
23
+ "CapabilityDescriptor",
24
+ "ClientInfo",
25
+ "ClientStatusMessage",
26
+ "PublicRepositorySummary",
27
+ "PublicRootSummary",
28
+ "RepositoryDescriptor",
29
+ "RootDescriptor",
30
+ "RuntimeHealth",
31
+ "TaskMessage",
32
+ "TerminalCloseMessage",
33
+ "TerminalClosedMessage",
34
+ "TerminalInputMessage",
35
+ "TerminalOpenMessage",
36
+ "TerminalOutputMessage",
37
+ "TerminalResizeMessage",
38
+ "TerminalStatusMessage",
39
+ ]
shared/protocol.py ADDED
@@ -0,0 +1,253 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any, Literal
4
+
5
+ from pydantic import BaseModel, Field, model_validator
6
+
7
+
8
+ class ProtocolModel(BaseModel):
9
+ model_config = {"extra": "forbid", "populate_by_name": True}
10
+
11
+
12
+ class CapabilityDescriptor(ProtocolModel):
13
+ capability: str
14
+ actions: list[str] = Field(default_factory=list)
15
+
16
+
17
+ class RootDescriptor(ProtocolModel):
18
+ path: str
19
+ name: str
20
+ repo_id: str | None = Field(default=None, exclude=True)
21
+
22
+ @model_validator(mode="before")
23
+ @classmethod
24
+ def _accept_legacy_repo_id(cls, data: Any) -> Any:
25
+ if isinstance(data, dict):
26
+ payload = dict(data)
27
+ if "path" not in payload and "repo_id" in payload:
28
+ payload["path"] = payload["repo_id"]
29
+ if "repo_id" not in payload and "path" in payload:
30
+ payload["repo_id"] = payload["path"]
31
+ return payload
32
+ return data
33
+
34
+
35
+ class PublicRootSummary(ProtocolModel):
36
+ path: str
37
+ name: str
38
+ status: str
39
+ repo_id: str | None = Field(default=None, exclude=True)
40
+
41
+ @model_validator(mode="before")
42
+ @classmethod
43
+ def _accept_legacy_repo_id(cls, data: Any) -> Any:
44
+ if isinstance(data, dict):
45
+ payload = dict(data)
46
+ if "path" not in payload and "repo_id" in payload:
47
+ payload["path"] = payload["repo_id"]
48
+ if "repo_id" not in payload and "path" in payload:
49
+ payload["repo_id"] = payload["path"]
50
+ return payload
51
+ return data
52
+
53
+
54
+ class ClientInfo(ProtocolModel):
55
+ hostname: str
56
+ version: str
57
+ platform: str
58
+
59
+
60
+ class ConnectivityTarget(ProtocolModel):
61
+ connected: bool
62
+
63
+
64
+ class ConnectivityState(ProtocolModel):
65
+ controller: ConnectivityTarget
66
+
67
+
68
+ class RuntimeHealth(ProtocolModel):
69
+ active_tasks: int
70
+ queued_tasks: int
71
+ max_concurrent_tasks: int
72
+
73
+
74
+ class TaskMessage(ProtocolModel):
75
+ type: Literal["task"] = "task"
76
+ task_id: str
77
+ path: str
78
+ capability: str
79
+ action: str
80
+ params: dict[str, Any] = Field(default_factory=dict)
81
+
82
+ @model_validator(mode="before")
83
+ @classmethod
84
+ def _accept_legacy_repo_id(cls, data: Any) -> Any:
85
+ if isinstance(data, dict):
86
+ payload = dict(data)
87
+ if "path" not in payload and "repo_id" in payload:
88
+ payload["path"] = payload["repo_id"]
89
+ return payload
90
+ return data
91
+
92
+ @property
93
+ def repo_id(self) -> str:
94
+ return self.path
95
+
96
+
97
+ class AgentRegisterMessage(ProtocolModel):
98
+ type: Literal["register"] = "register"
99
+ protocol_version: int
100
+ client_id: str | None = None
101
+ client_info: ClientInfo
102
+ capabilities: list[CapabilityDescriptor] = Field(default_factory=list)
103
+ roots: list[RootDescriptor] = Field(default_factory=list)
104
+ connectivity: ConnectivityState
105
+ runtime_health: RuntimeHealth
106
+
107
+ @model_validator(mode="before")
108
+ @classmethod
109
+ def _accept_legacy_repositories(cls, data: Any) -> Any:
110
+ if isinstance(data, dict):
111
+ payload = dict(data)
112
+ repositories = payload.pop("repositories", None)
113
+ if "roots" not in payload and repositories is not None:
114
+ payload["roots"] = repositories
115
+ return payload
116
+ return data
117
+
118
+ @property
119
+ def repositories(self) -> list[RootDescriptor]:
120
+ return self.roots
121
+
122
+
123
+ class ClientStatusMessage(ProtocolModel):
124
+ type: Literal["client_status"] = "client_status"
125
+ protocol_version: int = 2
126
+ client_id: str | None = None
127
+ client_info: ClientInfo | None = None
128
+ reason: str
129
+ capabilities: list[CapabilityDescriptor] = Field(default_factory=list)
130
+ roots: list[RootDescriptor] = Field(default_factory=list)
131
+ connectivity: ConnectivityState
132
+ runtime_health: RuntimeHealth
133
+
134
+ @model_validator(mode="before")
135
+ @classmethod
136
+ def _accept_legacy_repositories(cls, data: Any) -> Any:
137
+ if isinstance(data, dict):
138
+ payload = dict(data)
139
+ repositories = payload.pop("repositories", None)
140
+ if "roots" not in payload and repositories is not None:
141
+ payload["roots"] = repositories
142
+ return payload
143
+ return data
144
+
145
+ @property
146
+ def repositories(self) -> list[RootDescriptor]:
147
+ return self.roots
148
+
149
+
150
+ class RegisterRequestMessage(ProtocolModel):
151
+ type: Literal["register_request"] = "register_request"
152
+ approved: bool
153
+ client_id: str
154
+ token: str | None = None
155
+ message: str | None = None
156
+
157
+
158
+ class TerminalOpenMessage(ProtocolModel):
159
+ type: Literal["terminal_open"] = "terminal_open"
160
+ terminal_id: str
161
+ path: str
162
+ cols: int = 120
163
+ rows: int = 32
164
+
165
+
166
+ class TerminalInputMessage(ProtocolModel):
167
+ type: Literal["terminal_input"] = "terminal_input"
168
+ terminal_id: str
169
+ data: str
170
+
171
+
172
+ class TerminalResizeMessage(ProtocolModel):
173
+ type: Literal["terminal_resize"] = "terminal_resize"
174
+ terminal_id: str
175
+ cols: int
176
+ rows: int
177
+
178
+
179
+ class TerminalCloseMessage(ProtocolModel):
180
+ type: Literal["terminal_close"] = "terminal_close"
181
+ terminal_id: str
182
+ reason: str | None = None
183
+
184
+
185
+ class TerminalPingMessage(ProtocolModel):
186
+ type: Literal["terminal_ping"] = "terminal_ping"
187
+ terminal_id: str
188
+
189
+
190
+ class TerminalPongMessage(ProtocolModel):
191
+ type: Literal["terminal_pong"] = "terminal_pong"
192
+ terminal_id: str
193
+
194
+
195
+ class TerminalStatusMessage(ProtocolModel):
196
+ type: Literal["terminal_status"] = "terminal_status"
197
+ terminal_id: str
198
+ status: str
199
+ message: str | None = None
200
+
201
+
202
+ class TerminalOutputMessage(ProtocolModel):
203
+ type: Literal["terminal_output"] = "terminal_output"
204
+ terminal_id: str
205
+ data: str
206
+
207
+
208
+ class TerminalHeartbeatMessage(ProtocolModel):
209
+ type: Literal["terminal_heartbeat"] = "terminal_heartbeat"
210
+ terminal_id: str
211
+ process_alive: bool
212
+
213
+
214
+ class TerminalClosedMessage(ProtocolModel):
215
+ type: Literal["terminal_closed"] = "terminal_closed"
216
+ terminal_id: str
217
+ reason: str | None = None
218
+ exit_code: int | None = None
219
+
220
+
221
+ class TaskEventMessage(ProtocolModel):
222
+ type: Literal["task_event"] = "task_event"
223
+ task_id: str
224
+ status: str
225
+ message: str | None = None
226
+ details: dict[str, Any] = Field(default_factory=dict)
227
+
228
+
229
+ class TaskResultMessage(ProtocolModel):
230
+ type: Literal["task_result"] = "task_result"
231
+ task_id: str
232
+ success: bool
233
+ result: dict[str, Any] = Field(default_factory=dict)
234
+ error: str | None = None
235
+
236
+
237
+ class TaskQueryMessage(ProtocolModel):
238
+ type: Literal["task_query"] = "task_query"
239
+ task_id: str
240
+
241
+
242
+ class TaskQueryResultMessage(ProtocolModel):
243
+ type: Literal["task_query_result"] = "task_query_result"
244
+ task_id: str
245
+ found: bool
246
+ success: bool | None = None
247
+ result: dict[str, Any] = Field(default_factory=dict)
248
+ error: str | None = None
249
+
250
+
251
+ # Temporary compatibility aliases while the rest of the branch is converted.
252
+ RepositoryDescriptor = RootDescriptor
253
+ PublicRepositorySummary = PublicRootSummary