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.
- agent/__init__.py +0 -0
- agent/bamboo_git_agent/__init__.py +0 -0
- agent/bamboo_git_agent/capabilities/__init__.py +0 -0
- agent/bamboo_git_agent/capabilities/repo.py +189 -0
- agent/bamboo_git_agent/config.py +76 -0
- agent/bamboo_git_agent/controller_client.py +73 -0
- agent/bamboo_git_agent/journal.py +209 -0
- agent/bamboo_git_agent/main.py +164 -0
- agent/bamboo_git_agent/protocol.py +21 -0
- agent/bamboo_git_agent/status.py +59 -0
- api/__init__.py +2 -0
- api/commit.py +82 -0
- api/repository.py +592 -0
- bamboo_coding/__init__.py +3 -0
- bamboo_coding/client/__init__.py +3 -0
- bamboo_coding/client/capabilities/__init__.py +1 -0
- bamboo_coding/client/capabilities/repo.py +279 -0
- bamboo_coding/client/config.py +179 -0
- bamboo_coding/client/controller_client.py +112 -0
- bamboo_coding/client/journal.py +1 -0
- bamboo_coding/client/main.py +425 -0
- bamboo_coding/client/status.py +59 -0
- bamboo_coding/client/terminal_runtime.py +251 -0
- bamboo_coding/server/__init__.py +3 -0
- bamboo_coding/server/core/__init__.py +1 -0
- bamboo_coding/server/core/config.py +1 -0
- bamboo_coding/server/main.py +39 -0
- bamboo_coding/shared/__init__.py +39 -0
- bamboo_coding/shared/protocol.py +1 -0
- bamboo_coding-0.1.0.dist-info/METADATA +284 -0
- bamboo_coding-0.1.0.dist-info/RECORD +62 -0
- bamboo_coding-0.1.0.dist-info/WHEEL +5 -0
- bamboo_coding-0.1.0.dist-info/entry_points.txt +3 -0
- bamboo_coding-0.1.0.dist-info/top_level.txt +6 -0
- controller/__init__.py +0 -0
- controller/app/__init__.py +0 -0
- controller/app/api/__init__.py +0 -0
- controller/app/api/agents/__init__.py +3 -0
- controller/app/api/agents/ws.py +133 -0
- controller/app/api/public/__init__.py +11 -0
- controller/app/api/public/repos.py +207 -0
- controller/app/api/public/terminals.py +64 -0
- controller/app/core/__init__.py +0 -0
- controller/app/core/config.py +20 -0
- controller/app/core/errors.py +14 -0
- controller/app/db/__init__.py +0 -0
- controller/app/db/models.py +42 -0
- controller/app/db/session.py +74 -0
- controller/app/main.py +71 -0
- controller/app/schemas/__init__.py +23 -0
- controller/app/schemas/agent_messages.py +21 -0
- controller/app/schemas/public.py +3 -0
- controller/app/services/__init__.py +0 -0
- controller/app/services/agents.py +108 -0
- controller/app/services/registrations.py +17 -0
- controller/app/services/repositories.py +85 -0
- controller/app/services/router.py +140 -0
- controller/app/services/tasks.py +104 -0
- controller/app/services/terminals.py +148 -0
- git_utils.py +2238 -0
- shared/__init__.py +39 -0
- 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
|