gogeo-client-agentos 0.2.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.
Files changed (23) hide show
  1. gogeo_client_agentos-0.2.2/PKG-INFO +98 -0
  2. gogeo_client_agentos-0.2.2/README.md +86 -0
  3. gogeo_client_agentos-0.2.2/agentos/__init__.py +0 -0
  4. gogeo_client_agentos-0.2.2/agentos/cli.py +928 -0
  5. gogeo_client_agentos-0.2.2/agentos/resources/__init__.py +0 -0
  6. gogeo_client_agentos-0.2.2/agentos/resources/app/__init__.py +0 -0
  7. gogeo_client_agentos-0.2.2/agentos/resources/app/app.asar +0 -0
  8. gogeo_client_agentos-0.2.2/agentos/resources/desktop/__init__.py +0 -0
  9. gogeo_client_agentos-0.2.2/agentos/resources/desktop/chromium.desktop +9 -0
  10. gogeo_client_agentos-0.2.2/agentos/resources/desktop/gogeoclaw.desktop +10 -0
  11. gogeo_client_agentos-0.2.2/agentos/resources/desktop/terminal.desktop +9 -0
  12. gogeo_client_agentos-0.2.2/agentos/resources/desktop/vscode.desktop +9 -0
  13. gogeo_client_agentos-0.2.2/agentos/resources/icons/@nuwax-ainuwaclaw.png +0 -0
  14. gogeo_client_agentos-0.2.2/agentos/resources/icons/__init__.py +0 -0
  15. gogeo_client_agentos-0.2.2/agentos/resources/wallpaper/__init__.py +0 -0
  16. gogeo_client_agentos-0.2.2/agentos/resources/wallpaper/gogeoDesk.jpg +0 -0
  17. gogeo_client_agentos-0.2.2/gogeo_client_agentos.egg-info/PKG-INFO +98 -0
  18. gogeo_client_agentos-0.2.2/gogeo_client_agentos.egg-info/SOURCES.txt +21 -0
  19. gogeo_client_agentos-0.2.2/gogeo_client_agentos.egg-info/dependency_links.txt +1 -0
  20. gogeo_client_agentos-0.2.2/gogeo_client_agentos.egg-info/entry_points.txt +2 -0
  21. gogeo_client_agentos-0.2.2/gogeo_client_agentos.egg-info/top_level.txt +1 -0
  22. gogeo_client_agentos-0.2.2/pyproject.toml +30 -0
  23. gogeo_client_agentos-0.2.2/setup.cfg +4 -0
@@ -0,0 +1,98 @@
1
+ Metadata-Version: 2.4
2
+ Name: gogeo-client-agentos
3
+ Version: 0.2.2
4
+ Summary: AgentOS CLI tool for managing the AgentOS Client Docker container
5
+ Author-email: agentos-team <agentos@example.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/agentos/client
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Operating System :: OS Independent
10
+ Requires-Python: >=3.8
11
+ Description-Content-Type: text/markdown
12
+
13
+ # AgentOS Client
14
+
15
+ AgentOS Client Docker 容器管理 CLI 工具。
16
+
17
+ ## 安装
18
+
19
+ ```bash
20
+ pip install agentos
21
+ ```
22
+
23
+ ## 使用
24
+
25
+ ### 首次安装/设置
26
+
27
+ ```bash
28
+ # 方式一:直接设置(从环境变量或交互式输入读取 key)
29
+ agentos setup
30
+
31
+ # 方式二:命令行指定 key
32
+ agentos setup --key "your-nuwax-saved-key"
33
+
34
+ # 方式三:先设置环境变量
35
+ export NUWAX_SAVED_KEY="your-key"
36
+ agentos setup
37
+ ```
38
+
39
+ setup 流程:
40
+ 1. 检查 Docker 是否安装,未安装则自动安装(仅 Linux)
41
+ 2. 拉取 agentos-client 镜像
42
+ 3. 生成 docker-compose.yml 到 `~/.agentos/`
43
+ 4. 保存 key 到 `~/.agentos/.env`
44
+
45
+ ### 日常管理
46
+
47
+ ```bash
48
+ agentos start # 启动容器
49
+ agentos stop # 停止容器
50
+ agentos restart # 重启容器
51
+ agentos status # 查看容器状态
52
+ agentos logs # 查看最近 50 行日志
53
+ ```
54
+
55
+ ### 更新 key
56
+
57
+ ```bash
58
+ agentos update-key "new-key-here"
59
+ agentos restart # 重启生效
60
+ ```
61
+
62
+ ### 重新部署
63
+
64
+ ```bash
65
+ agentos redeploy # 删除旧配置,重新生成并重启
66
+ ```
67
+
68
+ ## 发布到 PyPI
69
+
70
+ ```bash
71
+ # 安装构建工具
72
+ pip install build twine
73
+
74
+ # 构建
75
+ cd gogeo-client
76
+ python -m build
77
+
78
+ # 发布到 TestPyPI(测试)
79
+ python -m twine upload --repository testpypi dist/*
80
+
81
+ # 发布到 PyPI(正式)
82
+ python -m twine upload dist/*
83
+ ```
84
+
85
+ ## 目录结构
86
+
87
+ ```
88
+ gogeo-client/
89
+ ├── pyproject.toml # Python 包配置
90
+ ├── agentos/
91
+ │ ├── __init__.py
92
+ │ └── cli.py # CLI 入口
93
+ ├── app/ # 应用覆盖文件
94
+ ├── desktop/ # 桌面快捷方式
95
+ ├── icons/ # 桌面图标
96
+ ├── wallpaper/ # 桌面壁纸
97
+ └── docker-compose.yml # 本地开发用 compose
98
+ ```
@@ -0,0 +1,86 @@
1
+ # AgentOS Client
2
+
3
+ AgentOS Client Docker 容器管理 CLI 工具。
4
+
5
+ ## 安装
6
+
7
+ ```bash
8
+ pip install agentos
9
+ ```
10
+
11
+ ## 使用
12
+
13
+ ### 首次安装/设置
14
+
15
+ ```bash
16
+ # 方式一:直接设置(从环境变量或交互式输入读取 key)
17
+ agentos setup
18
+
19
+ # 方式二:命令行指定 key
20
+ agentos setup --key "your-nuwax-saved-key"
21
+
22
+ # 方式三:先设置环境变量
23
+ export NUWAX_SAVED_KEY="your-key"
24
+ agentos setup
25
+ ```
26
+
27
+ setup 流程:
28
+ 1. 检查 Docker 是否安装,未安装则自动安装(仅 Linux)
29
+ 2. 拉取 agentos-client 镜像
30
+ 3. 生成 docker-compose.yml 到 `~/.agentos/`
31
+ 4. 保存 key 到 `~/.agentos/.env`
32
+
33
+ ### 日常管理
34
+
35
+ ```bash
36
+ agentos start # 启动容器
37
+ agentos stop # 停止容器
38
+ agentos restart # 重启容器
39
+ agentos status # 查看容器状态
40
+ agentos logs # 查看最近 50 行日志
41
+ ```
42
+
43
+ ### 更新 key
44
+
45
+ ```bash
46
+ agentos update-key "new-key-here"
47
+ agentos restart # 重启生效
48
+ ```
49
+
50
+ ### 重新部署
51
+
52
+ ```bash
53
+ agentos redeploy # 删除旧配置,重新生成并重启
54
+ ```
55
+
56
+ ## 发布到 PyPI
57
+
58
+ ```bash
59
+ # 安装构建工具
60
+ pip install build twine
61
+
62
+ # 构建
63
+ cd gogeo-client
64
+ python -m build
65
+
66
+ # 发布到 TestPyPI(测试)
67
+ python -m twine upload --repository testpypi dist/*
68
+
69
+ # 发布到 PyPI(正式)
70
+ python -m twine upload dist/*
71
+ ```
72
+
73
+ ## 目录结构
74
+
75
+ ```
76
+ gogeo-client/
77
+ ├── pyproject.toml # Python 包配置
78
+ ├── agentos/
79
+ │ ├── __init__.py
80
+ │ └── cli.py # CLI 入口
81
+ ├── app/ # 应用覆盖文件
82
+ ├── desktop/ # 桌面快捷方式
83
+ ├── icons/ # 桌面图标
84
+ ├── wallpaper/ # 桌面壁纸
85
+ └── docker-compose.yml # 本地开发用 compose
86
+ ```
File without changes
@@ -0,0 +1,928 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ AgentOS CLI tool
4
+ """
5
+
6
+ import argparse
7
+ import os
8
+ import platform
9
+ import subprocess
10
+ import sys
11
+ import time
12
+ from pathlib import Path
13
+
14
+ VERSION = "0.2.0"
15
+ IMAGE_NAME = "nuwax-docker-images-registry.cn-hangzhou.cr.aliyuncs.com/nuwax/nuwax-agent-client:latest"
16
+ CONTAINER_NAME = "agentos-client"
17
+
18
+ COLORS = {
19
+ "green": "\033[0;32m",
20
+ "yellow": "\033[1;33m",
21
+ "red": "\033[0;31m",
22
+ "cyan": "\033[0;36m",
23
+ "reset": "\033[0m",
24
+ }
25
+
26
+
27
+ def color(name, text):
28
+ return f"{COLORS.get(name, '')}{text}{COLORS['reset']}"
29
+
30
+
31
+ def info(text):
32
+ print(color("green", f"[INFO] {text}"))
33
+
34
+
35
+ def warn(text):
36
+ print(color("yellow", f"[WARN] {text}"))
37
+
38
+
39
+ def error(text):
40
+ print(color("red", f"[ERROR] {text}"))
41
+
42
+
43
+ # ============================================================
44
+ # Docker mirrors (acceleration)
45
+ # ============================================================
46
+
47
+ DOCKER_MIRRORS = [
48
+ "https://docker.1ms.run",
49
+ "https://hub-mirror.c.163.com",
50
+ "https://docker.m.daocloud.io",
51
+ ]
52
+
53
+
54
+ def configure_docker_mirrors():
55
+ """配置 Docker 镜像加速器"""
56
+ system = platform.system()
57
+ info("正在检查 Docker 镜像加速配置...")
58
+
59
+ if system == "Linux":
60
+ _configure_linux_mirrors()
61
+ elif system == "Darwin":
62
+ _configure_darwin_mirrors()
63
+ elif system == "Windows":
64
+ _configure_windows_mirrors()
65
+
66
+
67
+ def _configure_linux_mirrors():
68
+ daemon_json = Path("/etc/docker/daemon.json")
69
+ if daemon_json.exists():
70
+ import json
71
+ try:
72
+ existing = json.loads(daemon_json.read_text())
73
+ if "registry-mirrors" in existing:
74
+ info("Docker 镜像加速已配置")
75
+ return
76
+ except (json.JSONDecodeError, IOError):
77
+ pass
78
+
79
+ import json
80
+ config = {"registry-mirrors": DOCKER_MIRRORS}
81
+ if daemon_json.exists():
82
+ try:
83
+ existing = json.loads(daemon_json.read_text())
84
+ existing.update(config)
85
+ config = existing
86
+ except (json.JSONDecodeError, IOError):
87
+ pass
88
+
89
+ try:
90
+ daemon_json.write_text(json.dumps(config, indent=2))
91
+ info("已写入 Docker 镜像加速配置")
92
+ subprocess.run(["sudo", "systemctl", "reload", "docker"], capture_output=True, text=True)
93
+ result = subprocess.run(["docker", "info"], capture_output=True, text=True, timeout=5)
94
+ if result.returncode != 0:
95
+ subprocess.run(["sudo", "systemctl", "restart", "docker"])
96
+ except PermissionError:
97
+ warn("无权限写入 /etc/docker/daemon.json,跳过镜像加速配置")
98
+
99
+
100
+ def _configure_darwin_mirrors():
101
+ daemon_json = Path.home() / ".docker" / "daemon.json"
102
+ daemon_json.parent.mkdir(parents=True, exist_ok=True)
103
+ import json
104
+ if daemon_json.exists():
105
+ try:
106
+ existing = json.loads(daemon_json.read_text())
107
+ if "registry-mirrors" in existing:
108
+ info("Docker 镜像加速已配置")
109
+ return
110
+ existing.update({"registry-mirrors": DOCKER_MIRRORS})
111
+ config = existing
112
+ except (json.JSONDecodeError, IOError):
113
+ config = {"registry-mirrors": DOCKER_MIRRORS}
114
+ else:
115
+ config = {"registry-mirrors": DOCKER_MIRRORS}
116
+
117
+ daemon_json.write_text(json.dumps(config, indent=2))
118
+ info("已写入 Docker 镜像加速配置,请重启 Docker Desktop")
119
+
120
+
121
+ def _configure_windows_mirrors():
122
+ import json
123
+ docker_config_dir = Path(os.environ.get("PROGRAMDATA", "")) / "Docker" / "config"
124
+ daemon_json = docker_config_dir / "daemon.json"
125
+ daemon_json_alt = docker_config_dir / "daemon" / "daemon.json"
126
+
127
+ for config_path in [daemon_json, daemon_json_alt]:
128
+ if config_path.exists():
129
+ try:
130
+ existing = json.loads(config_path.read_text())
131
+ if "registry-mirrors" in existing:
132
+ info("Docker 镜像加速已配置")
133
+ return
134
+ existing.update({"registry-mirrors": DOCKER_MIRRORS})
135
+ config = existing
136
+ except (json.JSONDecodeError, IOError):
137
+ config = {"registry-mirrors": DOCKER_MIRRORS}
138
+ config_path.write_text(json.dumps(config, indent=2))
139
+ info("已写入 Docker 镜像加速配置")
140
+ return
141
+
142
+ docker_config_dir.mkdir(parents=True, exist_ok=True)
143
+ daemon_json.write_text(json.dumps({"registry-mirrors": DOCKER_MIRRORS}, indent=2))
144
+ info("已写入 Docker 镜像加速配置")
145
+
146
+
147
+ # ============================================================
148
+ # Docker check / install
149
+ # ============================================================
150
+
151
+ def docker_installed():
152
+ """检查 Docker 是否已安装并运行"""
153
+ try:
154
+ result = subprocess.run(
155
+ ["docker", "--version"], capture_output=True, text=True, timeout=5
156
+ )
157
+ if result.returncode != 0:
158
+ return False
159
+ except (subprocess.SubprocessError, FileNotFoundError):
160
+ return False
161
+
162
+ try:
163
+ result = subprocess.run(
164
+ ["docker", "info"], capture_output=True, text=True, timeout=10
165
+ )
166
+ return result.returncode == 0
167
+ except (subprocess.SubprocessError, FileNotFoundError):
168
+ return False
169
+
170
+
171
+ def check_docker():
172
+ """检查 Docker,未安装则自动安装"""
173
+ try:
174
+ result = subprocess.run(
175
+ ["docker", "--version"], capture_output=True, text=True, timeout=5
176
+ )
177
+ docker_binary_exists = result.returncode == 0
178
+ except (subprocess.SubprocessError, FileNotFoundError):
179
+ docker_binary_exists = False
180
+
181
+ if docker_installed():
182
+ return
183
+
184
+ if docker_binary_exists:
185
+ warn("Docker 已安装但服务未启动,正在尝试启动...")
186
+ _start_docker()
187
+ if docker_installed():
188
+ info(f"Docker 已启动: {subprocess.run(['docker', '--version'], capture_output=True, text=True).stdout.strip()}")
189
+ return
190
+ warn("Docker 服务启动失败,请手动检查")
191
+ sys.exit(1)
192
+
193
+ # Windows 特殊处理:检查 Docker Desktop 是否已安装(即使 docker 不在 PATH 中)
194
+ if platform.system() == "Windows":
195
+ if _check_docker_desktop_installed_windows():
196
+ warn("Docker Desktop 已安装但 docker 命令不可用,正在启动...")
197
+ _start_docker()
198
+ if docker_installed():
199
+ info(f"Docker 已启动: {subprocess.run(['docker', '--version'], capture_output=True, text=True).stdout.strip()}")
200
+ return
201
+ warn("Docker 服务启动失败,请手动检查")
202
+ sys.exit(1)
203
+
204
+ warn("未检测到 Docker,开始自动安装...")
205
+ install_docker()
206
+
207
+ if not docker_installed():
208
+ error("Docker 安装完成但服务未启动,请手动检查")
209
+ sys.exit(1)
210
+
211
+ info(f"Docker 已安装: {subprocess.run(['docker', '--version'], capture_output=True, text=True).stdout.strip()}")
212
+
213
+
214
+ def _check_docker_desktop_installed_windows():
215
+ """Windows 上检查 Docker Desktop 是否已安装"""
216
+ try:
217
+ result = subprocess.run(
218
+ ["winget", "list", "--id", "Docker.DockerDesktop",
219
+ "--accept-source-agreements"],
220
+ capture_output=True, text=True
221
+ )
222
+ return "Docker.DockerDesktop" in result.stdout or "Docker Desktop" in result.stdout
223
+ except (subprocess.SubprocessError, FileNotFoundError):
224
+ return False
225
+
226
+
227
+ def _start_docker():
228
+ """尝试启动 Docker 服务"""
229
+ system = platform.system()
230
+ if system == "Windows":
231
+ try:
232
+ subprocess.Popen(
233
+ ["C:\\Program Files\\Docker\\Docker\\Docker Desktop.exe"],
234
+ creationflags=subprocess.CREATE_NO_WINDOW
235
+ )
236
+ except FileNotFoundError:
237
+ pass
238
+ _wait_for_docker_ready()
239
+ elif system == "Darwin":
240
+ subprocess.Popen(["open", "/Applications/Docker.app"])
241
+ _wait_for_docker_ready()
242
+ elif system == "Linux":
243
+ subprocess.run(["sudo", "systemctl", "start", "docker"])
244
+
245
+
246
+ def _wait_for_docker_ready(timeout=300):
247
+ """轮询等待 Docker 就绪"""
248
+ start = time.time()
249
+ dots = 0
250
+ while time.time() - start < timeout:
251
+ try:
252
+ result = subprocess.run(
253
+ ["docker", "info"],
254
+ capture_output=True, text=True, timeout=5
255
+ )
256
+ if result.returncode == 0:
257
+ print()
258
+ info("Docker 已就绪")
259
+ return
260
+ except (subprocess.SubprocessError, FileNotFoundError):
261
+ pass
262
+
263
+ dots += 1
264
+ if dots % 5 == 0:
265
+ elapsed = int(time.time() - start)
266
+ print(f"\r 等待中... ({elapsed}s)", end="", flush=True)
267
+
268
+ time.sleep(3)
269
+
270
+ print()
271
+ error(f"Docker 在 {timeout}s 内未就绪,请稍后重试")
272
+ sys.exit(1)
273
+
274
+
275
+ def install_docker():
276
+ """自动安装 Docker"""
277
+ system = platform.system()
278
+
279
+ if system == "Windows":
280
+ _install_docker_windows()
281
+ elif system == "Darwin":
282
+ _install_docker_mac()
283
+ else:
284
+ _install_docker_linux()
285
+
286
+ # 启动服务(非 Windows)
287
+ if system != "Windows":
288
+ info("正在启动 Docker 服务...")
289
+ subprocess.run(["sudo", "systemctl", "start", "docker"])
290
+ subprocess.run(["sudo", "systemctl", "enable", "docker"])
291
+ _wait_for_docker_ready()
292
+ return
293
+
294
+ info("Docker 安装完成,等待服务就绪...")
295
+ _wait_for_docker_ready()
296
+
297
+
298
+ def _install_docker_windows():
299
+ # 先检查 winget 是否显示已安装(避免重复下载安装)
300
+ try:
301
+ result = subprocess.run(
302
+ ["winget", "list", "--id", "Docker.DockerDesktop",
303
+ "--accept-source-agreements"],
304
+ capture_output=True, text=True
305
+ )
306
+ if "Docker.DockerDesktop" in result.stdout or "Docker Desktop" in result.stdout:
307
+ info("Docker Desktop 已安装,正在启动...")
308
+ _start_docker()
309
+ return
310
+ except FileNotFoundError:
311
+ pass
312
+
313
+ info("正在安装 Docker Desktop (Windows)...")
314
+
315
+ # 优先使用 winget
316
+ try:
317
+ result = subprocess.run(
318
+ ["winget", "--version"], capture_output=True, text=True
319
+ )
320
+ if result.returncode == 0:
321
+ info("使用 winget 安装...")
322
+ rc = subprocess.run([
323
+ "winget", "install", "-e", "--id", "Docker.DockerDesktop",
324
+ "--accept-package-agreements", "--accept-source-agreements"
325
+ ])
326
+ if rc.returncode == 0:
327
+ _start_docker()
328
+ return
329
+ warn("winget 安装失败,尝试直接下载...")
330
+ except FileNotFoundError:
331
+ pass
332
+
333
+ # 备选:PowerShell 直接下载安装
334
+ info("使用 PowerShell 下载安装...")
335
+ docker_installer_url = (
336
+ "https://desktop.docker.com/win/main/amd64/225177/Docker%20Desktop%20Installer.exe"
337
+ )
338
+ installer_path = os.path.join(
339
+ os.environ.get("TEMP", "."), "DockerDesktopInstaller.exe"
340
+ )
341
+
342
+ info(f"正在下载: {docker_installer_url}")
343
+ rc = subprocess.run([
344
+ "powershell", "-Command",
345
+ f"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; "
346
+ f"Invoke-WebRequest -Uri '{docker_installer_url}' -OutFile '{installer_path}'"
347
+ ])
348
+ if rc.returncode != 0:
349
+ warn("下载失败,请手动安装 Docker Desktop:")
350
+ warn("https://www.docker.com/products/docker-desktop/")
351
+ sys.exit(1)
352
+
353
+ info("正在安装 Docker Desktop...")
354
+ subprocess.run([installer_path, "install", "--quiet", "--accept-license"])
355
+ _start_docker()
356
+
357
+
358
+ def _install_docker_mac():
359
+ info("正在安装 Docker Desktop (macOS)...")
360
+
361
+ try:
362
+ result = subprocess.run(
363
+ ["brew", "--version"], capture_output=True, text=True
364
+ )
365
+ if result.returncode == 0:
366
+ info("使用 Homebrew 安装...")
367
+ subprocess.run(["brew", "install", "--cask", "docker"])
368
+ _start_docker()
369
+ return
370
+ except FileNotFoundError:
371
+ pass
372
+
373
+ info("Homebrew 不可用,直接下载 Docker Desktop...")
374
+ docker_dmg_url = "https://desktop.docker.com/mac/main/arm64/Docker.dmg"
375
+ dmg_path = "/tmp/Docker.dmg"
376
+
377
+ info(f"正在下载: {docker_dmg_url}")
378
+ subprocess.run(["curl", "-fsSL", docker_dmg_url, "-o", dmg_path])
379
+
380
+ info("正在挂载并安装...")
381
+ result = subprocess.run(
382
+ ["hdiutil", "attach", dmg_path],
383
+ capture_output=True, text=True
384
+ )
385
+ mount_point = None
386
+ for line in result.stdout.splitlines():
387
+ if "Docker" in line and "/Volumes/" in line:
388
+ mount_point = line.split("/Volumes/")[-1].strip()
389
+ break
390
+
391
+ if mount_point:
392
+ subprocess.run(["cp", "-R", f"/Volumes/{mount_point}/Docker.app", "/Applications/"])
393
+ subprocess.run(["hdiutil", "detach", f"/Volumes/{mount_point}"])
394
+
395
+ os.remove(dmg_path)
396
+ _start_docker()
397
+
398
+
399
+ def _install_docker_linux():
400
+ try:
401
+ with open("/etc/os-release") as f:
402
+ os_release = f.read()
403
+ except FileNotFoundError:
404
+ os_release = ""
405
+
406
+ if "ubuntu" in os_release or "debian" in os_release:
407
+ _install_docker_debian()
408
+ elif "centos" in os_release or "rhel" in os_release or "rocky" in os_release or "almalinux" in os_release:
409
+ _install_docker_centos()
410
+ else:
411
+ _install_docker_generic()
412
+
413
+
414
+ def _install_docker_debian():
415
+ info("正在安装 Docker (Debian/Ubuntu)...")
416
+ _run_shell(["sudo", "apt-get", "update"])
417
+ _run_shell([
418
+ "sudo", "apt-get", "install", "-y",
419
+ "ca-certificates", "curl", "gnupg", "lsb-release",
420
+ ])
421
+ _run_shell(["sudo", "install", "-m", "0755", "-d", "/etc/apt/keyrings"])
422
+ try:
423
+ _run_shell([
424
+ "sudo", "bash", "-c",
425
+ "curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg "
426
+ "| gpg --dearmor -o /etc/apt/keyrings/docker.gpg"
427
+ ])
428
+ except RuntimeError:
429
+ _run_shell([
430
+ "sudo", "bash", "-c",
431
+ "curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/debian/gpg "
432
+ "| gpg --dearmor -o /etc/apt/keyrings/docker.gpg"
433
+ ])
434
+ _run_shell(["sudo", "chmod", "a+r", "/etc/apt/keyrings/docker.gpg"])
435
+ _run_shell([
436
+ "sudo", "bash", "-c",
437
+ "echo 'deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] "
438
+ "https://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable' "
439
+ "> /etc/apt/sources.list.d/docker.list"
440
+ ])
441
+ _run_shell(["sudo", "apt-get", "update"])
442
+ _run_shell([
443
+ "sudo", "apt-get", "install", "-y",
444
+ "docker-ce", "docker-ce-cli", "containerd.io", "docker-compose-plugin",
445
+ ])
446
+
447
+
448
+ def _install_docker_centos():
449
+ info("正在安装 Docker (CentOS/RHEL)...")
450
+ _run_shell(["sudo", "yum", "install", "-y", "yum-utils"])
451
+ try:
452
+ _run_shell([
453
+ "sudo", "yum-config-manager", "--add-repo",
454
+ "https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo"
455
+ ])
456
+ except RuntimeError:
457
+ _run_shell([
458
+ "sudo", "yum-config-manager", "--add-repo",
459
+ "https://download.docker.com/linux/centos/docker-ce.repo"
460
+ ])
461
+ _run_shell([
462
+ "sudo", "yum", "install", "-y",
463
+ "docker-ce", "docker-ce-cli", "containerd.io", "docker-compose-plugin",
464
+ ])
465
+
466
+
467
+ def _install_docker_generic():
468
+ info("正在安装 Docker (通用脚本)...")
469
+ _run_shell(["sudo", "bash", "-c", "curl -fsSL https://get.docker.com | sh -s -- --mirror Aliyun"])
470
+
471
+
472
+ def _run_shell(cmd, check=True):
473
+ """执行 shell 命令(静默)"""
474
+ result = subprocess.run(cmd, capture_output=True, text=True)
475
+ if check and result.returncode != 0:
476
+ raise RuntimeError(f"命令执行失败: {' '.join(cmd)}\n{result.stderr}")
477
+ return result
478
+
479
+
480
+ # ============================================================
481
+ # Docker compose
482
+ # ============================================================
483
+
484
+ def compose_command():
485
+ """返回可用的 docker compose 命令"""
486
+ for cmd in [["docker", "compose"], ["docker-compose"]]:
487
+ try:
488
+ result = subprocess.run(
489
+ cmd + ["version"], capture_output=True, text=True, timeout=5
490
+ )
491
+ if result.returncode == 0:
492
+ return cmd
493
+ except (subprocess.SubprocessError, FileNotFoundError):
494
+ continue
495
+ return None
496
+
497
+
498
+ def run_cmd(cmd, check=True):
499
+ """执行 shell 命令(可见输出)"""
500
+ print(color("cyan", f"$ {' '.join(cmd)}"))
501
+ result = subprocess.run(cmd)
502
+ if check and result.returncode != 0:
503
+ raise RuntimeError(f"命令执行失败: {' '.join(cmd)}")
504
+ return result
505
+
506
+
507
+ # ============================================================
508
+ # Pull image with progress
509
+ # ============================================================
510
+
511
+ def pull_image():
512
+ """拉取镜像(带进度显示)"""
513
+ DISPLAY_NAME = "gogeo-agentos:latest"
514
+ info(f"正在拉取镜像: {DISPLAY_NAME}")
515
+ print()
516
+
517
+ process = subprocess.Popen(
518
+ ["docker", "pull", IMAGE_NAME],
519
+ stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
520
+ text=True, bufsize=1
521
+ )
522
+
523
+ layers = {}
524
+ dots = 0
525
+
526
+ for line in process.stdout:
527
+ line = line.strip()
528
+ if not line:
529
+ continue
530
+
531
+ if ":" in line and any(kw in line for kw in [
532
+ "Downloading", "Extracting", "Pulling fs layer", "Waiting",
533
+ "Verifying Checksum", "Download complete", "Pull complete", "Already exists"
534
+ ]):
535
+ parts = line.split(":", 1)
536
+ layer_id = parts[0].strip()
537
+ layers[layer_id] = parts[1].strip() if len(parts) > 1 else ""
538
+ elif line and not line.startswith("{"):
539
+ print(f" {line}")
540
+
541
+ dots += 1
542
+ if dots % 20 == 0:
543
+ _print_pull_progress(layers)
544
+
545
+ process.wait()
546
+ print()
547
+ _print_pull_progress(layers, final=True)
548
+
549
+ if process.returncode != 0:
550
+ error("镜像拉取失败")
551
+ sys.exit(1)
552
+
553
+ info("镜像拉取完成")
554
+ print()
555
+
556
+
557
+ def _print_pull_progress(layers, final=False):
558
+ """打印拉取进度"""
559
+ total = len(layers)
560
+ if total == 0:
561
+ return
562
+
563
+ completed = 0
564
+ for layer_id, status in layers.items():
565
+ if any(kw in status for kw in ["Pull complete", "Download complete", "Already exists"]):
566
+ completed += 1
567
+
568
+ bar_len = 30
569
+ filled = int(bar_len * completed / total)
570
+ bar = "█" * filled + "░" * (bar_len - filled)
571
+ sys.stdout.write(f"\r [{bar}] {completed}/{total} 层 ")
572
+ if final:
573
+ sys.stdout.write("\n")
574
+ sys.stdout.flush()
575
+
576
+
577
+ def ensure_image():
578
+ """确保镜像存在"""
579
+ result = subprocess.run(
580
+ ["docker", "image", "inspect", IMAGE_NAME],
581
+ capture_output=True, text=True
582
+ )
583
+ if result.returncode != 0:
584
+ pull_image()
585
+ else:
586
+ info("镜像已存在,跳过拉取")
587
+
588
+
589
+ # ============================================================
590
+ # Config
591
+ # ============================================================
592
+
593
+ def get_config_dir():
594
+ """获取配置目录"""
595
+ return Path.home() / ".agentos"
596
+
597
+
598
+ def get_compose_file():
599
+ return get_config_dir() / "docker-compose.yml"
600
+
601
+
602
+ def get_env_file():
603
+ return get_config_dir() / ".env"
604
+
605
+
606
+ def get_saved_key():
607
+ """获取 NUWAX_SAVED_KEY"""
608
+ key = os.environ.get("NUWAX_SAVED_KEY")
609
+ if key:
610
+ return key
611
+
612
+ env_file = get_env_file()
613
+ if env_file.exists():
614
+ for line in env_file.read_text().splitlines():
615
+ if line.startswith("NUWAX_SAVED_KEY="):
616
+ return line.split("=", 1)[1].strip()
617
+
618
+ return None
619
+
620
+
621
+ def save_saved_key(key):
622
+ """保存 key 到 .env"""
623
+ config_dir = get_config_dir()
624
+ config_dir.mkdir(parents=True, exist_ok=True)
625
+
626
+ env_file = get_env_file()
627
+ env_file.write_text(f"# AgentOS 配置\nNUWAX_SAVED_KEY={key}\n")
628
+ info(f"已保存 key 到 {env_file}")
629
+
630
+
631
+ # ============================================================
632
+ # Setup
633
+ # ============================================================
634
+
635
+ def setup(key=None, force=False):
636
+ """首次安装/设置"""
637
+ print()
638
+ print("=" * 50)
639
+ print(" AgentOS 安装")
640
+ print("=" * 50)
641
+ print()
642
+
643
+ check_docker()
644
+ configure_docker_mirrors()
645
+
646
+ compose = compose_command()
647
+ if not compose:
648
+ error("未找到 docker compose 或 docker-compose 命令")
649
+ sys.exit(1)
650
+
651
+ info(f"使用 compose 命令: {' '.join(compose)}")
652
+
653
+ ensure_image()
654
+
655
+ if key:
656
+ saved_key = key
657
+ else:
658
+ saved_key = get_saved_key()
659
+
660
+ if not saved_key:
661
+ saved_key = input(color("yellow", "[输入] 请输入 NUWAX_SAVED_KEY: ")).strip()
662
+ if not saved_key:
663
+ error("key 不能为空")
664
+ sys.exit(1)
665
+
666
+ save_saved_key(saved_key)
667
+
668
+ deploy_compose(saved_key, force)
669
+ copy_resources(force)
670
+
671
+ print()
672
+ info("安装完成!")
673
+ info(f"配置文件: {get_config_dir()}")
674
+ print()
675
+ print(" 后续使用命令:")
676
+ print(" agentos start 启动容器")
677
+ print(" agentos stop 停止容器")
678
+ print(" agentos restart 重启容器")
679
+ print(" agentos status 查看状态")
680
+ print()
681
+
682
+
683
+ def copy_resources(force=False):
684
+ """从包内复制资源文件到配置目录"""
685
+ config_dir = get_config_dir()
686
+
687
+ import gzip
688
+ import importlib.resources as pkg_resources
689
+
690
+ resource_files = [
691
+ ("app/app.asar", True), # True = gzip 压缩
692
+ ("desktop/gogeoclaw.desktop", False),
693
+ ("desktop/terminal.desktop", False),
694
+ ("desktop/vscode.desktop", False),
695
+ ("desktop/chromium.desktop", False),
696
+ ("icons/@nuwax-ainuwaclaw.png", False),
697
+ ("wallpaper/gogeoDesk.jpg", False),
698
+ ]
699
+
700
+ copied = 0
701
+ replaced = 0
702
+ for rel_path, is_gzipped in resource_files:
703
+ dest = config_dir / rel_path
704
+
705
+ try:
706
+ res = pkg_resources.files("agentos.resources") / rel_path
707
+ data = res.read_bytes()
708
+ if is_gzipped:
709
+ data = gzip.decompress(data)
710
+ except (FileNotFoundError, TypeError):
711
+ data = b""
712
+
713
+ if dest.exists() and not dest.is_dir():
714
+ if not force and dest.stat().st_size == len(data):
715
+ continue
716
+ if dest.stat().st_size < len(data):
717
+ replaced += 1
718
+
719
+ dest.parent.mkdir(parents=True, exist_ok=True)
720
+ dest.write_bytes(data)
721
+ copied += 1
722
+
723
+ if replaced > 0:
724
+ info(f"已更新 {replaced} 个过时的资源文件")
725
+ if copied > 0 and replaced == 0:
726
+ info(f"已复制 {copied} 个资源文件到配置目录")
727
+ elif copied == 0:
728
+ info("资源文件已是最新版本")
729
+
730
+
731
+ def deploy_compose(key, force=False):
732
+ """部署 docker-compose.yml"""
733
+ config_dir = get_config_dir()
734
+ config_dir.mkdir(parents=True, exist_ok=True)
735
+
736
+ compose_file = get_compose_file()
737
+
738
+ if compose_file.exists() and not force:
739
+ info(f"docker-compose.yml 已存在: {compose_file}")
740
+ return
741
+
742
+ content = f"""services:
743
+ agentos-client:
744
+ image: {IMAGE_NAME}
745
+ container_name: {CONTAINER_NAME}
746
+ restart: always
747
+ ports:
748
+ - "6080:6080"
749
+ volumes:
750
+ - agentos_home:/home/user
751
+ - ./desktop/gogeoclaw.desktop:/usr/share/applications/@nuwax-ainuwaclaw.desktop
752
+ - ./desktop/terminal.desktop:/usr/share/applications/user-terminal.desktop
753
+ - ./desktop/vscode.desktop:/usr/share/applications/user-vscode.desktop
754
+ - ./desktop/chromium.desktop:/usr/share/applications/chromium-browser.desktop
755
+ - ./icons/@nuwax-ainuwaclaw.png:/usr/share/icons/hicolor/512x512/apps/@nuwax-ainuwaclaw.png
756
+ - ./wallpaper/gogeoDesk.jpg:/usr/share/backgrounds/xfce/wallpaper.jpeg
757
+
758
+ environment:
759
+ - TZ=Asia/Shanghai
760
+ - NUWAX_SERVER_HOST=https://agentos.topprismdata.com/claw-api
761
+ - NUWAX_AGENT_PORT=60006
762
+ - NUWAX_FILE_SERVER_PORT=60005
763
+ - NUWAX_WORKSPACE_DIR=/home/user/nuwaxbot/workspace
764
+ - NUWAX_SAVED_KEY={key}
765
+
766
+ volumes:
767
+ agentos_home:
768
+ """
769
+
770
+ compose_file.write_text(content)
771
+ info(f"已生成 docker-compose.yml: {compose_file}")
772
+
773
+
774
+ # ============================================================
775
+ # Commands
776
+ # ============================================================
777
+
778
+ def cmd_start():
779
+ compose = compose_command()
780
+ if not compose:
781
+ error("未找到 docker compose")
782
+ sys.exit(1)
783
+
784
+ compose_file = get_compose_file()
785
+ if not compose_file.exists():
786
+ warn("未找到配置,请先运行: agentos setup")
787
+ sys.exit(1)
788
+
789
+ info("启动 AgentOS Client...")
790
+ run_cmd(compose + ["-f", str(compose_file), "up", "-d"])
791
+
792
+ print()
793
+ info("容器已启动")
794
+ print()
795
+ print(" 访问地址: http://localhost:6080")
796
+ print()
797
+
798
+
799
+ def cmd_stop():
800
+ compose = compose_command()
801
+ if not compose:
802
+ error("未找到 docker compose")
803
+ sys.exit(1)
804
+
805
+ compose_file = get_compose_file()
806
+ if not compose_file.exists():
807
+ warn("未找到配置")
808
+ sys.exit(1)
809
+
810
+ info("停止 AgentOS Client...")
811
+ run_cmd(compose + ["-f", str(compose_file), "down"])
812
+ info("容器已停止")
813
+
814
+
815
+ def cmd_restart():
816
+ cmd_stop()
817
+ print()
818
+ cmd_start()
819
+
820
+
821
+ def cmd_status():
822
+ result = subprocess.run(
823
+ ["docker", "ps", "-a", "--filter", f"name={CONTAINER_NAME}",
824
+ "--format", "table {{.Names}}\t{{.Status}}\t{{.Ports}}"],
825
+ capture_output=True, text=True
826
+ )
827
+ print(result.stdout)
828
+
829
+ if CONTAINER_NAME not in result.stdout:
830
+ warn("容器不存在,请先运行: agentos setup")
831
+
832
+
833
+ def cmd_logs():
834
+ result = subprocess.run(
835
+ ["docker", "logs", "--tail", "50", CONTAINER_NAME],
836
+ capture_output=True, text=True
837
+ )
838
+ print(result.stdout)
839
+ print(result.stderr)
840
+
841
+
842
+ def cmd_update_key(new_key):
843
+ """更新 key"""
844
+ save_saved_key(new_key)
845
+
846
+ compose_file = get_compose_file()
847
+ if compose_file.exists():
848
+ content = compose_file.read_text()
849
+ content = content.replace(
850
+ "NUWAX_SAVED_KEY=",
851
+ f"NUWAX_SAVED_KEY={new_key}"
852
+ )
853
+ compose_file.write_text(content)
854
+ info("已更新 docker-compose.yml 中的 key")
855
+
856
+ info("如需生效,请运行: agentos restart")
857
+
858
+
859
+ def cmd_redeploy():
860
+ """重新部署(删除旧配置重新生成)"""
861
+ compose_file = get_compose_file()
862
+ if compose_file.exists():
863
+ compose_file.unlink()
864
+ info("已删除旧配置")
865
+
866
+ key = get_saved_key()
867
+ if key:
868
+ setup(key=key, force=True)
869
+ else:
870
+ warn("未找到已保存的 key,请先运行: agentos setup")
871
+ sys.exit(1)
872
+
873
+
874
+ # ============================================================
875
+ # CLI
876
+ # ============================================================
877
+
878
+ def main():
879
+ parser = argparse.ArgumentParser(
880
+ prog="agentos",
881
+ description="AgentOS Client Docker 容器管理工具",
882
+ )
883
+ parser.add_argument(
884
+ "--version", action="version", version=f"agentos {VERSION}"
885
+ )
886
+
887
+ subparsers = parser.add_subparsers(dest="command", help="命令")
888
+
889
+ p_setup = subparsers.add_parser("setup", help="首次安装/设置")
890
+ p_setup.add_argument("--key", help="NUWAX_SAVED_KEY")
891
+ p_setup.add_argument("--force", action="store_true", help="强制重新生成配置")
892
+
893
+ subparsers.add_parser("start", help="启动容器")
894
+ subparsers.add_parser("stop", help="停止容器")
895
+ subparsers.add_parser("restart", help="重启容器")
896
+ subparsers.add_parser("status", help="查看容器状态")
897
+ subparsers.add_parser("logs", help="查看容器日志")
898
+
899
+ p_key = subparsers.add_parser("update-key", help="更新 NUWAX_SAVED_KEY")
900
+ p_key.add_argument("key", help="新的 key")
901
+
902
+ subparsers.add_parser("redeploy", help="重新部署(重新生成配置并重启)")
903
+
904
+ args = parser.parse_args()
905
+
906
+ if args.command == "setup":
907
+ setup(key=args.key, force=args.force)
908
+ elif args.command == "start":
909
+ cmd_start()
910
+ elif args.command == "stop":
911
+ cmd_stop()
912
+ elif args.command == "restart":
913
+ cmd_restart()
914
+ elif args.command == "status":
915
+ cmd_status()
916
+ elif args.command == "logs":
917
+ cmd_logs()
918
+ elif args.command == "update-key":
919
+ cmd_update_key(args.key)
920
+ elif args.command == "redeploy":
921
+ cmd_redeploy()
922
+ else:
923
+ parser.print_help()
924
+ sys.exit(1)
925
+
926
+
927
+ if __name__ == "__main__":
928
+ main()
@@ -0,0 +1,9 @@
1
+ [Desktop Entry]
2
+ Version=1.0
3
+ Type=Application
4
+ Name=Chromium
5
+ Comment=Web Browser
6
+ Exec=/usr/bin/chromium-browser-launcher
7
+ Icon=chromium
8
+ Terminal=false
9
+ Categories=Network;WebBrowser;
@@ -0,0 +1,10 @@
1
+ [Desktop Entry]
2
+ Version=1.0
3
+ Type=Application
4
+ Name=AgentOs
5
+ Comment=AgentOs Desktop Client (Electron)
6
+ Exec=/usr/local/bin/nuwax-agent %U
7
+ Icon=@nuwax-ainuwaclaw
8
+ Terminal=false
9
+ Categories=Productivity;
10
+ StartupWMClass=nuwaclaw
@@ -0,0 +1,9 @@
1
+ [Desktop Entry]
2
+ Version=1.0
3
+ Type=Application
4
+ Name=Terminal
5
+ Comment=Terminal Emulator
6
+ Exec=xfce4-terminal
7
+ Icon=utilities-terminal
8
+ Terminal=false
9
+ Categories=System;TerminalEmulator;
@@ -0,0 +1,9 @@
1
+ [Desktop Entry]
2
+ Version=1.0
3
+ Type=Application
4
+ Name=Visual Studio Code
5
+ Comment=Code Editor
6
+ Exec=/usr/bin/code --no-sandbox --user-data-dir=/home/user/.config/Code
7
+ Icon=vscode
8
+ Terminal=false
9
+ Categories=Development;IDE;
@@ -0,0 +1,98 @@
1
+ Metadata-Version: 2.4
2
+ Name: gogeo-client-agentos
3
+ Version: 0.2.2
4
+ Summary: AgentOS CLI tool for managing the AgentOS Client Docker container
5
+ Author-email: agentos-team <agentos@example.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/agentos/client
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Operating System :: OS Independent
10
+ Requires-Python: >=3.8
11
+ Description-Content-Type: text/markdown
12
+
13
+ # AgentOS Client
14
+
15
+ AgentOS Client Docker 容器管理 CLI 工具。
16
+
17
+ ## 安装
18
+
19
+ ```bash
20
+ pip install agentos
21
+ ```
22
+
23
+ ## 使用
24
+
25
+ ### 首次安装/设置
26
+
27
+ ```bash
28
+ # 方式一:直接设置(从环境变量或交互式输入读取 key)
29
+ agentos setup
30
+
31
+ # 方式二:命令行指定 key
32
+ agentos setup --key "your-nuwax-saved-key"
33
+
34
+ # 方式三:先设置环境变量
35
+ export NUWAX_SAVED_KEY="your-key"
36
+ agentos setup
37
+ ```
38
+
39
+ setup 流程:
40
+ 1. 检查 Docker 是否安装,未安装则自动安装(仅 Linux)
41
+ 2. 拉取 agentos-client 镜像
42
+ 3. 生成 docker-compose.yml 到 `~/.agentos/`
43
+ 4. 保存 key 到 `~/.agentos/.env`
44
+
45
+ ### 日常管理
46
+
47
+ ```bash
48
+ agentos start # 启动容器
49
+ agentos stop # 停止容器
50
+ agentos restart # 重启容器
51
+ agentos status # 查看容器状态
52
+ agentos logs # 查看最近 50 行日志
53
+ ```
54
+
55
+ ### 更新 key
56
+
57
+ ```bash
58
+ agentos update-key "new-key-here"
59
+ agentos restart # 重启生效
60
+ ```
61
+
62
+ ### 重新部署
63
+
64
+ ```bash
65
+ agentos redeploy # 删除旧配置,重新生成并重启
66
+ ```
67
+
68
+ ## 发布到 PyPI
69
+
70
+ ```bash
71
+ # 安装构建工具
72
+ pip install build twine
73
+
74
+ # 构建
75
+ cd gogeo-client
76
+ python -m build
77
+
78
+ # 发布到 TestPyPI(测试)
79
+ python -m twine upload --repository testpypi dist/*
80
+
81
+ # 发布到 PyPI(正式)
82
+ python -m twine upload dist/*
83
+ ```
84
+
85
+ ## 目录结构
86
+
87
+ ```
88
+ gogeo-client/
89
+ ├── pyproject.toml # Python 包配置
90
+ ├── agentos/
91
+ │ ├── __init__.py
92
+ │ └── cli.py # CLI 入口
93
+ ├── app/ # 应用覆盖文件
94
+ ├── desktop/ # 桌面快捷方式
95
+ ├── icons/ # 桌面图标
96
+ ├── wallpaper/ # 桌面壁纸
97
+ └── docker-compose.yml # 本地开发用 compose
98
+ ```
@@ -0,0 +1,21 @@
1
+ README.md
2
+ pyproject.toml
3
+ agentos/__init__.py
4
+ agentos/cli.py
5
+ agentos/resources/__init__.py
6
+ agentos/resources/app/__init__.py
7
+ agentos/resources/app/app.asar
8
+ agentos/resources/desktop/__init__.py
9
+ agentos/resources/desktop/chromium.desktop
10
+ agentos/resources/desktop/gogeoclaw.desktop
11
+ agentos/resources/desktop/terminal.desktop
12
+ agentos/resources/desktop/vscode.desktop
13
+ agentos/resources/icons/@nuwax-ainuwaclaw.png
14
+ agentos/resources/icons/__init__.py
15
+ agentos/resources/wallpaper/__init__.py
16
+ agentos/resources/wallpaper/gogeoDesk.jpg
17
+ gogeo_client_agentos.egg-info/PKG-INFO
18
+ gogeo_client_agentos.egg-info/SOURCES.txt
19
+ gogeo_client_agentos.egg-info/dependency_links.txt
20
+ gogeo_client_agentos.egg-info/entry_points.txt
21
+ gogeo_client_agentos.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ agentos = agentos.cli:main
@@ -0,0 +1,30 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "gogeo-client-agentos"
7
+ version = "0.2.2"
8
+ description = "AgentOS CLI tool for managing the AgentOS Client Docker container"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ requires-python = ">=3.8"
12
+ authors = [
13
+ {name = "agentos-team", email = "agentos@example.com"},
14
+ ]
15
+ classifiers = [
16
+ "Programming Language :: Python :: 3",
17
+ "Operating System :: OS Independent",
18
+ ]
19
+
20
+ [project.scripts]
21
+ agentos = "agentos.cli:main"
22
+
23
+ [project.urls]
24
+ "Homepage" = "https://github.com/agentos/client"
25
+
26
+ [tool.setuptools.packages.find]
27
+ include = ["agentos*"]
28
+
29
+ [tool.setuptools.package-data]
30
+ agentos = ["resources/**/*"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+