cyclo-manager 1.0.0.dev10__tar.gz → 1.1.0.dev2__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 (23) hide show
  1. {cyclo_manager-1.0.0.dev10 → cyclo_manager-1.1.0.dev2}/PKG-INFO +16 -9
  2. {cyclo_manager-1.0.0.dev10 → cyclo_manager-1.1.0.dev2}/README.md +15 -8
  3. {cyclo_manager-1.0.0.dev10 → cyclo_manager-1.1.0.dev2}/cyclo_host_agent/main.py +3 -1
  4. cyclo_manager-1.1.0.dev2/cyclo_host_agent/models.py +242 -0
  5. cyclo_manager-1.1.0.dev2/cyclo_host_agent/routers/files.py +540 -0
  6. {cyclo_manager-1.0.0.dev10 → cyclo_manager-1.1.0.dev2}/cyclo_host_agent/routers/repos.py +178 -4
  7. cyclo_manager-1.1.0.dev2/cyclo_host_agent/routers/system_stats.py +156 -0
  8. {cyclo_manager-1.0.0.dev10 → cyclo_manager-1.1.0.dev2}/cyclo_manager.egg-info/PKG-INFO +16 -9
  9. {cyclo_manager-1.0.0.dev10 → cyclo_manager-1.1.0.dev2}/cyclo_manager.egg-info/SOURCES.txt +2 -0
  10. {cyclo_manager-1.0.0.dev10 → cyclo_manager-1.1.0.dev2}/cyclo_manager_cli/docker/docker-compose.yml +2 -2
  11. {cyclo_manager-1.0.0.dev10 → cyclo_manager-1.1.0.dev2}/pyproject.toml +1 -1
  12. cyclo_manager-1.0.0.dev10/cyclo_host_agent/models.py +0 -105
  13. {cyclo_manager-1.0.0.dev10 → cyclo_manager-1.1.0.dev2}/cyclo_host_agent/__init__.py +0 -0
  14. {cyclo_manager-1.0.0.dev10 → cyclo_manager-1.1.0.dev2}/cyclo_host_agent/routers/__init__.py +0 -0
  15. {cyclo_manager-1.0.0.dev10 → cyclo_manager-1.1.0.dev2}/cyclo_host_agent/routers/update.py +0 -0
  16. {cyclo_manager-1.0.0.dev10 → cyclo_manager-1.1.0.dev2}/cyclo_manager.egg-info/dependency_links.txt +0 -0
  17. {cyclo_manager-1.0.0.dev10 → cyclo_manager-1.1.0.dev2}/cyclo_manager.egg-info/entry_points.txt +0 -0
  18. {cyclo_manager-1.0.0.dev10 → cyclo_manager-1.1.0.dev2}/cyclo_manager.egg-info/requires.txt +0 -0
  19. {cyclo_manager-1.0.0.dev10 → cyclo_manager-1.1.0.dev2}/cyclo_manager.egg-info/top_level.txt +0 -0
  20. {cyclo_manager-1.0.0.dev10 → cyclo_manager-1.1.0.dev2}/cyclo_manager_cli/__init__.py +0 -0
  21. {cyclo_manager-1.0.0.dev10 → cyclo_manager-1.1.0.dev2}/cyclo_manager_cli/cli.py +0 -0
  22. {cyclo_manager-1.0.0.dev10 → cyclo_manager-1.1.0.dev2}/cyclo_manager_cli/config/config.yml +0 -0
  23. {cyclo_manager-1.0.0.dev10 → cyclo_manager-1.1.0.dev2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cyclo-manager
3
- Version: 1.0.0.dev10
3
+ Version: 1.1.0.dev2
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
@@ -18,7 +18,7 @@ Requires-Dist: ruff; extra == "dev"
18
18
  **Console commands:** `cyclo_manager` (underscore), `cyclo-manager` (hyphen)
19
19
  **Host agent:** `cyclo_host_agent` (installed by the package, run via systemd)
20
20
 
21
- This package is the **pip-installable launcher** for the cyclo_manager stack on a robot host. It:
21
+ This package is the **pip-installable launcher** for the cyclo_manager stack on a robot host. It is intended for production robots that run the pre-built Docker images. It:
22
22
 
23
23
  1. Runs **`docker compose`** against a **bundled** [`cyclo_manager_cli/docker/docker-compose.yml`](cyclo_manager_cli/docker/docker-compose.yml) to start the **API** and **web UI** containers.
24
24
  2. Installs and maintains **`cyclo_host_agent`** as a **systemd** service for host-level operations (git repo updates, `cyclo_manager` package update from the UI).
@@ -50,11 +50,12 @@ For the full monorepo (API source, UI source, dev compose), see the [repository
50
50
 
51
51
  ## Prerequisites
52
52
 
53
- - **Docker** with **Compose v2** (`docker compose` — the legacy `docker-compose` binary alone is not enough)
53
+ - **Docker** with **Compose v2** (`docker compose`; the legacy `docker-compose` binary alone is not enough)
54
54
  - **Python 3.10+**
55
+ - **systemd**: required for the managed `cyclo_host_agent.service`
55
56
  - **`sudo`** — required on normal-user hosts to install the host agent systemd unit, socket directory permissions, and sudoers rules
56
57
  - For **`cyclo_manager update`:** **`pip`** or **`pip3`** on `PATH`
57
- - **Root shell handling** — root is rejected when a normal login user exists. On root-only devices, the host agent is installed as root.
58
+ - **Root shell handling** — `cyclo_manager up` rejects direct root execution when a normal login user exists. On root-only devices, the host agent is installed as root.
58
59
  - **Agent sockets** on the host under `/var/run/robotis/agent_sockets/` (robot containers and host agent). The bundled Compose file bind-mounts this tree into the API container as `/agents/`.
59
60
 
60
61
  ---
@@ -94,6 +95,8 @@ python3 -m cyclo_manager_cli.cli up
94
95
  | `cyclo_manager update --no-pull` | Same as `update`, but skip image pull (use locally cached images). |
95
96
  | `cyclo_manager --help` | Subcommand overview |
96
97
 
98
+ The CLI also has an internal `refresh-host-agent` subcommand. It is used by the sudoers rule and should normally not be invoked by users directly.
99
+
97
100
  **`down` vs `update`:** `down` removes the host agent entirely. `update` only stops Docker containers, upgrades the pip package, restarts the stack, and refreshes the host agent — it does **not** call `cyclo_manager down`.
98
101
 
99
102
  ---
@@ -120,18 +123,21 @@ The pip package installs a small **FastAPI** server that listens on a **Unix dom
120
123
  |------|------|
121
124
  | Socket | `/var/run/robotis/agent_sockets/host/host_agent.sock` |
122
125
  | systemd unit | `cyclo_host_agent.service` |
123
- | sudoers | `/etc/sudoers.d/cyclo_manager` (`cp`, `udevadm` for container setup scripts; `refresh-host-agent` CLI subcommand for UI updates; skipped on root-only devices) |
126
+ | sudoers | `/etc/sudoers.d/cyclo_manager` (`cp`, `udevadm` for container setup scripts; `refresh-host-agent` CLI subcommand for package-update refresh; skipped on root-only devices) |
124
127
 
125
128
  The API container reaches it at `/agents/host/host_agent.sock` (see bundled `config.yml`).
126
129
 
127
130
  **Responsibilities:**
128
131
 
129
- - List and update **`~/ROBOTIS-GIT/*`** git repositories (Version Management in the UI)
130
- - Run Cyclo Manager package updates from the UI by delegating to `cyclo_manager update`
132
+ - List managed **ROBOTIS-GIT** git repositories in the configured workspace.
133
+ - Check update availability from remote tags and local `package.xml` versions.
134
+ - Update repos on allowed branches (`main`, `jazzy`) using stash or reset workflows.
135
+ - Stop/start a repo's `docker/container.sh` helper during an update when requested by the UI.
136
+ - Run Cyclo Manager package updates from the UI by delegating to `cyclo_manager update`.
131
137
 
132
138
  `cyclo_manager up` installs the `refresh-host-agent` CLI subcommand into sudoers. It is registered as `sys.executable -m cyclo_manager_cli.cli refresh-host-agent` with `SETENV`, so UI-triggered updates can pass the current `PYTHONPATH` to sudo and do not depend on `PATH`. The command is idempotent and refreshes the socket directory, sudoers file, systemd unit, and service state after package upgrades.
133
139
 
134
- Repository scanning uses `CYCLO_HOST_AGENT_WORKSPACE` when set. Otherwise it uses the service user's home directory, except root-only devices with `/data/docker`, where `/data/docker` is used automatically.
140
+ Repository scanning and the Files UI use `CYCLO_HOST_AGENT_WORKSPACE` when set. Otherwise they use the service user's home directory, except root-only devices with `/data/docker`, where `/data/docker` is used automatically. Only repositories whose `origin` remote belongs to `ROBOTIS-GIT` are returned by the repo list/update endpoints.
135
141
 
136
142
  ---
137
143
 
@@ -211,6 +217,7 @@ So `/agents/ai_worker/s6_agent.sock` in config corresponds to the host path abov
211
217
  | Variable | Set by | Purpose |
212
218
  |----------|--------|---------|
213
219
  | **`CYCLO_MANAGER_CONFIG_FILE`** | CLI (`up`, `down`, `update`) | Absolute path to bundled `config.yml` on the host; mounted into the API container |
220
+ | **`CYCLO_HOST_AGENT_WORKSPACE`** | User or CLI-generated systemd unit | Workspace scanned by `cyclo_host_agent` for managed git repositories and used as the Files UI/API root |
214
221
  | **`HOSTNAME`** | CLI (default: machine hostname) | Passed to API as `HOST_HOSTNAME` |
215
222
  | **`CONFIG_FILE`** | Compose (`/app/config.yml`) | Path inside the API container |
216
223
  | **`ROS_DOMAIN_ID`** | **Not** set by CLI | Set inside robot containers (e.g. `~/.bashrc`) so DDS matches your fleet |
@@ -252,7 +259,7 @@ Python dependencies declared in [`pyproject.toml`](pyproject.toml):
252
259
  |---------|---------|
253
260
  | **fastapi** | `cyclo_host_agent` HTTP API |
254
261
  | **uvicorn** | `cyclo_host_agent` server |
255
- | **psutil** | Host agent / system utilities |
262
+ | **psutil** | Declared package dependency for host/system utility support |
256
263
 
257
264
  The **`cyclo_manager`** CLI itself uses only the Python standard library plus **`subprocess`** calls to **`docker compose`**, **`pip`**, **`systemctl`**, and **`sudo`**.
258
265
 
@@ -4,7 +4,7 @@
4
4
  **Console commands:** `cyclo_manager` (underscore), `cyclo-manager` (hyphen)
5
5
  **Host agent:** `cyclo_host_agent` (installed by the package, run via systemd)
6
6
 
7
- This package is the **pip-installable launcher** for the cyclo_manager stack on a robot host. It:
7
+ This package is the **pip-installable launcher** for the cyclo_manager stack on a robot host. It is intended for production robots that run the pre-built Docker images. It:
8
8
 
9
9
  1. Runs **`docker compose`** against a **bundled** [`cyclo_manager_cli/docker/docker-compose.yml`](cyclo_manager_cli/docker/docker-compose.yml) to start the **API** and **web UI** containers.
10
10
  2. Installs and maintains **`cyclo_host_agent`** as a **systemd** service for host-level operations (git repo updates, `cyclo_manager` package update from the UI).
@@ -36,11 +36,12 @@ For the full monorepo (API source, UI source, dev compose), see the [repository
36
36
 
37
37
  ## Prerequisites
38
38
 
39
- - **Docker** with **Compose v2** (`docker compose` — the legacy `docker-compose` binary alone is not enough)
39
+ - **Docker** with **Compose v2** (`docker compose`; the legacy `docker-compose` binary alone is not enough)
40
40
  - **Python 3.10+**
41
+ - **systemd**: required for the managed `cyclo_host_agent.service`
41
42
  - **`sudo`** — required on normal-user hosts to install the host agent systemd unit, socket directory permissions, and sudoers rules
42
43
  - For **`cyclo_manager update`:** **`pip`** or **`pip3`** on `PATH`
43
- - **Root shell handling** — root is rejected when a normal login user exists. On root-only devices, the host agent is installed as root.
44
+ - **Root shell handling** — `cyclo_manager up` rejects direct root execution when a normal login user exists. On root-only devices, the host agent is installed as root.
44
45
  - **Agent sockets** on the host under `/var/run/robotis/agent_sockets/` (robot containers and host agent). The bundled Compose file bind-mounts this tree into the API container as `/agents/`.
45
46
 
46
47
  ---
@@ -80,6 +81,8 @@ python3 -m cyclo_manager_cli.cli up
80
81
  | `cyclo_manager update --no-pull` | Same as `update`, but skip image pull (use locally cached images). |
81
82
  | `cyclo_manager --help` | Subcommand overview |
82
83
 
84
+ The CLI also has an internal `refresh-host-agent` subcommand. It is used by the sudoers rule and should normally not be invoked by users directly.
85
+
83
86
  **`down` vs `update`:** `down` removes the host agent entirely. `update` only stops Docker containers, upgrades the pip package, restarts the stack, and refreshes the host agent — it does **not** call `cyclo_manager down`.
84
87
 
85
88
  ---
@@ -106,18 +109,21 @@ The pip package installs a small **FastAPI** server that listens on a **Unix dom
106
109
  |------|------|
107
110
  | Socket | `/var/run/robotis/agent_sockets/host/host_agent.sock` |
108
111
  | systemd unit | `cyclo_host_agent.service` |
109
- | sudoers | `/etc/sudoers.d/cyclo_manager` (`cp`, `udevadm` for container setup scripts; `refresh-host-agent` CLI subcommand for UI updates; skipped on root-only devices) |
112
+ | sudoers | `/etc/sudoers.d/cyclo_manager` (`cp`, `udevadm` for container setup scripts; `refresh-host-agent` CLI subcommand for package-update refresh; skipped on root-only devices) |
110
113
 
111
114
  The API container reaches it at `/agents/host/host_agent.sock` (see bundled `config.yml`).
112
115
 
113
116
  **Responsibilities:**
114
117
 
115
- - List and update **`~/ROBOTIS-GIT/*`** git repositories (Version Management in the UI)
116
- - Run Cyclo Manager package updates from the UI by delegating to `cyclo_manager update`
118
+ - List managed **ROBOTIS-GIT** git repositories in the configured workspace.
119
+ - Check update availability from remote tags and local `package.xml` versions.
120
+ - Update repos on allowed branches (`main`, `jazzy`) using stash or reset workflows.
121
+ - Stop/start a repo's `docker/container.sh` helper during an update when requested by the UI.
122
+ - Run Cyclo Manager package updates from the UI by delegating to `cyclo_manager update`.
117
123
 
118
124
  `cyclo_manager up` installs the `refresh-host-agent` CLI subcommand into sudoers. It is registered as `sys.executable -m cyclo_manager_cli.cli refresh-host-agent` with `SETENV`, so UI-triggered updates can pass the current `PYTHONPATH` to sudo and do not depend on `PATH`. The command is idempotent and refreshes the socket directory, sudoers file, systemd unit, and service state after package upgrades.
119
125
 
120
- Repository scanning uses `CYCLO_HOST_AGENT_WORKSPACE` when set. Otherwise it uses the service user's home directory, except root-only devices with `/data/docker`, where `/data/docker` is used automatically.
126
+ Repository scanning and the Files UI use `CYCLO_HOST_AGENT_WORKSPACE` when set. Otherwise they use the service user's home directory, except root-only devices with `/data/docker`, where `/data/docker` is used automatically. Only repositories whose `origin` remote belongs to `ROBOTIS-GIT` are returned by the repo list/update endpoints.
121
127
 
122
128
  ---
123
129
 
@@ -197,6 +203,7 @@ So `/agents/ai_worker/s6_agent.sock` in config corresponds to the host path abov
197
203
  | Variable | Set by | Purpose |
198
204
  |----------|--------|---------|
199
205
  | **`CYCLO_MANAGER_CONFIG_FILE`** | CLI (`up`, `down`, `update`) | Absolute path to bundled `config.yml` on the host; mounted into the API container |
206
+ | **`CYCLO_HOST_AGENT_WORKSPACE`** | User or CLI-generated systemd unit | Workspace scanned by `cyclo_host_agent` for managed git repositories and used as the Files UI/API root |
200
207
  | **`HOSTNAME`** | CLI (default: machine hostname) | Passed to API as `HOST_HOSTNAME` |
201
208
  | **`CONFIG_FILE`** | Compose (`/app/config.yml`) | Path inside the API container |
202
209
  | **`ROS_DOMAIN_ID`** | **Not** set by CLI | Set inside robot containers (e.g. `~/.bashrc`) so DDS matches your fleet |
@@ -238,7 +245,7 @@ Python dependencies declared in [`pyproject.toml`](pyproject.toml):
238
245
  |---------|---------|
239
246
  | **fastapi** | `cyclo_host_agent` HTTP API |
240
247
  | **uvicorn** | `cyclo_host_agent` server |
241
- | **psutil** | Host agent / system utilities |
248
+ | **psutil** | Declared package dependency for host/system utility support |
242
249
 
243
250
  The **`cyclo_manager`** CLI itself uses only the Python standard library plus **`subprocess`** calls to **`docker compose`**, **`pip`**, **`systemctl`**, and **`sudo`**.
244
251
 
@@ -21,7 +21,7 @@
21
21
  import logging
22
22
  from pathlib import Path
23
23
 
24
- from cyclo_host_agent.routers import repos, update
24
+ from cyclo_host_agent.routers import files, repos, system_stats, update
25
25
  from cyclo_manager_cli import __version__
26
26
  from fastapi import FastAPI
27
27
  import uvicorn
@@ -41,6 +41,8 @@ app = FastAPI(
41
41
  )
42
42
 
43
43
  app.include_router(repos.router)
44
+ app.include_router(files.router)
45
+ app.include_router(system_stats.router)
44
46
  app.include_router(update.router)
45
47
 
46
48
 
@@ -0,0 +1,242 @@
1
+ #!/usr/bin/env python3
2
+ #
3
+ # Copyright 2026 ROBOTIS CO., LTD.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+ # Author: Hyungyu Kim
18
+
19
+ """Pydantic models for cyclo_host_agent API."""
20
+
21
+ from typing import Optional
22
+
23
+ from pydantic import BaseModel
24
+
25
+
26
+ class RepoInfo(BaseModel):
27
+ """Single git repository info."""
28
+
29
+ name: str
30
+ path: str
31
+ branch: Optional[str] = None
32
+ remote: Optional[str] = None
33
+
34
+
35
+ class RepoListResponse(BaseModel):
36
+ """Response for GET /repos."""
37
+
38
+ repos: list[RepoInfo]
39
+ workspace_path: str
40
+
41
+
42
+ class RepoUpdateStatus(BaseModel):
43
+ """Version update status for a single repository."""
44
+
45
+ name: str
46
+ branch: Optional[str] = None
47
+ current_version: Optional[str] = None
48
+ latest_version: Optional[str] = None
49
+ has_update: bool
50
+
51
+
52
+ class RepoUpdatesResponse(BaseModel):
53
+ """Response for GET /repos/updates."""
54
+
55
+ repos: list[RepoUpdateStatus]
56
+ workspace_path: str
57
+
58
+
59
+ class FileChange(BaseModel):
60
+ """A single entry from git status --porcelain."""
61
+
62
+ path: str
63
+ status: str # e.g. M, D, ??, etc.
64
+
65
+
66
+ class RepoStatusResponse(BaseModel):
67
+ """Response for GET /repos/{name}/status."""
68
+
69
+ name: str
70
+ changes: list[FileChange]
71
+ has_changes: bool
72
+
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
+
82
+ class UpdateRequest(BaseModel):
83
+ """Request body for POST /repos/{name}/update."""
84
+
85
+ strategy: str # 'stash' | 'reset'
86
+ preserve_files: list[str] = [] # files to keep when using the reset strategy
87
+
88
+
89
+ class UpdateResponse(BaseModel):
90
+ """Response for POST /repos/{name}/update."""
91
+
92
+ name: str
93
+ success: bool
94
+ output: str
95
+ stash_conflict: bool = False
96
+ stash_conflict_files: list[str] = []
97
+
98
+
99
+ class ContainerScriptResponse(BaseModel):
100
+ """Response for POST /repos/{name}/container/{action}."""
101
+
102
+ name: str
103
+ action: str
104
+ success: bool
105
+ output: str
106
+
107
+
108
+ class ContainerStartStatusResponse(BaseModel):
109
+ """Current output/status for a container start operation."""
110
+
111
+ running: bool
112
+ output: str
113
+ success: bool | None = None
114
+ error: str = ''
115
+
116
+
117
+ class HostSystemStatsResponse(BaseModel):
118
+ """Host CPU/memory/disk/uptime/temperature status."""
119
+
120
+ cpu_percent: float
121
+ memory_used_mb: int
122
+ memory_total_mb: int
123
+ disk_used_gb: float
124
+ disk_total_gb: float
125
+ ssd_used_gb: float | None = None
126
+ ssd_total_gb: float | None = None
127
+ ssd_mount_path: str | None = None
128
+ uptime_seconds: int
129
+ temperature_celsius: float | None = None
130
+
131
+
132
+ class HostProcessInfo(BaseModel):
133
+ """Single host process CPU/memory usage sample."""
134
+
135
+ pid: int
136
+ user: str
137
+ cpu_percent: float
138
+ memory_percent: float
139
+ rss_kb: int | None = None
140
+ command: str
141
+
142
+
143
+ class HostProcessesResponse(BaseModel):
144
+ """Host process list with aggregate resource summary."""
145
+
146
+ cpu_percent: float
147
+ memory_used_mb: int
148
+ memory_total_mb: int
149
+ processes: list[HostProcessInfo]
150
+
151
+
152
+ class FileTreeEntry(BaseModel):
153
+ """Single file browser entry."""
154
+
155
+ name: str
156
+ path: str
157
+ type: str
158
+ size: int | None = None
159
+ modified: float | None = None
160
+ readonly: bool = False
161
+ hidden: bool = False
162
+ symlink: bool = False
163
+ git_status: str | None = None
164
+
165
+
166
+ class FileTreeResponse(BaseModel):
167
+ """Response for GET /files/tree."""
168
+
169
+ root_path: str
170
+ path: str
171
+ entries: list[FileTreeEntry]
172
+
173
+
174
+ class FileSearchResponse(BaseModel):
175
+ """Response for GET /files/search."""
176
+
177
+ root_path: str
178
+ path: str
179
+ query: str
180
+ entries: list[FileTreeEntry]
181
+ truncated: bool = False
182
+
183
+
184
+ class FileReadResponse(BaseModel):
185
+ """Response for GET /files/read."""
186
+
187
+ path: str
188
+ content: str
189
+ size: int
190
+ modified: float
191
+ readonly: bool = False
192
+
193
+
194
+ class FileDiffResponse(BaseModel):
195
+ """Response for GET /files/diff."""
196
+
197
+ path: str
198
+ status: str
199
+ original_content: str
200
+ current_content: str
201
+
202
+
203
+ class FileWriteRequest(BaseModel):
204
+ """Request body for POST /files/write."""
205
+
206
+ path: str
207
+ content: str
208
+ expected_modified: float | None = None
209
+
210
+
211
+ class FileCreateRequest(BaseModel):
212
+ """Request body for POST /files/create."""
213
+
214
+ path: str
215
+ type: str
216
+ content: str = ''
217
+
218
+
219
+ class FileRenameRequest(BaseModel):
220
+ """Request body for POST /files/rename."""
221
+
222
+ path: str
223
+ new_name: str
224
+
225
+
226
+ class FileUploadResponse(BaseModel):
227
+ """Response for POST /files/upload."""
228
+
229
+ name: str
230
+ path: str
231
+ size: int
232
+ overwritten: bool = False
233
+ success: bool
234
+ message: str
235
+
236
+
237
+ class FileOperationResponse(BaseModel):
238
+ """Generic file operation response."""
239
+
240
+ path: str
241
+ success: bool
242
+ message: str