clu-ssh 0.1.0__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.
- clu_ssh-0.1.0/.github/workflows/ci.yml +24 -0
- clu_ssh-0.1.0/.gitignore +22 -0
- clu_ssh-0.1.0/CLAUDE.md +10 -0
- clu_ssh-0.1.0/DESIGN.md +245 -0
- clu_ssh-0.1.0/LICENSE +21 -0
- clu_ssh-0.1.0/PKG-INFO +106 -0
- clu_ssh-0.1.0/README.md +54 -0
- clu_ssh-0.1.0/docs/architecture.html +13947 -0
- clu_ssh-0.1.0/docs/usage.md +173 -0
- clu_ssh-0.1.0/pyproject.toml +81 -0
- clu_ssh-0.1.0/src/clu/__init__.py +3 -0
- clu_ssh-0.1.0/src/clu/__main__.py +5 -0
- clu_ssh-0.1.0/src/clu/cli.py +557 -0
- clu_ssh-0.1.0/src/clu/client.py +87 -0
- clu_ssh-0.1.0/src/clu/config/__init__.py +1 -0
- clu_ssh-0.1.0/src/clu/config/ssh_config.py +153 -0
- clu_ssh-0.1.0/src/clu/config/store.py +150 -0
- clu_ssh-0.1.0/src/clu/constants.py +73 -0
- clu_ssh-0.1.0/src/clu/daemon/__init__.py +1 -0
- clu_ssh-0.1.0/src/clu/daemon/__main__.py +10 -0
- clu_ssh-0.1.0/src/clu/daemon/lifecycle.py +24 -0
- clu_ssh-0.1.0/src/clu/daemon/rpc.py +425 -0
- clu_ssh-0.1.0/src/clu/daemon/server.py +212 -0
- clu_ssh-0.1.0/src/clu/ledger/__init__.py +1 -0
- clu_ssh-0.1.0/src/clu/ledger/db.py +85 -0
- clu_ssh-0.1.0/src/clu/ledger/query.py +65 -0
- clu_ssh-0.1.0/src/clu/mcp_server.py +233 -0
- clu_ssh-0.1.0/src/clu/policy.py +121 -0
- clu_ssh-0.1.0/src/clu/profiles.py +18 -0
- clu_ssh-0.1.0/src/clu/protocol.py +63 -0
- clu_ssh-0.1.0/src/clu/slurm/__init__.py +1 -0
- clu_ssh-0.1.0/src/clu/slurm/alloc.py +348 -0
- clu_ssh-0.1.0/src/clu/slurm/commands.py +451 -0
- clu_ssh-0.1.0/src/clu/ssh/__init__.py +1 -0
- clu_ssh-0.1.0/src/clu/ssh/connection.py +273 -0
- clu_ssh-0.1.0/src/clu/ssh/forward.py +83 -0
- clu_ssh-0.1.0/src/clu/ssh/pool.py +148 -0
- clu_ssh-0.1.0/src/clu/tmux.py +87 -0
- clu_ssh-0.1.0/src/clu/transfer/__init__.py +1 -0
- clu_ssh-0.1.0/src/clu/transfer/sftp.py +56 -0
- clu_ssh-0.1.0/tests/conftest.py +1 -0
- clu_ssh-0.1.0/tests/docker/Dockerfile +8 -0
- clu_ssh-0.1.0/tests/docker/entrypoint.sh +10 -0
- clu_ssh-0.1.0/tests/docker/slurm/salloc +16 -0
- clu_ssh-0.1.0/tests/docker/slurm/sbatch +9 -0
- clu_ssh-0.1.0/tests/docker/slurm/scancel +2 -0
- clu_ssh-0.1.0/tests/docker/slurm/scontrol +10 -0
- clu_ssh-0.1.0/tests/docker/slurm/sinfo +4 -0
- clu_ssh-0.1.0/tests/docker/slurm/squeue +15 -0
- clu_ssh-0.1.0/tests/docker/slurm/srun +9 -0
- clu_ssh-0.1.0/tests/integration/conftest.py +155 -0
- clu_ssh-0.1.0/tests/integration/test_daemon_e2e.py +61 -0
- clu_ssh-0.1.0/tests/integration/test_m2_slurm.py +110 -0
- clu_ssh-0.1.0/tests/integration/test_m3_alloc.py +108 -0
- clu_ssh-0.1.0/tests/integration/test_m4_transfer.py +97 -0
- clu_ssh-0.1.0/tests/integration/test_mcp_e2e.py +97 -0
- clu_ssh-0.1.0/tests/integration/test_pool_integration.py +111 -0
- clu_ssh-0.1.0/tests/unit/test_cli.py +66 -0
- clu_ssh-0.1.0/tests/unit/test_cli_connection.py +86 -0
- clu_ssh-0.1.0/tests/unit/test_config_store.py +85 -0
- clu_ssh-0.1.0/tests/unit/test_forward_manager.py +52 -0
- clu_ssh-0.1.0/tests/unit/test_ledger_db.py +27 -0
- clu_ssh-0.1.0/tests/unit/test_ledger_query.py +39 -0
- clu_ssh-0.1.0/tests/unit/test_package.py +26 -0
- clu_ssh-0.1.0/tests/unit/test_policy.py +90 -0
- clu_ssh-0.1.0/tests/unit/test_pool.py +155 -0
- clu_ssh-0.1.0/tests/unit/test_protocol.py +48 -0
- clu_ssh-0.1.0/tests/unit/test_resources.py +96 -0
- clu_ssh-0.1.0/tests/unit/test_rpc_exec.py +79 -0
- clu_ssh-0.1.0/tests/unit/test_slurm_commands.py +83 -0
- clu_ssh-0.1.0/tests/unit/test_ssh_config.py +81 -0
- clu_ssh-0.1.0/tests/unit/test_tmux_alloc.py +146 -0
- clu_ssh-0.1.0/uv.lock +1265 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main, master]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
check:
|
|
10
|
+
strategy:
|
|
11
|
+
fail-fast: false
|
|
12
|
+
matrix:
|
|
13
|
+
os: [ubuntu-latest, macos-latest]
|
|
14
|
+
runs-on: ${{ matrix.os }}
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
- uses: astral-sh/setup-uv@v5
|
|
18
|
+
with:
|
|
19
|
+
enable-cache: true
|
|
20
|
+
- run: uv sync
|
|
21
|
+
- run: uv run ruff format --check .
|
|
22
|
+
- run: uv run ruff check .
|
|
23
|
+
- run: uv run mypy
|
|
24
|
+
- run: uv run pytest
|
clu_ssh-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
dist/
|
|
6
|
+
build/
|
|
7
|
+
|
|
8
|
+
# uv / venv
|
|
9
|
+
.venv/
|
|
10
|
+
|
|
11
|
+
# tools caches
|
|
12
|
+
.pytest_cache/
|
|
13
|
+
.mypy_cache/
|
|
14
|
+
.ruff_cache/
|
|
15
|
+
|
|
16
|
+
# local only
|
|
17
|
+
.env
|
|
18
|
+
*.sqlite3
|
|
19
|
+
*.sqlite3-journal
|
|
20
|
+
|
|
21
|
+
# archify 工作区(回执与捕获,可由 candidate.json 再生)
|
|
22
|
+
.archify/
|
clu_ssh-0.1.0/CLAUDE.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# clu 开发约定
|
|
2
|
+
|
|
3
|
+
- 一切设计以 DESIGN.md 为准;改设计先改文档(§13 决策记录表追加一行),再写代码。
|
|
4
|
+
- 模块 docstring 标注所属里程碑(M1–M4),不提前实现后续里程碑内容。
|
|
5
|
+
- uv 管理环境。提交前四件套全绿:
|
|
6
|
+
`uv run ruff format --check .` → `uv run ruff check .` → `uv run mypy` → `uv run pytest`
|
|
7
|
+
- mypy strict;ruff(E,F,W,I,UP,B,C4,SIM,RUF);conventional commits。
|
|
8
|
+
- 测试三层:unit(纯逻辑)、integration(M1 起,Docker sshd 容器 + 假 slurm)、
|
|
9
|
+
验收(真实集群 3 天日用,手动)。
|
|
10
|
+
- 文档/面向用户文案用中文;代码标识符用英文。
|
clu_ssh-0.1.0/DESIGN.md
ADDED
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
# clu 设计文档
|
|
2
|
+
|
|
3
|
+
> 共识来源:2026-10-19 设计评审(grilling)会话。本文档是唯一权威设计来源;
|
|
4
|
+
> 改设计先改本文档并在 §13 决策记录表追加一行,再写代码。
|
|
5
|
+
|
|
6
|
+
## 1. 定位与设计原则
|
|
7
|
+
|
|
8
|
+
面向高校师生的**单用户**开源工具,两层价值合一:
|
|
9
|
+
|
|
10
|
+
1. **AI 能力层**:Claude Code(MCP)为第一消费方;其他 agent 未来经 MCP 接入
|
|
11
|
+
2. **SSH 会话管理层**:人类经 `clu` CLI 直接使用同一套连接池与托管会话
|
|
12
|
+
|
|
13
|
+
不自建 agent 循环、不做事务/计划模型——那是 agent 层(Claude Code)的事。
|
|
14
|
+
本项目只做被所有消费方共享的**能力层**。
|
|
15
|
+
|
|
16
|
+
前作教训(connector v1/v2、slurm-bot-executor-redesign、Rust slurm-client 脚手架):
|
|
17
|
+
设计过度、工程实现不规范,均未达到日用状态。对策:
|
|
18
|
+
|
|
19
|
+
- **能力层保持薄**:留痕是执行副产物,不预建模;不重建审批流
|
|
20
|
+
- **工程规范保持硬**:mypy strict、ruff、pytest 全绿才合并;容器化集成测试
|
|
21
|
+
|
|
22
|
+
## 2. 命名与发行
|
|
23
|
+
|
|
24
|
+
| 项 | 值 | 备注 |
|
|
25
|
+
|---|---|---|
|
|
26
|
+
| PyPI 包名 | `clu-ssh` | 已核查可用(`clu`、`clu-cli`、`clink` 被占用) |
|
|
27
|
+
| CLI 命令 | `clu` | `clu status` / `clu attach` |
|
|
28
|
+
| 配置目录 | `~/.config/clu/` | 遵循 XDG |
|
|
29
|
+
| 数据目录 | `~/.local/share/clu/` | 留痕 SQLite |
|
|
30
|
+
| 运行时目录 | `$XDG_RUNTIME_DIR/clu/` | unix socket |
|
|
31
|
+
| License | MIT | |
|
|
32
|
+
|
|
33
|
+
发行:`uv tool install clu-ssh`。平台 v1 仅 macOS + Linux;Windows 进路线图。
|
|
34
|
+
|
|
35
|
+
## 3. 总体架构
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
┌─────────────┐ ┌──────────┐
|
|
39
|
+
│ Claude Code │ │ 人类 │
|
|
40
|
+
│ (MCP stdio) │ │ │
|
|
41
|
+
└──────┬──────┘ └────┬─────┘
|
|
42
|
+
│ MCP │ CLI(clu)
|
|
43
|
+
┌──────▼────────────────────▼──────┐
|
|
44
|
+
│ mcp_server.py cli.py │ 薄客户端(无常驻状态)
|
|
45
|
+
└───────────────┬─────────────────┘
|
|
46
|
+
│ unix socket(JSON 消息,见 src/clu/protocol.py)
|
|
47
|
+
┌───────────────▼─────────────────┐
|
|
48
|
+
│ clu daemon │
|
|
49
|
+
│ ┌──────────┐ ┌──────┐ ┌─────┐ │
|
|
50
|
+
│ │ SSH 连接池│ │ tmux │ │policy│ │
|
|
51
|
+
│ └────┬─────┘ └──┬───┘ └──▲──┘ │
|
|
52
|
+
│ ┌────▼─────┐ ┌──▼──────┐ │ │
|
|
53
|
+
│ │ ledger │ │ slurm │──┘ │
|
|
54
|
+
│ │ (sqlite) │ │ commands│ │
|
|
55
|
+
│ └──────────┘ └─────────┘ │
|
|
56
|
+
└────────┬───────────────┬─────────┘
|
|
57
|
+
│ asyncssh │ ssh(tmux/命令通道)
|
|
58
|
+
▼ ▼
|
|
59
|
+
集群 / 服务器(贵大 HPC、aliyun、4090、WSL……)
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
进程模型:
|
|
63
|
+
|
|
64
|
+
- **daemon**:唯一常驻进程,持有连接池、tmux 会话句柄、SQLite 留痕。
|
|
65
|
+
缺席时由任一客户端自动拉起(`clu server ensure` 模式)
|
|
66
|
+
- **MCP server**:Claude Code 经 stdio 启动的短生命周期进程,只做协议转换
|
|
67
|
+
- **CLI**:一次性进程,经 unix socket 调 daemon
|
|
68
|
+
|
|
69
|
+
MCP stdio 进程随时会被 Claude Code 杀掉,因此一切状态必须归 daemon。
|
|
70
|
+
|
|
71
|
+
## 4. 连接与配置管理
|
|
72
|
+
|
|
73
|
+
`~/.config/clu/connections.toml`(tomlkit 读写,保留用户注释):
|
|
74
|
+
|
|
75
|
+
```toml
|
|
76
|
+
[connections.gzu]
|
|
77
|
+
kind = "cluster" # cluster | instance | local
|
|
78
|
+
host = "hpc.example.edu.cn"
|
|
79
|
+
port = 22
|
|
80
|
+
user = "you"
|
|
81
|
+
proxy = "gzu-relay" # 可选:单级跳板,值为另一连接的 label
|
|
82
|
+
profile = "gzu" # 可选:定制 profile
|
|
83
|
+
|
|
84
|
+
[profiles.gzu]
|
|
85
|
+
public_dirs = ["/public/home", "/public/soft"]
|
|
86
|
+
heavy_guard = true # 登录节点重操作拦截(默认全局开启,profile 可加名单)
|
|
87
|
+
preempt_partition = "..." # 抢占模式使用的分区
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
- **导入语义**:`clu connection import` 从 `~/.ssh/config` **一次性导入副本**,
|
|
91
|
+
不持续跟踪源文件变化;**仅导入公钥认证可达的条目**;解析 `HostName/Port/
|
|
92
|
+
User/ProxyJump`;跳板引用不存在的条目时导入告警
|
|
93
|
+
- **认证**:仅公钥;复用 ssh-agent 与 `~/.ssh` 中的 key 路径,不自建凭据库
|
|
94
|
+
- **kind 语义**:`cluster`(Slurm 集群,启用 slurm 工具面)/ `instance`
|
|
95
|
+
(租用 GPU 机等普通服务器)/ `local`(局域网/本机转发目标)
|
|
96
|
+
- **profile**:一切学校/集群定制(公共资源目录、重操作名单、抢占分区)进
|
|
97
|
+
profile 配置,代码零硬编码;仓库内置贵大 profile 作为示例
|
|
98
|
+
|
|
99
|
+
## 5. SSH 能力层
|
|
100
|
+
|
|
101
|
+
### 5.1 连接池(M1)
|
|
102
|
+
|
|
103
|
+
- 按 label 管理长连 asyncssh 连接;懒建立,首次使用时连
|
|
104
|
+
- 心跳:asyncssh keepalive,间隔 30s(可配)
|
|
105
|
+
- 断线:自动重连,指数退避 1s → 上限 30s;重连期间请求排队或快速失败(M1 定)
|
|
106
|
+
- 单级跳板:经 `proxy` 指向的连接建立 tunnel(asyncssh 原生);多级链进路线图
|
|
107
|
+
- 通道:命令执行、SFTP、tmux 控制共用同一连接,每连接通道数上限(默认 10,可配)
|
|
108
|
+
|
|
109
|
+
### 5.2 tmux 编排保活(M3)
|
|
110
|
+
|
|
111
|
+
- 所有交互式资源(salloc)与长任务在远端 tmux 会话内运行,
|
|
112
|
+
命名规范 `clu/<connection_label>/<purpose>`
|
|
113
|
+
- daemon 持有"tmux 会话 → 意图/关联 job/资源"映射表(重启后可从 tmux 列表恢复)
|
|
114
|
+
- `clu attach <label>/<purpose>` 人类直接接入
|
|
115
|
+
- saloc 获得分配后 `sleep infinity` 占住资源(继承旧 skill 抢占语义)
|
|
116
|
+
|
|
117
|
+
### 5.3 端口转发(M4,最小集)
|
|
118
|
+
|
|
119
|
+
- 本地转发(`-L` 等价):`clu forward add/list/remove`,经连接池连接建立
|
|
120
|
+
- 动态转发(SOCKS)与远程转发(`-R`)进路线图
|
|
121
|
+
|
|
122
|
+
## 6. MCP 工具面(M2)
|
|
123
|
+
|
|
124
|
+
专用结构化工具优先,泛用 `exec` 兜底。全部经 daemon 执行并写留痕。
|
|
125
|
+
|
|
126
|
+
| 工具 | 关键参数 | 输出 | 里程碑 |
|
|
127
|
+
|---|---|---|---|
|
|
128
|
+
| `exec` | connection, cmd, timeout | stdout/stderr/exit_code/时长 | M2 |
|
|
129
|
+
| `jobs` | connection, state? | 结构化作业列表(squeue) | M2 |
|
|
130
|
+
| `status` | connection | 分区/节点/GPU 概览(sinfo+squeue 合并单次往返) | M2 |
|
|
131
|
+
| `resources` | connection, partition?, filter?, gpu_only?, include_nodes? | 节点级+分区级 CPU/GPU 余量,单次往返。已占取节点 AllocTRES(gres/gpu 总量为准,typed 归属型号;老集群退回 squeue %b 估算并注明)。filter=cpu_free / cpu_gpu_free / fully_idle,gpu_only 可叠加;默认紧凑视图,过滤或 include_nodes 才带节点明细(验收期新增,替代 agent 自拼 sinfo/scontrol) | v1 |
|
|
132
|
+
| `submit` | connection, script(文本或远端路径) | job_id | M2 |
|
|
133
|
+
| `log` | connection, job_id, tail? | 日志文本 | M2 |
|
|
134
|
+
| `cancel` | connection, job_id | 结果 | M2 |
|
|
135
|
+
| `ledger_query` | 时间范围/连接/关键词/job_id 过滤 | 留痕记录列表(结构化过滤,不暴露裸 SQL) | M2 |
|
|
136
|
+
| `alloc` | connection, purpose?, resource?, gpus=1, cpus?, partition?, wait? | 抢占接口(自动选择,无需先查询):resource 缺省 GPU 优先、无则回退 CPU;gpu/cpu 只抢该类;partition 显式则直用。分区按单节点可满足度排名、瞬死自动轮换候选(忙分区竞态)。分配后 srun bash 落计算节点 | v1 |
|
|
137
|
+
| `session_list` / `session_info` | connection? | tmux 托管会话列表/详情 | M3 |
|
|
138
|
+
| `upload` / `download` | connection, local_path, remote_path | 传输结果 | M4 |
|
|
139
|
+
| `connection_list` | — | 连接与池状态(含 health) | M2 |
|
|
140
|
+
|
|
141
|
+
**alloc 语义(继承旧 skill,不可削弱)**:
|
|
142
|
+
|
|
143
|
+
- 申请资源必须**直接执行**,禁止只返回 salloc 命令让用户手动跑;
|
|
144
|
+
仅当用户明确说"先看命令"时才返回命令文本
|
|
145
|
+
- "抢占 A100"等表述 → `preempt=true`:分区默认取 profile.preempt_partition;tmux 内 `salloc --gres=gpu:N ... srun bash`——attach 即计算节点 shell,exit 即释放(`--gres` 经典语法与 `srun` 落点均为贵大真机实测结论)
|
|
146
|
+
- 只读工具(jobs/status/log/ledger_query/connection_list)与写工具在 MCP 层
|
|
147
|
+
分开声明,便于 Claude Code 权限配置只读免确认
|
|
148
|
+
|
|
149
|
+
## 7. 留痕(SQLite 最小集)
|
|
150
|
+
|
|
151
|
+
执行的自然副产物,单表起步:
|
|
152
|
+
|
|
153
|
+
```sql
|
|
154
|
+
CREATE TABLE exec_records (
|
|
155
|
+
id INTEGER PRIMARY KEY,
|
|
156
|
+
ts TEXT NOT NULL, -- UTC ISO8601
|
|
157
|
+
connection TEXT NOT NULL, -- 连接 label
|
|
158
|
+
kind TEXT NOT NULL, -- exec | submit | alloc | cancel | upload | download | forward
|
|
159
|
+
command TEXT NOT NULL,
|
|
160
|
+
exit_code INTEGER,
|
|
161
|
+
duration_ms INTEGER,
|
|
162
|
+
job_id TEXT, -- 可空:关联 slurm 作业
|
|
163
|
+
summary TEXT -- 可空:一行摘要,供检索
|
|
164
|
+
);
|
|
165
|
+
CREATE INDEX idx_exec_ts ON exec_records(ts);
|
|
166
|
+
CREATE INDEX idx_exec_conn ON exec_records(connection);
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
不做事务/计划模型。检索 = `ledger_query` 结构化过滤。
|
|
170
|
+
|
|
171
|
+
## 8. 安全模型(双层)
|
|
172
|
+
|
|
173
|
+
**第一层:Claude Code 工具权限**(主)。只读/写工具分开声明,用户在 Claude
|
|
174
|
+
Code 侧配置免确认白名单。
|
|
175
|
+
|
|
176
|
+
**第二层:server 端硬规则**(极薄,仅两条):
|
|
177
|
+
|
|
178
|
+
1. **登录节点重操作拦截**:在 `kind=cluster` 的登录节点上命中重操作模式 →
|
|
179
|
+
拒绝并建议 alloc/submit。初始名单(profile 可增):
|
|
180
|
+
`torchrun`、`deepspeed`、`accelerate launch`、`python -m torch.distributed`、
|
|
181
|
+
`make -j`、`cmake --build`、`conda create/install`、`pip install`(大包场景)
|
|
182
|
+
2. **危险模式黑名单**(无条件拒绝):递归删除根/家目录的 `rm -rf`、`mkfs`、
|
|
183
|
+
`dd of=/dev/*`、`shutdown/reboot`、`scancel --all`、fork 炸弹、
|
|
184
|
+
`chmod -R 777 /`
|
|
185
|
+
|
|
186
|
+
不重建审批流;其余信任第一层。
|
|
187
|
+
|
|
188
|
+
## 9. 文件传输
|
|
189
|
+
|
|
190
|
+
- **M4:SFTP**——走连接池内连接,单文件与少量文件;`upload/download` 记留痕
|
|
191
|
+
- **v1.1:系统 rsync**——目录增量同步,spawn rsync 子进程(用系统 ssh,绕开
|
|
192
|
+
连接池但传输仍记留痕)
|
|
193
|
+
- "先查公共资源目录再下载"等学校规则进 profile 提示,不进传输层
|
|
194
|
+
|
|
195
|
+
## 10. 测试策略
|
|
196
|
+
|
|
197
|
+
三层,**不依赖真实集群**:
|
|
198
|
+
|
|
199
|
+
1. **单元测试**:连接池状态机、重连退避、策略门匹配、配置读写——纯逻辑,
|
|
200
|
+
快速全量跑
|
|
201
|
+
2. **集成测试**:**Docker 容器当集群/服务器**——sshd 容器(注入测试 key)+
|
|
202
|
+
容器内假 slurm CLI(脚本输出固定 squeue/sacct/sinfo JSON)。不碰物理机、
|
|
203
|
+
不碰真集群,开源贡献者本地与 CI 都能跑
|
|
204
|
+
3. **验收测试**:3 天真实日用(见 §12),手动执行
|
|
205
|
+
|
|
206
|
+
## 11. 工程规范
|
|
207
|
+
|
|
208
|
+
- uv 管理环境与依赖;Python ≥ 3.11
|
|
209
|
+
- ruff(E,F,W,I,UP,B,C4,SIM,RUF)+ ruff format
|
|
210
|
+
- mypy **strict**
|
|
211
|
+
- pytest + pytest-asyncio;CI = GitHub Actions,macOS + Linux 矩阵
|
|
212
|
+
- conventional commits
|
|
213
|
+
- 提交前四件套全绿:`ruff format --check` → `ruff check` → `mypy` → `pytest`
|
|
214
|
+
- 模块 docstring 标注所属里程碑(M1–M4);不提前实现后续里程碑内容
|
|
215
|
+
|
|
216
|
+
## 12. 里程碑与验收
|
|
217
|
+
|
|
218
|
+
| 里程碑 | 内容 | 完成定义 |
|
|
219
|
+
|---|---|---|
|
|
220
|
+
| M0 | 骨架 + 本文档 | 目录/工具链/CI 就位,四件套全绿,CLI `--help` 可用 |
|
|
221
|
+
| M1 | daemon + 连接池 | socket 通信、ensure 拉起、ssh config 导入、心跳重连、单级跳板;容器集成测试覆盖连接建立/断线重连 |
|
|
222
|
+
| M2 | MCP 工具面 + 安全门 | Claude Code 经 MCP 完成 exec/jobs/status/submit/log/cancel + ledger_query;两条硬规则生效 |
|
|
223
|
+
| M3 | alloc + tmux 保活 | 抢卡→alloc 直接执行→tmux 保活→`clu attach` 全链路 |
|
|
224
|
+
| M4 | SFTP + 转发管理 | 上传/下载可用;`-L` 按需管理 |
|
|
225
|
+
| **验收** | **3 天日用** | 连续 3 天,贵大集群全部日常操作(查卡/提交/看日志/抢卡/传文件)100% 经 Claude Code 或 `clu`,零手打 ssh |
|
|
226
|
+
|
|
227
|
+
**v1.1 路线图**:系统 rsync 同步、多级跳板链、SOCKS/远程转发、Windows 支持。
|
|
228
|
+
|
|
229
|
+
## 13. 决策记录
|
|
230
|
+
|
|
231
|
+
| 日期 | 决策 | 理由 |
|
|
232
|
+
|---|---|---|
|
|
233
|
+
| 2026-10-19 | 双栖能力层(MCP+CLI),不自建 agent 循环 | 与 Claude Code 重复造轮子;MCP 天然服务其他 agent |
|
|
234
|
+
| 2026-10-19 | Python + asyncssh,弃 Rust/包装系统 ssh | 最快到达日用;ControlMaster 与保活需求冲突 |
|
|
235
|
+
| 2026-10-19 | daemon + 薄客户端(unix socket,ensure 拉起) | MCP stdio 进程随时被杀,状态必须归 daemon |
|
|
236
|
+
| 2026-10-19 | 连接配置独立 toml + ssh config 一次性导入(含 ProxyJump、仅公钥) | 可管理、可预测;高校密码场景引导配 key |
|
|
237
|
+
| 2026-10-19 | SQLite 最小留痕,不做事务模型 | 留痕是副产物;事务归 agent 层 |
|
|
238
|
+
| 2026-10-19 | 安全双层:Claude Code 权限为主 + server 两条硬规则 | 不重建审批流;真踩过的坑用硬规则兜底 |
|
|
239
|
+
| 2026-10-19 | tmux 编排保活,弃 mosh/ET | 集群无 root 装不了;托管资源会话才是痛点 |
|
|
240
|
+
| 2026-10-19 | SFTP 先行,rsync v1.1 | 先跑起来;SFTP 覆盖 80% 场景 |
|
|
241
|
+
| 2026-10-19 | 单级跳板进 v1,多级链路线图 | asyncssh 原生支持成本低;导入即全可用 |
|
|
242
|
+
| 2026-10-19 | macOS + Linux 优先 | HPC 用户工作机以 Mac/Linux 为主 |
|
|
243
|
+
| 2026-10-19 | 集成测试用容器,不用进程内假服务器/物理机 | 环境更真实;贡献者无真集群也能跑 |
|
|
244
|
+
| 2026-10-20 | alloc 升级为专门抢占接口:默认 GPU 优先回退 CPU、resource/gpus/cpus/partition 可指定;用户侧命令形式保持 --gpus 简洁语法,集群方言由 clu 内部转换 | 用户裁决;贵大真机实测(--gres 插件强制、忙分区竞态需故障转移) |
|
|
245
|
+
| 2026-10-19 | 包名 clu-ssh(clu 被占用) | PyPI 已核查 |
|
clu_ssh-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Qianding Huang
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
clu_ssh-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: clu-ssh
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: AI 能力层 + SSH 会话管理:经 MCP/CLI 连接 Slurm 集群与普通服务器
|
|
5
|
+
Project-URL: Homepage, https://github.com/QiandingHuang666/clu-ssh
|
|
6
|
+
Project-URL: Repository, https://github.com/QiandingHuang666/clu-ssh
|
|
7
|
+
Project-URL: Issues, https://github.com/QiandingHuang666/clu-ssh/issues
|
|
8
|
+
Author: Qianding Huang
|
|
9
|
+
License: MIT License
|
|
10
|
+
|
|
11
|
+
Copyright (c) 2026 Qianding Huang
|
|
12
|
+
|
|
13
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
14
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
15
|
+
in the Software without restriction, including without limitation the rights
|
|
16
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
17
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
18
|
+
furnished to do so, subject to the following conditions:
|
|
19
|
+
|
|
20
|
+
The above copyright notice and this permission notice shall be included in all
|
|
21
|
+
copies or substantial portions of the Software.
|
|
22
|
+
|
|
23
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
24
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
25
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
26
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
27
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
28
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
29
|
+
SOFTWARE.
|
|
30
|
+
License-File: LICENSE
|
|
31
|
+
Keywords: agent,hpc,mcp,slurm,ssh
|
|
32
|
+
Classifier: Development Status :: 4 - Beta
|
|
33
|
+
Classifier: Environment :: Console
|
|
34
|
+
Classifier: Intended Audience :: Science/Research
|
|
35
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
36
|
+
Classifier: Operating System :: MacOS
|
|
37
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
38
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
39
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
40
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
41
|
+
Classifier: Topic :: Scientific/Engineering
|
|
42
|
+
Classifier: Topic :: System :: Clustering
|
|
43
|
+
Requires-Python: >=3.11
|
|
44
|
+
Requires-Dist: aiosqlite>=0.20
|
|
45
|
+
Requires-Dist: asyncssh>=2.17
|
|
46
|
+
Requires-Dist: mcp>=1.2
|
|
47
|
+
Requires-Dist: pydantic>=2.7
|
|
48
|
+
Requires-Dist: rich>=13.7
|
|
49
|
+
Requires-Dist: tomlkit>=0.13
|
|
50
|
+
Requires-Dist: typer>=0.12
|
|
51
|
+
Description-Content-Type: text/markdown
|
|
52
|
+
|
|
53
|
+
# clu
|
|
54
|
+
|
|
55
|
+
SSH 会话保持与管理 + Slurm 集群 / 普通服务器的 AI agent 能力层。
|
|
56
|
+
|
|
57
|
+
一个常驻 daemon 持有 SSH 连接池、tmux 托管会话与执行留痕;Claude Code(MCP)
|
|
58
|
+
与人类(`clu` CLI)作为两个薄客户端共享同一套能力。
|
|
59
|
+
|
|
60
|
+
> 状态:M0 骨架阶段,尚未发布。设计共识与里程碑见 [DESIGN.md](DESIGN.md)。
|
|
61
|
+
|
|
62
|
+
总体架构图(交互式,明暗主题):[docs/architecture.html](docs/architecture.html)
|
|
63
|
+
使用说明:[docs/usage.md](docs/usage.md)
|
|
64
|
+
|
|
65
|
+
## 安装(计划)
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
uv tool install clu-ssh
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## 接入 Claude Code(MCP)
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
# 项目级(推荐,随仓库共享)
|
|
75
|
+
claude mcp add clu -- clu-mcp
|
|
76
|
+
|
|
77
|
+
# 或用户级
|
|
78
|
+
claude mcp add --scope user clu -- clu-mcp
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
工具面(只读工具带 read-only hint,可配置免确认):
|
|
82
|
+
|
|
83
|
+
| 工具 | 说明 |
|
|
84
|
+
|---|---|
|
|
85
|
+
| `exec` | 远程执行单条命令(受安全门约束) |
|
|
86
|
+
| `jobs` / `status` / `log` | 作业列表 / 集群概览 / 作业日志(只读) |
|
|
87
|
+
| `submit` / `cancel` | 提交 / 取消作业 |
|
|
88
|
+
| `ledger_query` | 检索执行留痕(跨会话记忆,只读) |
|
|
89
|
+
| `connection_list` | 连接与连接池状态(只读) |
|
|
90
|
+
|
|
91
|
+
## 开发
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
uv sync # 安装依赖(含 dev 组)
|
|
95
|
+
uv run clu --help # CLI
|
|
96
|
+
uv run pytest # 单元测试
|
|
97
|
+
uv run ruff format . # 格式化
|
|
98
|
+
uv run ruff check . # 静态检查
|
|
99
|
+
uv run mypy # 类型检查(strict)
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
CI(GitHub Actions)在 macOS 与 Linux 矩阵上运行同一套检查。
|
|
103
|
+
|
|
104
|
+
## License
|
|
105
|
+
|
|
106
|
+
MIT
|
clu_ssh-0.1.0/README.md
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# clu
|
|
2
|
+
|
|
3
|
+
SSH 会话保持与管理 + Slurm 集群 / 普通服务器的 AI agent 能力层。
|
|
4
|
+
|
|
5
|
+
一个常驻 daemon 持有 SSH 连接池、tmux 托管会话与执行留痕;Claude Code(MCP)
|
|
6
|
+
与人类(`clu` CLI)作为两个薄客户端共享同一套能力。
|
|
7
|
+
|
|
8
|
+
> 状态:M0 骨架阶段,尚未发布。设计共识与里程碑见 [DESIGN.md](DESIGN.md)。
|
|
9
|
+
|
|
10
|
+
总体架构图(交互式,明暗主题):[docs/architecture.html](docs/architecture.html)
|
|
11
|
+
使用说明:[docs/usage.md](docs/usage.md)
|
|
12
|
+
|
|
13
|
+
## 安装(计划)
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
uv tool install clu-ssh
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## 接入 Claude Code(MCP)
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# 项目级(推荐,随仓库共享)
|
|
23
|
+
claude mcp add clu -- clu-mcp
|
|
24
|
+
|
|
25
|
+
# 或用户级
|
|
26
|
+
claude mcp add --scope user clu -- clu-mcp
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
工具面(只读工具带 read-only hint,可配置免确认):
|
|
30
|
+
|
|
31
|
+
| 工具 | 说明 |
|
|
32
|
+
|---|---|
|
|
33
|
+
| `exec` | 远程执行单条命令(受安全门约束) |
|
|
34
|
+
| `jobs` / `status` / `log` | 作业列表 / 集群概览 / 作业日志(只读) |
|
|
35
|
+
| `submit` / `cancel` | 提交 / 取消作业 |
|
|
36
|
+
| `ledger_query` | 检索执行留痕(跨会话记忆,只读) |
|
|
37
|
+
| `connection_list` | 连接与连接池状态(只读) |
|
|
38
|
+
|
|
39
|
+
## 开发
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
uv sync # 安装依赖(含 dev 组)
|
|
43
|
+
uv run clu --help # CLI
|
|
44
|
+
uv run pytest # 单元测试
|
|
45
|
+
uv run ruff format . # 格式化
|
|
46
|
+
uv run ruff check . # 静态检查
|
|
47
|
+
uv run mypy # 类型检查(strict)
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
CI(GitHub Actions)在 macOS 与 Linux 矩阵上运行同一套检查。
|
|
51
|
+
|
|
52
|
+
## License
|
|
53
|
+
|
|
54
|
+
MIT
|