cyclo-manager 0.2.0.dev12__tar.gz → 0.2.1.dev0__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 (20) hide show
  1. {cyclo_manager-0.2.0.dev12 → cyclo_manager-0.2.1.dev0}/PKG-INFO +5 -11
  2. {cyclo_manager-0.2.0.dev12 → cyclo_manager-0.2.1.dev0}/README.md +4 -10
  3. {cyclo_manager-0.2.0.dev12 → cyclo_manager-0.2.1.dev0}/cyclo_host_agent/main.py +3 -4
  4. {cyclo_manager-0.2.0.dev12 → cyclo_manager-0.2.1.dev0}/cyclo_host_agent/models.py +8 -0
  5. {cyclo_manager-0.2.0.dev12 → cyclo_manager-0.2.1.dev0}/cyclo_host_agent/routers/repos.py +23 -7
  6. {cyclo_manager-0.2.0.dev12 → cyclo_manager-0.2.1.dev0}/cyclo_host_agent/routers/update.py +4 -2
  7. {cyclo_manager-0.2.0.dev12 → cyclo_manager-0.2.1.dev0}/cyclo_manager.egg-info/PKG-INFO +5 -11
  8. {cyclo_manager-0.2.0.dev12 → cyclo_manager-0.2.1.dev0}/cyclo_manager_cli/__init__.py +1 -1
  9. {cyclo_manager-0.2.0.dev12 → cyclo_manager-0.2.1.dev0}/cyclo_manager_cli/cli.py +12 -5
  10. {cyclo_manager-0.2.0.dev12 → cyclo_manager-0.2.1.dev0}/cyclo_manager_cli/config/config.yml +1 -1
  11. {cyclo_manager-0.2.0.dev12 → cyclo_manager-0.2.1.dev0}/cyclo_manager_cli/docker/docker-compose.yml +2 -2
  12. {cyclo_manager-0.2.0.dev12 → cyclo_manager-0.2.1.dev0}/pyproject.toml +1 -1
  13. {cyclo_manager-0.2.0.dev12 → cyclo_manager-0.2.1.dev0}/setup.cfg +1 -1
  14. {cyclo_manager-0.2.0.dev12 → cyclo_manager-0.2.1.dev0}/cyclo_host_agent/__init__.py +0 -0
  15. {cyclo_manager-0.2.0.dev12 → cyclo_manager-0.2.1.dev0}/cyclo_host_agent/routers/__init__.py +0 -0
  16. {cyclo_manager-0.2.0.dev12 → cyclo_manager-0.2.1.dev0}/cyclo_manager.egg-info/SOURCES.txt +0 -0
  17. {cyclo_manager-0.2.0.dev12 → cyclo_manager-0.2.1.dev0}/cyclo_manager.egg-info/dependency_links.txt +0 -0
  18. {cyclo_manager-0.2.0.dev12 → cyclo_manager-0.2.1.dev0}/cyclo_manager.egg-info/entry_points.txt +0 -0
  19. {cyclo_manager-0.2.0.dev12 → cyclo_manager-0.2.1.dev0}/cyclo_manager.egg-info/requires.txt +0 -0
  20. {cyclo_manager-0.2.0.dev12 → cyclo_manager-0.2.1.dev0}/cyclo_manager.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cyclo-manager
3
- Version: 0.2.0.dev12
3
+ Version: 0.2.1.dev0
4
4
  Summary: cyclo_manager CLI: pip-installable launcher for cyclo_manager server and UI containers. Run 'cyclo_manager up' to start Docker stack.
5
5
  License-Expression: Apache-2.0
6
6
  Requires-Python: >=3.10
@@ -67,12 +67,6 @@ From **PyPI**:
67
67
  pip install cyclo-manager
68
68
  ```
69
69
 
70
- Pre-release versions:
71
-
72
- ```bash
73
- pip install --pre cyclo-manager==0.2.0.dev0
74
- ```
75
-
76
70
  If `cyclo_manager` is not on `PATH`, add the user script directory:
77
71
 
78
72
  ```bash
@@ -144,8 +138,8 @@ Defined in [`cyclo_manager_cli/docker/docker-compose.yml`](cyclo_manager_cli/doc
144
138
 
145
139
  | Compose service | Container name | `cyclo_manager up` | Image (example) |
146
140
  |-----------------|----------------|--------------------|-----------------|
147
- | `cyclo_manager` | `cyclo_manager` | **Started** | `robotis/cyclo-manager:0.2.0` |
148
- | `ui` | `cyclo_manager_ui` | **Started** | `robotis/cyclo-manager-ui:0.2.0` |
141
+ | `cyclo_manager` | `cyclo_manager` | **Started** | `robotis/cyclo-manager:0.2.1` |
142
+ | `ui` | `cyclo_manager_ui` | **Started** | `robotis/cyclo-manager-ui:0.2.1` |
149
143
  | `rmw_zenoh` | `zenoh_daemon` | **Created only** | `robotis/zenoh-daemon:latest` |
150
144
  | `novnc-server` | `novnc-server` | **Created only** | `robotis/novnc-server:latest` |
151
145
 
@@ -177,7 +171,7 @@ robot_container: ai_worker
177
171
 
178
172
  sockets:
179
173
  ai_worker: "/agents/ai_worker/s6_agent.sock"
180
- physical_ai_server: "/agents/physical_ai_server/s6_agent.sock"
174
+ cyclo_intelligence: "/agents/cyclo_intelligence/s6_agent.sock"
181
175
  host_agent: "/agents/host/host_agent.sock"
182
176
  ```
183
177
 
@@ -198,7 +192,7 @@ On the host, sockets typically live under:
198
192
  ```text
199
193
  /var/run/robotis/agent_sockets/
200
194
  ├── ai_worker/s6_agent.sock
201
- ├── physical_ai_server/s6_agent.sock
195
+ ├── cyclo_intelligence/s6_agent.sock
202
196
  └── host/host_agent.sock ← created by cyclo_manager up
203
197
  ```
204
198
 
@@ -53,12 +53,6 @@ From **PyPI**:
53
53
  pip install cyclo-manager
54
54
  ```
55
55
 
56
- Pre-release versions:
57
-
58
- ```bash
59
- pip install --pre cyclo-manager==0.2.0.dev0
60
- ```
61
-
62
56
  If `cyclo_manager` is not on `PATH`, add the user script directory:
63
57
 
64
58
  ```bash
@@ -130,8 +124,8 @@ Defined in [`cyclo_manager_cli/docker/docker-compose.yml`](cyclo_manager_cli/doc
130
124
 
131
125
  | Compose service | Container name | `cyclo_manager up` | Image (example) |
132
126
  |-----------------|----------------|--------------------|-----------------|
133
- | `cyclo_manager` | `cyclo_manager` | **Started** | `robotis/cyclo-manager:0.2.0` |
134
- | `ui` | `cyclo_manager_ui` | **Started** | `robotis/cyclo-manager-ui:0.2.0` |
127
+ | `cyclo_manager` | `cyclo_manager` | **Started** | `robotis/cyclo-manager:0.2.1` |
128
+ | `ui` | `cyclo_manager_ui` | **Started** | `robotis/cyclo-manager-ui:0.2.1` |
135
129
  | `rmw_zenoh` | `zenoh_daemon` | **Created only** | `robotis/zenoh-daemon:latest` |
136
130
  | `novnc-server` | `novnc-server` | **Created only** | `robotis/novnc-server:latest` |
137
131
 
@@ -163,7 +157,7 @@ robot_container: ai_worker
163
157
 
164
158
  sockets:
165
159
  ai_worker: "/agents/ai_worker/s6_agent.sock"
166
- physical_ai_server: "/agents/physical_ai_server/s6_agent.sock"
160
+ cyclo_intelligence: "/agents/cyclo_intelligence/s6_agent.sock"
167
161
  host_agent: "/agents/host/host_agent.sock"
168
162
  ```
169
163
 
@@ -184,7 +178,7 @@ On the host, sockets typically live under:
184
178
  ```text
185
179
  /var/run/robotis/agent_sockets/
186
180
  ├── ai_worker/s6_agent.sock
187
- ├── physical_ai_server/s6_agent.sock
181
+ ├── cyclo_intelligence/s6_agent.sock
188
182
  └── host/host_agent.sock ← created by cyclo_manager up
189
183
  ```
190
184
 
@@ -21,10 +21,9 @@
21
21
  import logging
22
22
  from pathlib import Path
23
23
 
24
- import uvicorn
25
- from fastapi import FastAPI
26
-
27
24
  from cyclo_host_agent.routers import repos, update
25
+ from fastapi import FastAPI
26
+ import uvicorn
28
27
 
29
28
  logging.basicConfig(
30
29
  level=logging.INFO,
@@ -37,7 +36,7 @@ SOCKET_PATH = '/var/run/robotis/agent_sockets/host/host_agent.sock'
37
36
  app = FastAPI(
38
37
  title='cyclo_host_agent',
39
38
  description='Host agent for Cyclo Manager: repo management.',
40
- version='0.2.0',
39
+ version='0.2.1',
41
40
  )
42
41
 
43
42
  app.include_router(repos.router)
@@ -71,6 +71,14 @@ class RepoStatusResponse(BaseModel):
71
71
  has_changes: bool
72
72
 
73
73
 
74
+ class RepoBranchCheckResponse(BaseModel):
75
+ """Response for GET /repos/{name}/branch."""
76
+
77
+ name: str
78
+ branch: Optional[str] = None
79
+ allowed: bool
80
+
81
+
74
82
  class UpdateRequest(BaseModel):
75
83
  """Request body for POST /repos/{name}/update."""
76
84
 
@@ -20,23 +20,23 @@
20
20
 
21
21
  import asyncio
22
22
  import os
23
- import re
24
23
  from pathlib import Path
24
+ import re
25
25
  from typing import Optional
26
26
 
27
- from fastapi import APIRouter, HTTPException, status
28
-
29
27
  from cyclo_host_agent.models import (
30
28
  ContainerScriptResponse,
31
29
  FileChange,
30
+ RepoBranchCheckResponse,
32
31
  RepoInfo,
33
32
  RepoListResponse,
34
33
  RepoStatusResponse,
35
- RepoUpdateStatus,
36
34
  RepoUpdatesResponse,
35
+ RepoUpdateStatus,
37
36
  UpdateRequest,
38
37
  UpdateResponse,
39
38
  )
39
+ from fastapi import APIRouter, HTTPException, status
40
40
 
41
41
  router = APIRouter(prefix='/repos', tags=['repos'])
42
42
 
@@ -109,12 +109,12 @@ async def _ensure_allowed_branch(repo_path: Path) -> None:
109
109
  allowed = ', '.join(sorted(ALLOWED_UPDATE_BRANCHES))
110
110
  if branch:
111
111
  detail = (
112
- f"Updates are only allowed on branches: {allowed}. "
112
+ f'Updates are only allowed on branches: {allowed}. '
113
113
  f"Current branch is '{branch}'."
114
114
  )
115
115
  else:
116
116
  detail = (
117
- f"Updates are only allowed on branches: {allowed}. "
117
+ f'Updates are only allowed on branches: {allowed}. '
118
118
  'Could not determine the current branch (detached HEAD?).'
119
119
  )
120
120
  raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=detail)
@@ -221,7 +221,12 @@ async def _repo_update_status(repo_path: Path) -> Optional[RepoUpdateStatus]:
221
221
 
222
222
  latest = await _fetch_latest_tag(remote_url)
223
223
  if not latest:
224
- return RepoUpdateStatus(name=repo_path.name, branch=branch, current_version=current, has_update=False)
224
+ return RepoUpdateStatus(
225
+ name=repo_path.name,
226
+ branch=branch,
227
+ current_version=current,
228
+ has_update=False,
229
+ )
225
230
 
226
231
  return RepoUpdateStatus(
227
232
  name=repo_path.name,
@@ -356,6 +361,17 @@ async def list_repos() -> RepoListResponse:
356
361
  return RepoListResponse(repos=repos, workspace_path=str(WORKSPACE_PATH))
357
362
 
358
363
 
364
+ @router.get('/{name}/branch', response_model=RepoBranchCheckResponse)
365
+ async def get_repo_branch(name: str) -> RepoBranchCheckResponse:
366
+ repo_path = _get_repo(name)
367
+ branch = await _current_branch(repo_path)
368
+ return RepoBranchCheckResponse(
369
+ name=name,
370
+ branch=branch,
371
+ allowed=branch in ALLOWED_UPDATE_BRANCHES,
372
+ )
373
+
374
+
359
375
  @router.get('/{name}/status', response_model=RepoStatusResponse)
360
376
  async def get_repo_status(name: str) -> RepoStatusResponse:
361
377
  repo_path = _get_repo(name)
@@ -62,6 +62,10 @@ async def start_update() -> dict:
62
62
  raise HTTPException(status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
63
63
  detail='cyclo_manager command not found')
64
64
 
65
+ if _update_status.get('phase') == 'updating':
66
+ raise HTTPException(status_code=status.HTTP_409_CONFLICT,
67
+ detail='Update already in progress')
68
+
65
69
  _update_status = {'phase': 'updating', 'output': '', 'error': ''}
66
70
  asyncio.create_task(_run_update(cyclo_exe))
67
71
  return {'status': 'update started'}
@@ -71,5 +75,3 @@ async def start_update() -> dict:
71
75
  async def get_update_status() -> dict:
72
76
  """Return the current update phase and stored outputs."""
73
77
  return _update_status
74
-
75
-
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cyclo-manager
3
- Version: 0.2.0.dev12
3
+ Version: 0.2.1.dev0
4
4
  Summary: cyclo_manager CLI: pip-installable launcher for cyclo_manager server and UI containers. Run 'cyclo_manager up' to start Docker stack.
5
5
  License-Expression: Apache-2.0
6
6
  Requires-Python: >=3.10
@@ -67,12 +67,6 @@ From **PyPI**:
67
67
  pip install cyclo-manager
68
68
  ```
69
69
 
70
- Pre-release versions:
71
-
72
- ```bash
73
- pip install --pre cyclo-manager==0.2.0.dev0
74
- ```
75
-
76
70
  If `cyclo_manager` is not on `PATH`, add the user script directory:
77
71
 
78
72
  ```bash
@@ -144,8 +138,8 @@ Defined in [`cyclo_manager_cli/docker/docker-compose.yml`](cyclo_manager_cli/doc
144
138
 
145
139
  | Compose service | Container name | `cyclo_manager up` | Image (example) |
146
140
  |-----------------|----------------|--------------------|-----------------|
147
- | `cyclo_manager` | `cyclo_manager` | **Started** | `robotis/cyclo-manager:0.2.0` |
148
- | `ui` | `cyclo_manager_ui` | **Started** | `robotis/cyclo-manager-ui:0.2.0` |
141
+ | `cyclo_manager` | `cyclo_manager` | **Started** | `robotis/cyclo-manager:0.2.1` |
142
+ | `ui` | `cyclo_manager_ui` | **Started** | `robotis/cyclo-manager-ui:0.2.1` |
149
143
  | `rmw_zenoh` | `zenoh_daemon` | **Created only** | `robotis/zenoh-daemon:latest` |
150
144
  | `novnc-server` | `novnc-server` | **Created only** | `robotis/novnc-server:latest` |
151
145
 
@@ -177,7 +171,7 @@ robot_container: ai_worker
177
171
 
178
172
  sockets:
179
173
  ai_worker: "/agents/ai_worker/s6_agent.sock"
180
- physical_ai_server: "/agents/physical_ai_server/s6_agent.sock"
174
+ cyclo_intelligence: "/agents/cyclo_intelligence/s6_agent.sock"
181
175
  host_agent: "/agents/host/host_agent.sock"
182
176
  ```
183
177
 
@@ -198,7 +192,7 @@ On the host, sockets typically live under:
198
192
  ```text
199
193
  /var/run/robotis/agent_sockets/
200
194
  ├── ai_worker/s6_agent.sock
201
- ├── physical_ai_server/s6_agent.sock
195
+ ├── cyclo_intelligence/s6_agent.sock
202
196
  └── host/host_agent.sock ← created by cyclo_manager up
203
197
  ```
204
198
 
@@ -18,4 +18,4 @@
18
18
 
19
19
  """cyclo_manager CLI - pip-installable launcher for cyclo_manager server and UI containers."""
20
20
 
21
- __version__ = '0.2.0'
21
+ __version__ = '0.2.1'
@@ -95,7 +95,7 @@ def _setup_socket_dir(user: str) -> bool:
95
95
  check=True,
96
96
  capture_output=True,
97
97
  )
98
- print(f' [3/3] Removing stale socket file (if any)...')
98
+ print(' [3/3] Removing stale socket file (if any)...')
99
99
  subprocess.run(
100
100
  ['sudo', 'rm', '-f', HOST_AGENT_SOCKET],
101
101
  check=True,
@@ -109,8 +109,10 @@ def _setup_socket_dir(user: str) -> bool:
109
109
 
110
110
  def _install_sudoers(user: str) -> bool:
111
111
  """
112
- Write /etc/sudoers.d/cyclo_manager granting NOPASSWD for udev operations
113
- needed by container.sh (cp to /etc/udev/rules.d/, udevadm control/trigger).
112
+ Write sudoers rules for cyclo_manager.
113
+
114
+ Grant NOPASSWD for udev operations needed by container.sh
115
+ (cp to /etc/udev/rules.d/, udevadm control/trigger).
114
116
  """
115
117
  print(' Installing sudoers rules (cp, udevadm)...')
116
118
  sudoers_content = (
@@ -272,7 +274,10 @@ def _teardown_host_agent() -> None:
272
274
  steps = [
273
275
  (['sudo', 'systemctl', 'stop', f'{HOST_AGENT_SERVICE}.service'], 'stop service'),
274
276
  (['sudo', 'systemctl', 'disable', f'{HOST_AGENT_SERVICE}.service'], 'disable service'),
275
- (['sudo', 'rm', '-f', f'/etc/systemd/system/{HOST_AGENT_SERVICE}.service'], 'remove unit file'),
277
+ (
278
+ ['sudo', 'rm', '-f', f'/etc/systemd/system/{HOST_AGENT_SERVICE}.service'],
279
+ 'remove unit file',
280
+ ),
276
281
  (['sudo', 'systemctl', 'daemon-reload'], 'daemon-reload'),
277
282
  (['sudo', 'rm', '-f', '/etc/sudoers.d/cyclo_manager'], 'remove sudoers'),
278
283
  (['sudo', 'rm', '-rf', HOST_AGENT_SOCKET_DIR], 'remove socket dir'),
@@ -370,7 +375,9 @@ def cmd_update(args: argparse.Namespace) -> int:
370
375
  return e.returncode
371
376
 
372
377
  print('Refreshing host agent (unit, socket, sudoers)...')
373
- _ensure_host_agent()
378
+ if _ensure_host_agent() != 0:
379
+ print('Warning: Failed to refresh host agent service.', file=sys.stderr)
380
+ return 1
374
381
 
375
382
  print('cyclo_manager update completed.')
376
383
  return 0
@@ -4,5 +4,5 @@ robot_container: ai_worker
4
4
 
5
5
  sockets:
6
6
  ai_worker: "/agents/ai_worker/s6_agent.sock"
7
- physical_ai_server: "/agents/physical_ai_server/s6_agent.sock"
7
+ cyclo_intelligence: "/agents/cyclo_intelligence/s6_agent.sock"
8
8
  host_agent: "/agents/host/host_agent.sock"
@@ -11,7 +11,7 @@ services:
11
11
 
12
12
  cyclo_manager:
13
13
  container_name: cyclo_manager
14
- image: robotis/cyclo-manager:0.2.0
14
+ image: robotis/cyclo-manager:0.2.1
15
15
  restart: always
16
16
  network_mode: host
17
17
  volumes:
@@ -27,7 +27,7 @@ services:
27
27
 
28
28
  ui:
29
29
  container_name: cyclo_manager_ui
30
- image: robotis/cyclo-manager-ui:0.2.0
30
+ image: robotis/cyclo-manager-ui:0.2.1
31
31
  restart: always
32
32
  network_mode: host
33
33
  environment:
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "cyclo-manager"
7
- version = "0.2.0.dev12"
7
+ version = "0.2.1.dev0"
8
8
  description = "cyclo_manager CLI: pip-installable launcher for cyclo_manager server and UI containers. Run 'cyclo_manager up' to start Docker stack."
9
9
  readme = "README.md"
10
10
  license = "Apache-2.0"
@@ -1,6 +1,6 @@
1
1
  [metadata]
2
2
  name = cyclo-manager
3
- version = 0.2.0
3
+ version = 0.2.1
4
4
 
5
5
  [egg_info]
6
6
  egg_base = .