msdev 0.10.0__tar.gz → 0.11.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.
Files changed (94) hide show
  1. {msdev-0.10.0 → msdev-0.11.0}/PKG-INFO +93 -122
  2. msdev-0.11.0/README.md +236 -0
  3. {msdev-0.10.0 → msdev-0.11.0}/pyproject.toml +2 -1
  4. {msdev-0.10.0 → msdev-0.11.0}/src/msdev/__init__.py +1 -1
  5. {msdev-0.10.0 → msdev-0.11.0}/src/msdev/cli.py +213 -498
  6. msdev-0.11.0/src/msdev/core/__init__.py +1 -0
  7. msdev-0.11.0/src/msdev/core/compat.py +222 -0
  8. msdev-0.11.0/src/msdev/core/config.py +373 -0
  9. {msdev-0.10.0 → msdev-0.11.0}/src/msdev/core/container_helper.py +13 -6
  10. msdev-0.11.0/src/msdev/core/env_transfer.py +398 -0
  11. msdev-0.11.0/src/msdev/core/exec_argv.py +82 -0
  12. {msdev-0.10.0 → msdev-0.11.0}/src/msdev/core/host_mutations.py +1 -1
  13. {msdev-0.10.0 → msdev-0.11.0}/src/msdev/core/limits.py +2 -2
  14. msdev-0.11.0/src/msdev/core/local_rpc.py +85 -0
  15. {msdev-0.10.0 → msdev-0.11.0}/src/msdev/core/resources.py +4 -2
  16. {msdev-0.10.0 → msdev-0.11.0}/src/msdev/core/services/__init__.py +10 -22
  17. {msdev-0.10.0 → msdev-0.11.0}/src/msdev/core/services/capabilities.py +3 -23
  18. {msdev-0.10.0 → msdev-0.11.0}/src/msdev/core/services/context.py +0 -2
  19. msdev-0.11.0/src/msdev/core/services/environment.py +331 -0
  20. {msdev-0.10.0 → msdev-0.11.0}/src/msdev/core/services/execution.py +8 -0
  21. {msdev-0.10.0 → msdev-0.11.0}/src/msdev/core/services/node.py +2 -0
  22. msdev-0.11.0/src/msdev/core/ssh_auth.py +395 -0
  23. msdev-0.11.0/src/msdev/core/ssh_tunnel.py +558 -0
  24. {msdev-0.10.0 → msdev-0.11.0}/src/msdev/core/stream_server.py +14 -4
  25. {msdev-0.10.0 → msdev-0.11.0}/src/msdev/core/stream_transport.py +32 -15
  26. {msdev-0.10.0 → msdev-0.11.0}/src/msdev/core/transport.py +366 -90
  27. {msdev-0.10.0 → msdev-0.11.0}/src/msdev/daemon.py +116 -177
  28. {msdev-0.10.0 → msdev-0.11.0}/src/msdev.egg-info/PKG-INFO +93 -122
  29. {msdev-0.10.0 → msdev-0.11.0}/src/msdev.egg-info/SOURCES.txt +15 -13
  30. {msdev-0.10.0 → msdev-0.11.0}/tests/test_cli.py +26 -303
  31. {msdev-0.10.0 → msdev-0.11.0}/tests/test_cli_only_architecture.py +4 -7
  32. msdev-0.11.0/tests/test_compat.py +64 -0
  33. {msdev-0.10.0 → msdev-0.11.0}/tests/test_config.py +82 -1
  34. {msdev-0.10.0 → msdev-0.11.0}/tests/test_daemon.py +100 -59
  35. {msdev-0.10.0 → msdev-0.11.0}/tests/test_daemon_container_stream.py +1 -0
  36. {msdev-0.10.0 → msdev-0.11.0}/tests/test_docker_stream_dispatch.py +7 -2
  37. msdev-0.11.0/tests/test_env_put_get_scenario.py +134 -0
  38. msdev-0.11.0/tests/test_env_read_write_scenario.py +134 -0
  39. msdev-0.11.0/tests/test_env_transfer.py +88 -0
  40. msdev-0.11.0/tests/test_exec_argv.py +55 -0
  41. msdev-0.11.0/tests/test_exec_default_timeout_scenario.py +134 -0
  42. {msdev-0.10.0 → msdev-0.11.0}/tests/test_model_services.py +0 -2
  43. {msdev-0.10.0 → msdev-0.11.0}/tests/test_msdev_cli_skill.py +9 -9
  44. {msdev-0.10.0 → msdev-0.11.0}/tests/test_multiplex.py +12 -3
  45. msdev-0.11.0/tests/test_node_env_services.py +187 -0
  46. {msdev-0.10.0 → msdev-0.11.0}/tests/test_request_client.py +10 -4
  47. msdev-0.11.0/tests/test_ssh_auth.py +515 -0
  48. msdev-0.11.0/tests/test_ssh_tunnel.py +57 -0
  49. {msdev-0.10.0 → msdev-0.11.0}/tests/test_stream_server.py +10 -3
  50. {msdev-0.10.0 → msdev-0.11.0}/tests/test_stream_transport.py +9 -4
  51. {msdev-0.10.0 → msdev-0.11.0}/tests/test_target_exec_services.py +73 -4
  52. {msdev-0.10.0 → msdev-0.11.0}/tests/test_transport.py +212 -17
  53. msdev-0.11.0/tests/test_windows_local_scenario.py +124 -0
  54. msdev-0.10.0/README.md +0 -266
  55. msdev-0.10.0/src/msdev/core/__init__.py +0 -1
  56. msdev-0.10.0/src/msdev/core/config.py +0 -193
  57. msdev-0.10.0/src/msdev/core/services/environment.py +0 -84
  58. msdev-0.10.0/src/msdev/core/services/workspace.py +0 -567
  59. msdev-0.10.0/src/msdev/core/workspace/__init__.py +0 -43
  60. msdev-0.10.0/src/msdev/core/workspace/access.py +0 -1216
  61. msdev-0.10.0/src/msdev/core/workspace/client.py +0 -329
  62. msdev-0.10.0/src/msdev/core/workspace/paths.py +0 -65
  63. msdev-0.10.0/src/msdev/core/workspace/registry.py +0 -189
  64. msdev-0.10.0/src/msdev/session/__init__.py +0 -13
  65. msdev-0.10.0/src/msdev/session/export.py +0 -190
  66. msdev-0.10.0/src/msdev/session/log.py +0 -269
  67. msdev-0.10.0/tests/test_cli_session.py +0 -202
  68. msdev-0.10.0/tests/test_node_env_services.py +0 -63
  69. msdev-0.10.0/tests/test_workspace.py +0 -855
  70. msdev-0.10.0/tests/test_workspace_client.py +0 -321
  71. msdev-0.10.0/tests/test_workspace_services.py +0 -414
  72. {msdev-0.10.0 → msdev-0.11.0}/LICENSE +0 -0
  73. {msdev-0.10.0 → msdev-0.11.0}/setup.cfg +0 -0
  74. {msdev-0.10.0 → msdev-0.11.0}/src/msdev/core/guides.py +0 -0
  75. {msdev-0.10.0 → msdev-0.11.0}/src/msdev/core/helper_deploy.py +0 -0
  76. {msdev-0.10.0 → msdev-0.11.0}/src/msdev/core/host_files.py +0 -0
  77. {msdev-0.10.0 → msdev-0.11.0}/src/msdev/core/inventory.py +0 -0
  78. {msdev-0.10.0 → msdev-0.11.0}/src/msdev/core/multiplex.py +0 -0
  79. {msdev-0.10.0 → msdev-0.11.0}/src/msdev/core/request_client.py +0 -0
  80. {msdev-0.10.0 → msdev-0.11.0}/src/msdev/core/services/model.py +0 -0
  81. {msdev-0.10.0 → msdev-0.11.0}/src/msdev/core/services/npu.py +0 -0
  82. {msdev-0.10.0 → msdev-0.11.0}/src/msdev/core/services/results.py +0 -0
  83. {msdev-0.10.0 → msdev-0.11.0}/src/msdev/core/stream_limits.py +0 -0
  84. {msdev-0.10.0 → msdev-0.11.0}/src/msdev/core/streamproto.py +0 -0
  85. {msdev-0.10.0 → msdev-0.11.0}/src/msdev.egg-info/dependency_links.txt +0 -0
  86. {msdev-0.10.0 → msdev-0.11.0}/src/msdev.egg-info/entry_points.txt +0 -0
  87. {msdev-0.10.0 → msdev-0.11.0}/src/msdev.egg-info/top_level.txt +0 -0
  88. {msdev-0.10.0 → msdev-0.11.0}/tests/test_container_helper.py +0 -0
  89. {msdev-0.10.0 → msdev-0.11.0}/tests/test_helper_deploy.py +0 -0
  90. {msdev-0.10.0 → msdev-0.11.0}/tests/test_inventory.py +0 -0
  91. {msdev-0.10.0 → msdev-0.11.0}/tests/test_model_cli.py +0 -0
  92. {msdev-0.10.0 → msdev-0.11.0}/tests/test_node_env_config.py +0 -0
  93. {msdev-0.10.0 → msdev-0.11.0}/tests/test_streamproto.py +0 -0
  94. {msdev-0.10.0 → msdev-0.11.0}/tests/test_target_guides.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: msdev
3
- Version: 0.10.0
3
+ Version: 0.11.0
4
4
  Summary: Portable nodes and execution environments for msModelSlim development
5
5
  Author: msModelSlim Agent Contributors
6
6
  License-Expression: MulanPSL-2.0
@@ -15,6 +15,7 @@ Classifier: Programming Language :: Python :: 3.11
15
15
  Classifier: Programming Language :: Python :: 3.12
16
16
  Classifier: Programming Language :: Python :: 3.13
17
17
  Classifier: Operating System :: MacOS
18
+ Classifier: Operating System :: Microsoft :: Windows
18
19
  Classifier: Operating System :: POSIX :: Linux
19
20
  Classifier: Topic :: Software Development :: Build Tools
20
21
  Requires-Python: >=3.10
@@ -32,7 +33,6 @@ The CLI is intentionally stateless:
32
33
 
33
34
  - Node-scoped NPU/model operations name `--node` or use `--all`;
34
35
  - execution names `--env`;
35
- - every workspace operation names the registered workspace;
36
36
  - no harness conversation binding or implicit current Env exists;
37
37
  - MCP is not part of the architecture.
38
38
 
@@ -47,6 +47,40 @@ msdev --help
47
47
 
48
48
  The package installs `msdev` and `msdevd`.
49
49
 
50
+ ## Windows client
51
+
52
+ The typical setup is a **Windows laptop talking to Linux Nodes** via OpenSSH
53
+ (`C:\Windows\System32\OpenSSH\ssh.exe`). Native Windows OpenSSH does not
54
+ implement ControlMaster multiplexing, so msdev:
55
+
56
+ - omits `ControlMaster`/`ControlPath` on Windows (override with
57
+ `MSDEV_SSH_CONTROL_MASTER=1` only if your SSH client actually supports mux);
58
+ - starts a persistent `ssh -L` LocalForward tunnel automatically on the first
59
+ RPC (same role as ControlMaster). Explicit `msdev node connect NODE` is
60
+ optional; disable persist with `MSDEV_SSH_LOCAL_FORWARD_PERSIST=0`;
61
+ - reuses that tunnel for captured RPC and default streaming `msdev exec`;
62
+ `env put`/`get` stay on scp/ssh streams (file bytes do not go through JSON RPC);
63
+ - hides SSH console windows (`CREATE_NO_WINDOW`) and kills process trees with
64
+ `taskkill /T` on timeout or cancel;
65
+ - SSH is non-interactive: `BatchMode` unless a password is supplied, host keys
66
+ use `accept-new`, and there is no password/passphrase/yes-no prompt. When a
67
+ password is known, injects OpenSSH `SSH_ASKPASS` so `node connect` (and later
68
+ ssh/scp) can authenticate without a TTY; the local public key is then
69
+ installed on the Node so later logins are passwordless. The password is
70
+ never written to the node registry;
71
+ - serves a TCP loopback endpoint for local `msdevd` when this Python build has
72
+ no `AF_UNIX` sockets.
73
+
74
+ Install with `python -m pip install -e .`. `install-user.py` writes
75
+ `msdev.cmd` / `msdevd.cmd` under `%USERPROFILE%\.local\bin`.
76
+
77
+ Remote paths inside a Linux Env remain POSIX (`/srv/...`). Local `env put`/`get`
78
+ on Windows accept Windows absolute paths (`C:\...`).
79
+
80
+ Local `exec` on Windows wraps Conda with `conda run` and venvs with
81
+ `Scripts\activate.bat` (remote Linux Nodes still use POSIX `sh`/`bash` wrappers).
82
+ If `ssh` is not on PATH, msdev looks in `%SystemRoot%\System32\OpenSSH\`.
83
+
50
84
  ## Nodes and execution environments
51
85
 
52
86
  Register a host from `~/.ssh/config`:
@@ -64,10 +98,23 @@ the remote user daemon:
64
98
  msdev node bootstrap dev-122
65
99
  ```
66
100
 
67
- Persistent OpenSSH masters are optional:
101
+ Persistent OpenSSH masters are optional. All SSH from msdev is
102
+ non-interactive: host keys use `accept-new`, and password/passphrase prompts
103
+ are disabled. Supply a password via environment or file (never a prompt);
104
+ connect then installs the local public key (`~/.ssh/id_ed25519`, generated
105
+ if missing) so later connections are passwordless:
68
106
 
69
107
  ```bash
108
+ # Environment (also used by exec / env put after connect if persist is off)
109
+ export MSDEV_SSH_PASSWORD='...'
110
+ export MSDEV_SSH_PASSWORD_DEV_122='...' # per-node override
111
+
70
112
  msdev node connect dev-122
113
+ msdev node connect dev-122 --password-file FILE
114
+ msdev node connect dev-122 --password-env VAR
115
+ msdev node connect dev-122 --password PASSWORD # non-interactive; visible in ps
116
+ msdev node connect dev-122 --identity FILE # choose which key to install
117
+ msdev node connect dev-122 --no-install-key # password only, do not copy key
71
118
  msdev node disconnect dev-122
72
119
  ```
73
120
 
@@ -107,6 +154,33 @@ msdev env add dev-122-vllm \
107
154
  --layer venv:/srv/project/.venv
108
155
  ```
109
156
 
157
+ ## File put, get, read, and write
158
+
159
+ Bulk transfer copies a local file into an Env filesystem, or fetches one back:
160
+
161
+ ```bash
162
+ msdev env put dev-122 ./config.yaml /srv/project/config.yaml
163
+ msdev env get dev-122 /srv/project/config.yaml --output ./config.yaml
164
+ msdev env get dev-122 /srv/project/config.yaml > ./config.yaml
165
+ ```
166
+
167
+ Editing uses content-oriented read/write. Paths inside the Env must be
168
+ absolute. Host Envs use direct filesystem copy locally and ``scp``/``ssh``
169
+ streams remotely. Docker Envs stage through the node with ``docker cp``.
170
+ File bytes never pass through JSON RPC.
171
+
172
+ ```bash
173
+ msdev env read dev-122 /srv/project/config.yaml
174
+ msdev env read dev-122 /srv/project/config.yaml --json
175
+ msdev env write dev-122 /srv/project/note.md --file /tmp/note.md
176
+ msdev env write dev-122 /srv/project/note.md < /tmp/note.md
177
+ msdev env write dev-122 /srv/project/note.md --file /tmp/note.md \
178
+ --expected-sha256 <digest>
179
+ ```
180
+
181
+ Read before replacing an existing file. `--expected-sha256` is compare-and-swap
182
+ replacement that refuses to overwrite a changed remote file.
183
+
110
184
  ## NPU inventory
111
185
 
112
186
  ```bash
@@ -130,8 +204,15 @@ msdev exec \
130
204
  -- python3 run.py
131
205
  ```
132
206
 
133
- `--timeout-seconds` defaults to 300, accepts any positive finite duration, and
134
- uses `-1` for no deadline. A positive timeout kills the complete command
207
+ Quoted pipelines and `|` tokens are executed through a remote POSIX shell
208
+ (`sh -c`), so they run on the Node instead of being treated as a single
209
+ executable name. On a Windows `local` Env they use `cmd.exe /s /c`. Prefer
210
+ `sh -c '…'` for complex scripts. Default streaming writes POSIX newlines as
211
+ CRLF on a Windows console so remote line output does not staircase; piped
212
+ CLI output keeps LF.
213
+
214
+ `--timeout-seconds` defaults to `-1` (no deadline). Any positive finite duration
215
+ is also accepted. A positive timeout kills the complete command
135
216
  process group and returns exit code 124. Cancelling the local CLI closes the RPC
136
217
  connection, causing `msdevd` to kill and reap the remote process group. Finite
137
218
  SSH/Unix RPC deadlines include a short completion grace for output drain and
@@ -140,66 +221,6 @@ serialization.
140
221
  `--result-json` selects captured, non-streaming execution and prints one
141
222
  structured JSON result containing stdout and stderr.
142
223
 
143
- ## Remote workspaces
144
-
145
- A workspace gives a stable name to an Env and filesystem root:
146
-
147
- ```bash
148
- msdev workspace add project \
149
- --env dev-122 \
150
- --root /srv/project
151
-
152
- msdev workspace list
153
- msdev workspace inspect project
154
- ```
155
-
156
- Workspace operations are file- and Git-oriented. There is no
157
- `msdev workspace exec`; use `msdev exec --env ... --cwd ...` for commands.
158
-
159
- ### Read and inspect
160
-
161
- ```bash
162
- msdev workspace stat project README.md
163
- msdev workspace read project README.md
164
- msdev workspace read project weights.bin --output /tmp/weights.bin
165
- msdev workspace list project src --json
166
- msdev workspace glob project '**/*.py' --json
167
- msdev workspace search project 'TODO' src tests --json
168
- ```
169
-
170
- ### Write safely
171
-
172
- For non-trivial content, use stdin or `--file` rather than shell-escaped
173
- `--content`:
174
-
175
- ```bash
176
- msdev workspace write project docs/note.md < /tmp/note.md
177
- msdev workspace write project docs/note.md --file /tmp/note.md
178
- ```
179
-
180
- Compare-and-swap replacement prevents overwriting a changed remote file:
181
-
182
- ```bash
183
- msdev workspace apply-patch project docs/note.md \
184
- --file /tmp/note.md \
185
- --expected-sha256 <digest>
186
- ```
187
-
188
- Delete an explicit remote file:
189
-
190
- ```bash
191
- msdev workspace delete project docs/obsolete.md
192
- ```
193
-
194
- ### Git
195
-
196
- ```bash
197
- msdev workspace git-status project --result-json
198
- msdev workspace git-diff project --result-json -- --stat
199
- ```
200
-
201
- Git diff rejects options that can write files or invoke external diff helpers.
202
-
203
224
  ## Model inventory
204
225
 
205
226
  Examples:
@@ -216,59 +237,6 @@ msdev model audit --node dev-122
216
237
  Use `msdev model --help` and the individual subcommand help for register,
217
238
  update, replicas, refresh, verify, export, import, and rebind.
218
239
 
219
- ## Explicit CLI sessions and runbooks
220
-
221
- Create a session before a reproducible workflow:
222
-
223
- ```bash
224
- msdev session begin --name qwen3-quant --json
225
- ```
226
-
227
- Pass the returned ID explicitly or set it in a persistent terminal:
228
-
229
- ```bash
230
- export MSDEV_SESSION_ID=<session-id>
231
- ```
232
-
233
- Intent metadata is global and must appear before the subcommand:
234
-
235
- ```bash
236
- msdev \
237
- --session-id <session-id> \
238
- --intent-kind execution \
239
- --intent-summary 'Run Qwen3 quantization' \
240
- --intent-phase quantization \
241
- --intent-step-id quant-1 \
242
- exec --env dev-122 --timeout-seconds 1800 -- python3 quant.py
243
- ```
244
-
245
- Intent kinds:
246
-
247
- - `execution`: core reproduction step;
248
- - `verification`: optional confirmation;
249
- - `diagnostic`: troubleshooting, excluded from core steps;
250
- - `exploration`: discovery, excluded from core steps.
251
-
252
- Each invocation receives a unique `operation_id`. `session_id` groups CLI
253
- operations only; it never supplies a Node, Env, or workspace default.
254
-
255
- Logs are private JSONL files under:
256
-
257
- ```text
258
- ${XDG_STATE_HOME:-~/.local/state}/msdev/sessions/
259
- ```
260
-
261
- They retain sanitized logical arguments, preview, explicit resource, intent,
262
- exit code, and elapsed time. Command stdout/stderr and environment values are
263
- not duplicated into logs.
264
-
265
- ```bash
266
- msdev session list
267
- msdev session export --session-id <session-id> --output runbook.md
268
- msdev session export --latest --detail normal --output runbook.md
269
- msdev session export --input /path/to/session.jsonl --detail full
270
- ```
271
-
272
240
  ## Architecture
273
241
 
274
242
  ```text
@@ -276,15 +244,18 @@ msdev CLI
276
244
  -> typed core service
277
245
  -> UnixRpcTransport or SshRpcTransport
278
246
  -> per-user msdevd
279
- -> host/container command, workspace filesystem, NPU, or inventory
247
+ -> host/container command, env file transfer, NPU, or inventory
280
248
  ```
281
249
 
282
- Remote RPC responses and command output are bounded. Workspace paths are
283
- normalized under the registered root. Writes are atomic and support SHA-256
284
- compare-and-swap. Node/Env and workspace registries use locked atomic updates.
250
+ Remote RPC responses and command output are bounded. Node/Env registries use
251
+ locked atomic updates.
285
252
 
286
253
  ## Testing
287
254
 
288
255
  ```bash
289
256
  python3 -m unittest discover -s tests -v
290
257
  ```
258
+
259
+ Feature work must include at least one actual scenario test on the real
260
+ control path (`msdev` CLI → service → transport → `msdevd` → effect). Unit
261
+ tests alone are not sufficient.
msdev-0.11.0/README.md ADDED
@@ -0,0 +1,236 @@
1
+ # msdev
2
+
3
+ `msdev` manages connection Nodes and execution Envs. A Node owns SSH and its
4
+ per-user `msdevd`; an Env references a Node and adds a host/Docker runtime plus
5
+ optional conda/venv/uv layers.
6
+
7
+ The CLI is intentionally stateless:
8
+
9
+ - Node-scoped NPU/model operations name `--node` or use `--all`;
10
+ - execution names `--env`;
11
+ - no harness conversation binding or implicit current Env exists;
12
+ - MCP is not part of the architecture.
13
+
14
+ ## Install
15
+
16
+ ```bash
17
+ git clone https://gitcode.com/rookie_hongchuan/msdev.git
18
+ cd msdev
19
+ python3 -m pip install -e .
20
+ msdev --help
21
+ ```
22
+
23
+ The package installs `msdev` and `msdevd`.
24
+
25
+ ## Windows client
26
+
27
+ The typical setup is a **Windows laptop talking to Linux Nodes** via OpenSSH
28
+ (`C:\Windows\System32\OpenSSH\ssh.exe`). Native Windows OpenSSH does not
29
+ implement ControlMaster multiplexing, so msdev:
30
+
31
+ - omits `ControlMaster`/`ControlPath` on Windows (override with
32
+ `MSDEV_SSH_CONTROL_MASTER=1` only if your SSH client actually supports mux);
33
+ - starts a persistent `ssh -L` LocalForward tunnel automatically on the first
34
+ RPC (same role as ControlMaster). Explicit `msdev node connect NODE` is
35
+ optional; disable persist with `MSDEV_SSH_LOCAL_FORWARD_PERSIST=0`;
36
+ - reuses that tunnel for captured RPC and default streaming `msdev exec`;
37
+ `env put`/`get` stay on scp/ssh streams (file bytes do not go through JSON RPC);
38
+ - hides SSH console windows (`CREATE_NO_WINDOW`) and kills process trees with
39
+ `taskkill /T` on timeout or cancel;
40
+ - SSH is non-interactive: `BatchMode` unless a password is supplied, host keys
41
+ use `accept-new`, and there is no password/passphrase/yes-no prompt. When a
42
+ password is known, injects OpenSSH `SSH_ASKPASS` so `node connect` (and later
43
+ ssh/scp) can authenticate without a TTY; the local public key is then
44
+ installed on the Node so later logins are passwordless. The password is
45
+ never written to the node registry;
46
+ - serves a TCP loopback endpoint for local `msdevd` when this Python build has
47
+ no `AF_UNIX` sockets.
48
+
49
+ Install with `python -m pip install -e .`. `install-user.py` writes
50
+ `msdev.cmd` / `msdevd.cmd` under `%USERPROFILE%\.local\bin`.
51
+
52
+ Remote paths inside a Linux Env remain POSIX (`/srv/...`). Local `env put`/`get`
53
+ on Windows accept Windows absolute paths (`C:\...`).
54
+
55
+ Local `exec` on Windows wraps Conda with `conda run` and venvs with
56
+ `Scripts\activate.bat` (remote Linux Nodes still use POSIX `sh`/`bash` wrappers).
57
+ If `ssh` is not on PATH, msdev looks in `%SystemRoot%\System32\OpenSSH\`.
58
+
59
+ ## Nodes and execution environments
60
+
61
+ Register a host from `~/.ssh/config`:
62
+
63
+ ```bash
64
+ msdev node add dev-122 --ssh-host dev-122
65
+ msdev node list
66
+ msdev node status dev-122
67
+ ```
68
+
69
+ Adding a Node atomically creates a same-named host Env. Bootstrap or refresh
70
+ the remote user daemon:
71
+
72
+ ```bash
73
+ msdev node bootstrap dev-122
74
+ ```
75
+
76
+ Persistent OpenSSH masters are optional. All SSH from msdev is
77
+ non-interactive: host keys use `accept-new`, and password/passphrase prompts
78
+ are disabled. Supply a password via environment or file (never a prompt);
79
+ connect then installs the local public key (`~/.ssh/id_ed25519`, generated
80
+ if missing) so later connections are passwordless:
81
+
82
+ ```bash
83
+ # Environment (also used by exec / env put after connect if persist is off)
84
+ export MSDEV_SSH_PASSWORD='...'
85
+ export MSDEV_SSH_PASSWORD_DEV_122='...' # per-node override
86
+
87
+ msdev node connect dev-122
88
+ msdev node connect dev-122 --password-file FILE
89
+ msdev node connect dev-122 --password-env VAR
90
+ msdev node connect dev-122 --password PASSWORD # non-interactive; visible in ps
91
+ msdev node connect dev-122 --identity FILE # choose which key to install
92
+ msdev node connect dev-122 --no-install-key # password only, do not copy key
93
+ msdev node disconnect dev-122
94
+ ```
95
+
96
+ Nodes and Envs have separate private Markdown guides:
97
+
98
+ ```bash
99
+ msdev node guide dev-122
100
+ msdev node guide dev-122 --write ./dev-122-guide.md
101
+ msdev env guide dev-122
102
+ msdev env guide dev-122 --write ./host-env-guide.md
103
+ ```
104
+
105
+ Guides are stored under `~/.config/msdev/guides/nodes/` and
106
+ `~/.config/msdev/guides/environments/`, with private permissions and a 256 KiB
107
+ limit. Agents read the applicable guides once before first use in a session.
108
+
109
+ Open a human-operated interactive shell in an Env:
110
+
111
+ ```bash
112
+ msdev env shell dev-122
113
+ msdev env shell dev-122 --cwd /srv/project
114
+ ```
115
+
116
+ The command allocates an OpenSSH PTY and enters the Env's Docker runtime and
117
+ conda/venv/uv layers. Exiting returns
118
+ to the local shell. Only the shell session start and final status are visible
119
+ to msdev; commands typed inside it are not individually logged. Agent
120
+ automation should continue using `msdev exec`.
121
+
122
+ Create another Env on the same Node for Docker and Python layers:
123
+
124
+ ```bash
125
+ msdev env add dev-122-vllm \
126
+ --node dev-122 \
127
+ --docker-container vllm-ascend \
128
+ --layer conda:base \
129
+ --layer venv:/srv/project/.venv
130
+ ```
131
+
132
+ ## File put, get, read, and write
133
+
134
+ Bulk transfer copies a local file into an Env filesystem, or fetches one back:
135
+
136
+ ```bash
137
+ msdev env put dev-122 ./config.yaml /srv/project/config.yaml
138
+ msdev env get dev-122 /srv/project/config.yaml --output ./config.yaml
139
+ msdev env get dev-122 /srv/project/config.yaml > ./config.yaml
140
+ ```
141
+
142
+ Editing uses content-oriented read/write. Paths inside the Env must be
143
+ absolute. Host Envs use direct filesystem copy locally and ``scp``/``ssh``
144
+ streams remotely. Docker Envs stage through the node with ``docker cp``.
145
+ File bytes never pass through JSON RPC.
146
+
147
+ ```bash
148
+ msdev env read dev-122 /srv/project/config.yaml
149
+ msdev env read dev-122 /srv/project/config.yaml --json
150
+ msdev env write dev-122 /srv/project/note.md --file /tmp/note.md
151
+ msdev env write dev-122 /srv/project/note.md < /tmp/note.md
152
+ msdev env write dev-122 /srv/project/note.md --file /tmp/note.md \
153
+ --expected-sha256 <digest>
154
+ ```
155
+
156
+ Read before replacing an existing file. `--expected-sha256` is compare-and-swap
157
+ replacement that refuses to overwrite a changed remote file.
158
+
159
+ ## NPU inventory
160
+
161
+ ```bash
162
+ msdev npu list --node dev-122 --json
163
+ msdev npu list --all --json
164
+ ```
165
+
166
+ ## Command execution
167
+
168
+ Commands execute synchronously and stream stdout and stderr to the terminal as
169
+ they are produced. Cursor or Claude Code should use their native background
170
+ terminal support for long jobs. Long jobs may also write a persistent progress
171
+ log when later inspection is required.
172
+
173
+ ```bash
174
+ msdev exec \
175
+ --env dev-122 \
176
+ --cwd /srv/project \
177
+ --timeout-seconds 1800 \
178
+ --env-var MODE=test \
179
+ -- python3 run.py
180
+ ```
181
+
182
+ Quoted pipelines and `|` tokens are executed through a remote POSIX shell
183
+ (`sh -c`), so they run on the Node instead of being treated as a single
184
+ executable name. On a Windows `local` Env they use `cmd.exe /s /c`. Prefer
185
+ `sh -c '…'` for complex scripts. Default streaming writes POSIX newlines as
186
+ CRLF on a Windows console so remote line output does not staircase; piped
187
+ CLI output keeps LF.
188
+
189
+ `--timeout-seconds` defaults to `-1` (no deadline). Any positive finite duration
190
+ is also accepted. A positive timeout kills the complete command
191
+ process group and returns exit code 124. Cancelling the local CLI closes the RPC
192
+ connection, causing `msdevd` to kill and reap the remote process group. Finite
193
+ SSH/Unix RPC deadlines include a short completion grace for output drain and
194
+ serialization.
195
+
196
+ `--result-json` selects captured, non-streaming execution and prints one
197
+ structured JSON result containing stdout and stderr.
198
+
199
+ ## Model inventory
200
+
201
+ Examples:
202
+
203
+ ```bash
204
+ msdev model discover --node dev-122 --root /data/models
205
+ msdev model list --node dev-122 --json
206
+ msdev model list --all --json
207
+ msdev model inspect model://qwen/Qwen3-32B@main --node dev-122
208
+ msdev model validate model://qwen/Qwen3-32B@main --node dev-122
209
+ msdev model audit --node dev-122
210
+ ```
211
+
212
+ Use `msdev model --help` and the individual subcommand help for register,
213
+ update, replicas, refresh, verify, export, import, and rebind.
214
+
215
+ ## Architecture
216
+
217
+ ```text
218
+ msdev CLI
219
+ -> typed core service
220
+ -> UnixRpcTransport or SshRpcTransport
221
+ -> per-user msdevd
222
+ -> host/container command, env file transfer, NPU, or inventory
223
+ ```
224
+
225
+ Remote RPC responses and command output are bounded. Node/Env registries use
226
+ locked atomic updates.
227
+
228
+ ## Testing
229
+
230
+ ```bash
231
+ python3 -m unittest discover -s tests -v
232
+ ```
233
+
234
+ Feature work must include at least one actual scenario test on the real
235
+ control path (`msdev` CLI → service → transport → `msdevd` → effect). Unit
236
+ tests alone are not sufficient.
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "msdev"
7
- version = "0.10.0"
7
+ version = "0.11.0"
8
8
  description = "Portable nodes and execution environments for msModelSlim development"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -23,6 +23,7 @@ classifiers = [
23
23
  "Programming Language :: Python :: 3.12",
24
24
  "Programming Language :: Python :: 3.13",
25
25
  "Operating System :: MacOS",
26
+ "Operating System :: Microsoft :: Windows",
26
27
  "Operating System :: POSIX :: Linux",
27
28
  "Topic :: Software Development :: Build Tools",
28
29
  ]
@@ -1,3 +1,3 @@
1
1
  """Portable node and execution-environment tooling for msModelSlim."""
2
2
 
3
- __version__ = "0.10.0"
3
+ __version__ = "0.11.0"