Metadata-Version: 2.4
Name: msdev
Version: 0.12.0
Summary: Portable nodes and execution environments for msModelSlim development
Author: msModelSlim Agent Contributors
License-Expression: MulanPSL-2.0
Project-URL: Homepage, https://gitcode.com/rookie_hongchuan/msdev
Project-URL: Repository, https://gitcode.com/rookie_hongchuan/msdev
Keywords: ssh,docker,conda,venv,remote,npu,mlops,devops
Classifier: Environment :: Console
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Operating System :: MacOS
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: POSIX :: Linux
Classifier: Topic :: Software Development :: Build Tools
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# msdev

`msdev` exposes three capabilities: **`node`** (connect + host agent),
**`env`** (shared execution context, shell, files), and **`exec`** (commands).

A Node owns SSH reachability and `msdevd` deployment. An Env owns the full
execution context: host or Docker runtime, conda/venv/uv layers, optional
`setup` script (root switch, proxy, etc.), command `wrap`, and static env vars.

The CLI is intentionally stateless: execution always names `--env` explicitly.
MCP is not part of the architecture.

## Install

```bash
git clone https://gitcode.com/rookie_hongchuan/msdev.git
cd msdev
python3 -m pip install -e .
msdev --help
```

The package installs `msdev` and `msdevd`.

## Windows client

The typical setup is a **Windows laptop talking to Linux Nodes** via OpenSSH
(`C:\Windows\System32\OpenSSH\ssh.exe`). Native Windows OpenSSH does not
implement ControlMaster multiplexing, so msdev:

- omits `ControlMaster`/`ControlPath` on Windows (override with
  `MSDEV_SSH_CONTROL_MASTER=1` only if your SSH client actually supports mux);
- starts a persistent `ssh -L` LocalForward tunnel automatically on the first
  RPC (same role as ControlMaster). Explicit `msdev node connect NODE` is
  optional; disable persist with `MSDEV_SSH_LOCAL_FORWARD_PERSIST=0`;
- reuses that tunnel for captured RPC and default streaming `msdev exec`;
  `env put`/`get` stay on scp/ssh streams (file bytes do not go through JSON RPC);
- hides SSH console windows (`CREATE_NO_WINDOW`) and kills process trees with
  `taskkill /T` on timeout or cancel;
- SSH is non-interactive: `BatchMode` unless a password is supplied, host keys
  use `accept-new`, and there is no password/passphrase/yes-no prompt. When a
  password is known, injects OpenSSH `SSH_ASKPASS` so `node connect` (and later
  ssh/scp) can authenticate without a TTY; the local public key is then
  installed on the Node so later logins are passwordless. The password is
  never written to the node registry;
- serves a TCP loopback endpoint for local `msdevd` when this Python build has
  no `AF_UNIX` sockets.

Install with `python -m pip install -e .`. `install-user.py` writes
`msdev.cmd` / `msdevd.cmd` under `%USERPROFILE%\.local\bin`.

Remote paths inside a Linux Env remain POSIX (`/srv/...`). Local `env put`/`get`
on Windows accept Windows absolute paths (`C:\...`).

Local `exec` on Windows wraps Conda with `conda run` and venvs with
`Scripts\activate.bat` (remote Linux Nodes still use POSIX `sh`/`bash` wrappers).
If `ssh` is not on PATH, msdev looks in `%SystemRoot%\System32\OpenSSH\`.

## Nodes and execution environments

Register a host from `~/.ssh/config`:

```bash
msdev node add dev-122 --ssh-host dev-122
msdev node list
msdev node status dev-122
```

Adding a Node atomically creates a same-named host Env. Connect deploys and
starts the remote `msdevd` when needed:

```bash
msdev node connect dev-122
```

Connect uploads a **static Go msdevd** binary matching the node architecture
(`linux-amd64` / `linux-arm64`) when the agent is missing or stale. No Python
is required on the node.

Build the static daemons before release or local testing:

```bash
bash msdevd/build-static.sh
bash file-helper/build-static.sh
```

Packaged artifacts live under `src/msdev/helpers/` (gitignored until built).
The Go source is in `msdev/`.

Persistent OpenSSH masters are optional. All SSH from msdev is
non-interactive: host keys use `accept-new`, and password/passphrase prompts
are disabled. Supply a password via environment or file (never a prompt);
connect then installs the local public key (`~/.ssh/id_ed25519`, generated
if missing) so later connections are passwordless:

```bash
# Environment (also used by exec / env put after connect if persist is off)
export MSDEV_SSH_PASSWORD='...'
export MSDEV_SSH_PASSWORD_DEV_122='...'   # per-node override

msdev node connect dev-122
msdev node connect dev-122 --password-file FILE
msdev node connect dev-122 --password-env VAR
msdev node connect dev-122 --password PASSWORD   # non-interactive; visible in ps
msdev node connect dev-122 --identity FILE     # choose which key to install
msdev node connect dev-122 --no-install-key    # password only, do not copy key
msdev node disconnect dev-122
```

Nodes and Envs have separate private Markdown guides:

```bash
msdev node guide dev-122
msdev node guide dev-122 --write ./dev-122-guide.md
msdev env guide dev-122
msdev env guide dev-122 --write ./host-env-guide.md
```

Guides are stored under `~/.config/msdev/guides/nodes/` and
`~/.config/msdev/guides/environments/`. **Node guides** document how to
connect; **Env guides** document how to initialize shared context (`setup`).

```bash
msdev env add dev-122-root \
  --node dev-122 \
  --setup-file ./setup-root.sh \
  --wrap sudo --wrap -n --wrap --

msdev env open dev-122-root
```

Open a human-operated interactive shell in an Env:

```bash
msdev env shell dev-122
msdev env shell dev-122 --cwd /srv/project
```

Agent automation should use `msdev exec`, not `env shell`.

## File put, get, read, and write

Bulk transfer copies a local file into an Env filesystem, or fetches one back:

```bash
msdev env put dev-122 ./config.yaml /srv/project/config.yaml
msdev env get dev-122 /srv/project/config.yaml --output ./config.yaml
msdev env get dev-122 /srv/project/config.yaml > ./config.yaml
```

Editing uses content-oriented read/write. Paths inside the Env must be
absolute. Host Envs use direct filesystem copy locally and ``scp``/``ssh``
streams remotely. Docker Envs stage through the node with ``docker cp``.
File bytes never pass through JSON RPC.

```bash
msdev env read dev-122 /srv/project/config.yaml
msdev env read dev-122 /srv/project/config.yaml --json
msdev env write dev-122 /srv/project/note.md --file /tmp/note.md
msdev env write dev-122 /srv/project/note.md < /tmp/note.md
msdev env write dev-122 /srv/project/note.md --file /tmp/note.md \
  --expected-sha256 <digest>
```

Read before replacing an existing file. `--expected-sha256` is compare-and-swap
replacement that refuses to overwrite a changed remote file.

## Command execution

Commands execute synchronously and stream stdout and stderr to the terminal as
they are produced. Cursor or Claude Code should use their native background
terminal support for long jobs. Long jobs may also write a persistent progress
log when later inspection is required.

```bash
msdev exec \
  --env dev-122 \
  --cwd /srv/project \
  --timeout-seconds 1800 \
  --env-var MODE=test \
  -- python3 run.py
```

Quoted pipelines and `|` tokens are executed through a remote POSIX shell
(`sh -c`), so they run on the Node instead of being treated as a single
executable name. On a Windows `local` Env they use `cmd.exe /s /c`. Prefer
`sh -c '…'` for complex scripts. Default streaming writes POSIX newlines as
CRLF on a Windows console so remote line output does not staircase; piped
CLI output keeps LF.

`--timeout-seconds` defaults to `-1` (no deadline). Any positive finite duration
is also accepted. A positive timeout kills the complete command
process group and returns exit code 124. Cancelling the local CLI closes the RPC
connection, causing `msdevd` to kill and reap the remote process group. Finite
SSH/Unix RPC deadlines include a short completion grace for output drain and
serialization.

`--result-json` selects captured, non-streaming execution and prints one
structured JSON result containing stdout and stderr.

## Architecture

```text
msdev CLI
  -> typed core service
  -> UnixRpcTransport or SshRpcTransport
  -> per-user msdevd (env session + job runner + files)
```

Remote RPC responses and command output are bounded. Node/Env registries use
locked atomic updates.

## Testing

```bash
python3 -m unittest discover -s tests -v
```

Feature work must include at least one actual scenario test on the real
control path (`msdev` CLI → service → transport → `msdevd` → effect). Unit
tests alone are not sufficient.
