bamboo-coding 0.1.1__tar.gz → 0.1.2__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.
- bamboo_coding-0.1.2/PKG-INFO +29 -0
- bamboo_coding-0.1.2/README.md +18 -0
- bamboo_coding-0.1.2/pyproject.toml +23 -0
- {bamboo_coding-0.1.1/bamboo_coding/client → bamboo_coding-0.1.2/src/bamboo_coding}/capabilities/repo.py +2 -2
- {bamboo_coding-0.1.1/bamboo_coding/client → bamboo_coding-0.1.2/src/bamboo_coding}/config.py +79 -12
- {bamboo_coding-0.1.1/bamboo_coding/client → bamboo_coding-0.1.2/src/bamboo_coding}/controller_client.py +1 -4
- {bamboo_coding-0.1.1/bamboo_coding/client → bamboo_coding-0.1.2/src/bamboo_coding}/main.py +364 -104
- {bamboo_coding-0.1.1/agent/bamboo_git_agent → bamboo_coding-0.1.2/src/bamboo_coding}/status.py +1 -1
- {bamboo_coding-0.1.1/bamboo_coding/client → bamboo_coding-0.1.2/src/bamboo_coding}/terminal_runtime.py +1 -1
- bamboo_coding-0.1.2/src/bamboo_coding.egg-info/PKG-INFO +29 -0
- bamboo_coding-0.1.2/src/bamboo_coding.egg-info/SOURCES.txt +20 -0
- bamboo_coding-0.1.2/src/bamboo_coding.egg-info/entry_points.txt +2 -0
- bamboo_coding-0.1.2/src/bamboo_coding.egg-info/requires.txt +4 -0
- bamboo_coding-0.1.2/src/bamboo_coding.egg-info/top_level.txt +1 -0
- bamboo_coding-0.1.1/PKG-INFO +0 -284
- bamboo_coding-0.1.1/README.md +0 -270
- bamboo_coding-0.1.1/agent/__init__.py +0 -0
- bamboo_coding-0.1.1/agent/bamboo_git_agent/__init__.py +0 -0
- bamboo_coding-0.1.1/agent/bamboo_git_agent/capabilities/__init__.py +0 -0
- bamboo_coding-0.1.1/agent/bamboo_git_agent/capabilities/repo.py +0 -189
- bamboo_coding-0.1.1/agent/bamboo_git_agent/config.py +0 -76
- bamboo_coding-0.1.1/agent/bamboo_git_agent/controller_client.py +0 -73
- bamboo_coding-0.1.1/agent/bamboo_git_agent/main.py +0 -164
- bamboo_coding-0.1.1/agent/bamboo_git_agent/protocol.py +0 -21
- bamboo_coding-0.1.1/api/__init__.py +0 -2
- bamboo_coding-0.1.1/api/commit.py +0 -82
- bamboo_coding-0.1.1/api/repository.py +0 -592
- bamboo_coding-0.1.1/bamboo_coding/__init__.py +0 -3
- bamboo_coding-0.1.1/bamboo_coding/client/journal.py +0 -1
- bamboo_coding-0.1.1/bamboo_coding/client/status.py +0 -59
- bamboo_coding-0.1.1/bamboo_coding/server/__init__.py +0 -3
- bamboo_coding-0.1.1/bamboo_coding/server/core/__init__.py +0 -1
- bamboo_coding-0.1.1/bamboo_coding/server/core/config.py +0 -1
- bamboo_coding-0.1.1/bamboo_coding/server/main.py +0 -39
- bamboo_coding-0.1.1/bamboo_coding/shared/__init__.py +0 -39
- bamboo_coding-0.1.1/bamboo_coding/shared/protocol.py +0 -1
- bamboo_coding-0.1.1/bamboo_coding.egg-info/PKG-INFO +0 -284
- bamboo_coding-0.1.1/bamboo_coding.egg-info/SOURCES.txt +0 -71
- bamboo_coding-0.1.1/bamboo_coding.egg-info/entry_points.txt +0 -3
- bamboo_coding-0.1.1/bamboo_coding.egg-info/requires.txt +0 -7
- bamboo_coding-0.1.1/bamboo_coding.egg-info/top_level.txt +0 -6
- bamboo_coding-0.1.1/controller/__init__.py +0 -0
- bamboo_coding-0.1.1/controller/app/__init__.py +0 -0
- bamboo_coding-0.1.1/controller/app/api/__init__.py +0 -0
- bamboo_coding-0.1.1/controller/app/api/agents/__init__.py +0 -3
- bamboo_coding-0.1.1/controller/app/api/agents/ws.py +0 -139
- bamboo_coding-0.1.1/controller/app/api/public/__init__.py +0 -13
- bamboo_coding-0.1.1/controller/app/api/public/repos.py +0 -228
- bamboo_coding-0.1.1/controller/app/api/public/terminals.py +0 -82
- bamboo_coding-0.1.1/controller/app/core/__init__.py +0 -0
- bamboo_coding-0.1.1/controller/app/core/config.py +0 -20
- bamboo_coding-0.1.1/controller/app/core/errors.py +0 -14
- bamboo_coding-0.1.1/controller/app/db/__init__.py +0 -0
- bamboo_coding-0.1.1/controller/app/db/models.py +0 -42
- bamboo_coding-0.1.1/controller/app/db/session.py +0 -74
- bamboo_coding-0.1.1/controller/app/main.py +0 -80
- bamboo_coding-0.1.1/controller/app/schemas/__init__.py +0 -23
- bamboo_coding-0.1.1/controller/app/schemas/agent_messages.py +0 -21
- bamboo_coding-0.1.1/controller/app/schemas/public.py +0 -3
- bamboo_coding-0.1.1/controller/app/services/__init__.py +0 -0
- bamboo_coding-0.1.1/controller/app/services/agents.py +0 -108
- bamboo_coding-0.1.1/controller/app/services/registrations.py +0 -17
- bamboo_coding-0.1.1/controller/app/services/repositories.py +0 -85
- bamboo_coding-0.1.1/controller/app/services/router.py +0 -140
- bamboo_coding-0.1.1/controller/app/services/tasks.py +0 -104
- bamboo_coding-0.1.1/controller/app/services/terminals.py +0 -331
- bamboo_coding-0.1.1/pyproject.toml +0 -29
- bamboo_coding-0.1.1/shared/__init__.py +0 -39
- bamboo_coding-0.1.1/tests/test_api.py +0 -140
- bamboo_coding-0.1.1/tests/test_container_contract.py +0 -7
- bamboo_coding-0.1.1/tests/test_frontend_contract.py +0 -3275
- bamboo_coding-0.1.1/tests/test_git_utils.py +0 -286
- bamboo_coding-0.1.1/tests/test_makefile.py +0 -62
- {bamboo_coding-0.1.1 → bamboo_coding-0.1.2}/setup.cfg +0 -0
- {bamboo_coding-0.1.1/bamboo_coding/client → bamboo_coding-0.1.2/src/bamboo_coding}/__init__.py +0 -0
- {bamboo_coding-0.1.1/bamboo_coding/client → bamboo_coding-0.1.2/src/bamboo_coding}/capabilities/__init__.py +0 -0
- {bamboo_coding-0.1.1 → bamboo_coding-0.1.2/src/bamboo_coding}/git_utils.py +0 -0
- {bamboo_coding-0.1.1/agent/bamboo_git_agent → bamboo_coding-0.1.2/src/bamboo_coding}/journal.py +0 -0
- {bamboo_coding-0.1.1/shared → bamboo_coding-0.1.2/src/bamboo_coding}/protocol.py +0 -0
- {bamboo_coding-0.1.1/bamboo_coding/client → bamboo_coding-0.1.2/src/bamboo_coding}/scrollback_buffer.py +0 -0
- {bamboo_coding-0.1.1 → bamboo_coding-0.1.2/src}/bamboo_coding.egg-info/dependency_links.txt +0 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: bamboo-coding
|
|
3
|
+
Version: 0.1.2
|
|
4
|
+
Summary: Bamboo Coding outbound client
|
|
5
|
+
Requires-Python: >=3.12
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
Requires-Dist: gitpython==3.1.40
|
|
8
|
+
Requires-Dist: websockets==13.1
|
|
9
|
+
Requires-Dist: pydantic>=2.0
|
|
10
|
+
Requires-Dist: bamboo-ssh
|
|
11
|
+
|
|
12
|
+
# bamboo-coding
|
|
13
|
+
|
|
14
|
+
Outbound client for the Bamboo Coding controller.
|
|
15
|
+
|
|
16
|
+
## Install
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
pip install bamboo-coding
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
bamboo-coding setup # configure default profile
|
|
26
|
+
bamboo-coding run # connect to the controller
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The client reads its configuration from `~/.bamboo-coding/bamboo-coding.toml`.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# bamboo-coding
|
|
2
|
+
|
|
3
|
+
Outbound client for the Bamboo Coding controller.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install bamboo-coding
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
bamboo-coding setup # configure default profile
|
|
15
|
+
bamboo-coding run # connect to the controller
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
The client reads its configuration from `~/.bamboo-coding/bamboo-coding.toml`.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=69", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "bamboo-coding"
|
|
7
|
+
version = "0.1.2"
|
|
8
|
+
description = "Bamboo Coding outbound client"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.12"
|
|
11
|
+
dependencies = [
|
|
12
|
+
"gitpython==3.1.40",
|
|
13
|
+
"websockets==13.1",
|
|
14
|
+
"pydantic>=2.0",
|
|
15
|
+
"bamboo-ssh",
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
[project.scripts]
|
|
19
|
+
bamboo-coding = "bamboo_coding.main:main"
|
|
20
|
+
|
|
21
|
+
[tool.setuptools.packages.find]
|
|
22
|
+
where = ["src"]
|
|
23
|
+
include = ["bamboo_coding*"]
|
|
@@ -3,8 +3,8 @@ from __future__ import annotations
|
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
from typing import Callable
|
|
5
5
|
|
|
6
|
-
import git_utils
|
|
7
|
-
from
|
|
6
|
+
from .. import git_utils
|
|
7
|
+
from ..protocol import TaskMessage
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
def _allowed_roots(repositories: dict[str, str] | list[str] | tuple[str, ...]) -> list[str]:
|
{bamboo_coding-0.1.1/bamboo_coding/client → bamboo_coding-0.1.2/src/bamboo_coding}/config.py
RENAMED
|
@@ -13,6 +13,8 @@ DEFAULT_CONFIG_DIRNAME = ".bamboo-coding"
|
|
|
13
13
|
DEFAULT_CONFIG_FILENAME = "bamboo-coding.toml"
|
|
14
14
|
DEFAULT_CONTROLLER_URL = "ws://127.0.0.1:8100/ws/agents"
|
|
15
15
|
DEFAULT_CLIENT_ID = "bamboo-coding-client"
|
|
16
|
+
DEFAULT_PROFILE = "default"
|
|
17
|
+
SERVERS_DIRNAME = "servers"
|
|
16
18
|
|
|
17
19
|
|
|
18
20
|
@dataclass(frozen=True)
|
|
@@ -32,6 +34,10 @@ class AgentConfig:
|
|
|
32
34
|
token_path: Path
|
|
33
35
|
journal_path: Path
|
|
34
36
|
config_path: Path = field(default_factory=Path)
|
|
37
|
+
profile: str = DEFAULT_PROFILE
|
|
38
|
+
profile_exists: bool = True
|
|
39
|
+
legacy_client_section: bool = False
|
|
40
|
+
available_profiles: tuple[str, ...] = field(default_factory=tuple)
|
|
35
41
|
max_concurrent_tasks: int = 1
|
|
36
42
|
allowed_roots: tuple[str, ...] = field(default_factory=tuple)
|
|
37
43
|
repositories: tuple[RepositoryConfig, ...] = field(default_factory=tuple)
|
|
@@ -107,7 +113,39 @@ def _load_legacy_token(default_token_path: Path) -> str:
|
|
|
107
113
|
return token
|
|
108
114
|
|
|
109
115
|
|
|
110
|
-
def
|
|
116
|
+
def _resolve_profile_section(raw_config: dict, profile: str) -> tuple[dict | None, bool]:
|
|
117
|
+
"""Return (profile_dict, is_legacy_client_section).
|
|
118
|
+
|
|
119
|
+
profile_dict is None if no matching profile was found.
|
|
120
|
+
"""
|
|
121
|
+
servers = raw_config.get("servers")
|
|
122
|
+
if isinstance(servers, dict):
|
|
123
|
+
candidate = servers.get(profile)
|
|
124
|
+
if isinstance(candidate, dict):
|
|
125
|
+
return candidate, False
|
|
126
|
+
if profile == DEFAULT_PROFILE:
|
|
127
|
+
legacy = raw_config.get("client")
|
|
128
|
+
if isinstance(legacy, dict):
|
|
129
|
+
return legacy, True
|
|
130
|
+
return None, False
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def _list_available_profiles(raw_config: dict) -> tuple[str, ...]:
|
|
134
|
+
names: list[str] = []
|
|
135
|
+
servers = raw_config.get("servers")
|
|
136
|
+
if isinstance(servers, dict):
|
|
137
|
+
names.extend(name for name in servers if isinstance(servers.get(name), dict))
|
|
138
|
+
if DEFAULT_PROFILE not in names and isinstance(raw_config.get("client"), dict):
|
|
139
|
+
names.insert(0, DEFAULT_PROFILE)
|
|
140
|
+
return tuple(names)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def _profile_storage_dir(storage_home: Path, profile: str) -> Path:
|
|
144
|
+
return storage_home / SERVERS_DIRNAME / profile
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def load_config(profile: str | None = None) -> AgentConfig:
|
|
148
|
+
active_profile = profile or DEFAULT_PROFILE
|
|
111
149
|
config_home = Path(_first_env("BAMBOO_CODING_HOME") or (Path.home() / DEFAULT_CONFIG_DIRNAME)).expanduser().resolve()
|
|
112
150
|
config_path = _resolve_path(
|
|
113
151
|
_first_env("BAMBOO_CODING_CONFIG_PATH"),
|
|
@@ -115,45 +153,70 @@ def load_config() -> AgentConfig:
|
|
|
115
153
|
base_dir=config_home,
|
|
116
154
|
)
|
|
117
155
|
raw_config = _load_toml(config_path)
|
|
118
|
-
|
|
119
|
-
|
|
156
|
+
profile_section, is_legacy_client = _resolve_profile_section(raw_config, active_profile)
|
|
157
|
+
available_profiles = _list_available_profiles(raw_config)
|
|
158
|
+
profile_exists = profile_section is not None
|
|
159
|
+
section = profile_section if isinstance(profile_section, dict) else {}
|
|
160
|
+
|
|
161
|
+
explicit_new_layout = profile_exists and not is_legacy_client
|
|
162
|
+
storage_config = (
|
|
163
|
+
raw_config.get("storage")
|
|
164
|
+
if not explicit_new_layout and isinstance(raw_config.get("storage"), dict)
|
|
165
|
+
else {}
|
|
166
|
+
)
|
|
120
167
|
|
|
121
168
|
storage_home_value = _first_env("BAMBOO_CODING_HOME", "AGENT_HOME")
|
|
122
169
|
storage_home = Path(storage_home_value).expanduser().resolve() if storage_home_value else config_home
|
|
123
170
|
|
|
171
|
+
if explicit_new_layout:
|
|
172
|
+
profile_dir = _profile_storage_dir(storage_home, active_profile)
|
|
173
|
+
default_token_path = profile_dir / "token.json"
|
|
174
|
+
default_journal_path = profile_dir / "journal.db"
|
|
175
|
+
elif active_profile == DEFAULT_PROFILE:
|
|
176
|
+
default_token_path = storage_home / "token.json"
|
|
177
|
+
default_journal_path = storage_home / "journal.db"
|
|
178
|
+
else:
|
|
179
|
+
profile_dir = _profile_storage_dir(storage_home, active_profile)
|
|
180
|
+
default_token_path = profile_dir / "token.json"
|
|
181
|
+
default_journal_path = profile_dir / "journal.db"
|
|
182
|
+
|
|
124
183
|
controller_url = _first_env("BAMBOO_CODING_CONTROLLER_URL", "CONTROLLER_URL") or str(
|
|
125
|
-
|
|
184
|
+
section.get("controller_url") or DEFAULT_CONTROLLER_URL
|
|
126
185
|
)
|
|
127
186
|
client_id = _first_env("BAMBOO_CODING_CLIENT_ID", "AGENT_CLIENT_ID") or str(
|
|
128
|
-
|
|
187
|
+
section.get("client_id") or platform.node() or DEFAULT_CLIENT_ID
|
|
129
188
|
)
|
|
130
189
|
hostname = _first_env("BAMBOO_CODING_HOSTNAME", "AGENT_HOSTNAME") or str(
|
|
131
|
-
|
|
190
|
+
section.get("hostname") or platform.node() or client_id
|
|
132
191
|
)
|
|
133
|
-
version = _first_env("BAMBOO_CODING_VERSION", "AGENT_VERSION") or str(
|
|
192
|
+
version = _first_env("BAMBOO_CODING_VERSION", "AGENT_VERSION") or str(section.get("version") or _default_version())
|
|
134
193
|
allowed_roots = _coerce_allowed_roots(
|
|
135
194
|
_first_env("BAMBOO_CODING_ALLOWED_ROOTS", "AGENT_ALLOWED_ROOTS", "AGENT_ROOT", "AGENT_REPO_PATH")
|
|
136
|
-
or
|
|
195
|
+
or section.get("allowed_roots")
|
|
137
196
|
)
|
|
138
197
|
max_concurrent_tasks = int(
|
|
139
198
|
_first_env("BAMBOO_CODING_MAX_CONCURRENT_TASKS", "AGENT_MAX_CONCURRENT_TASKS")
|
|
140
|
-
or
|
|
199
|
+
or section.get("max_concurrent_tasks")
|
|
141
200
|
or 1
|
|
142
201
|
)
|
|
143
202
|
|
|
144
203
|
token_path = _resolve_path(
|
|
145
204
|
_first_env("BAMBOO_CODING_TOKEN_PATH", "AGENT_TOKEN_PATH") or storage_config.get("token_path"),
|
|
146
|
-
default=
|
|
205
|
+
default=default_token_path,
|
|
147
206
|
base_dir=config_path.parent,
|
|
148
207
|
)
|
|
149
208
|
journal_path = _resolve_path(
|
|
150
209
|
_first_env("BAMBOO_CODING_JOURNAL_PATH", "AGENT_JOURNAL_PATH") or storage_config.get("journal_path"),
|
|
151
|
-
default=
|
|
210
|
+
default=default_journal_path,
|
|
152
211
|
base_dir=config_path.parent,
|
|
153
212
|
)
|
|
154
213
|
|
|
155
214
|
token = _first_env("BAMBOO_CODING_TOKEN", "AGENT_TOKEN") or _load_stored_token(token_path)
|
|
156
|
-
if
|
|
215
|
+
if (
|
|
216
|
+
not token
|
|
217
|
+
and active_profile == DEFAULT_PROFILE
|
|
218
|
+
and not _first_env("BAMBOO_CODING_TOKEN_PATH", "AGENT_TOKEN_PATH", "AGENT_HOME")
|
|
219
|
+
):
|
|
157
220
|
token = _load_legacy_token(token_path)
|
|
158
221
|
|
|
159
222
|
repositories = tuple(
|
|
@@ -173,6 +236,10 @@ def load_config() -> AgentConfig:
|
|
|
173
236
|
token_path=token_path,
|
|
174
237
|
journal_path=journal_path,
|
|
175
238
|
config_path=config_path,
|
|
239
|
+
profile=active_profile,
|
|
240
|
+
profile_exists=profile_exists,
|
|
241
|
+
legacy_client_section=is_legacy_client,
|
|
242
|
+
available_profiles=available_profiles,
|
|
176
243
|
max_concurrent_tasks=max_concurrent_tasks,
|
|
177
244
|
allowed_roots=allowed_roots,
|
|
178
245
|
repositories=repositories,
|
|
@@ -11,7 +11,7 @@ from websockets.exceptions import ConnectionClosed
|
|
|
11
11
|
|
|
12
12
|
LOGGER = logging.getLogger(__name__)
|
|
13
13
|
|
|
14
|
-
from
|
|
14
|
+
from .protocol import (
|
|
15
15
|
AgentRegisterMessage,
|
|
16
16
|
ClientStatusMessage,
|
|
17
17
|
TaskEventMessage,
|
|
@@ -131,9 +131,6 @@ class ControllerConnection:
|
|
|
131
131
|
try:
|
|
132
132
|
await self.websocket.send(json.dumps(payload))
|
|
133
133
|
except ConnectionClosed:
|
|
134
|
-
# Controller is gone; the run loop will reconnect. Drop the
|
|
135
|
-
# outbound frame so cleanup paths (heartbeats, terminal_closed)
|
|
136
|
-
# don't crash the runtime during server restarts.
|
|
137
134
|
LOGGER.debug('skipping outbound message; controller connection is closed')
|
|
138
135
|
|
|
139
136
|
async def _receive(self) -> dict:
|