remote-cli 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.
- remote_cli-0.1.0/.github/workflows/publish.yml +66 -0
- remote_cli-0.1.0/.gitignore +38 -0
- remote_cli-0.1.0/.python-version +1 -0
- remote_cli-0.1.0/LICENSE +21 -0
- remote_cli-0.1.0/PKG-INFO +166 -0
- remote_cli-0.1.0/README.md +154 -0
- remote_cli-0.1.0/pyproject.toml +47 -0
- remote_cli-0.1.0/skills/remote-cli/SKILL.md +148 -0
- remote_cli-0.1.0/src/remote_cli/__init__.py +15 -0
- remote_cli-0.1.0/src/remote_cli/_version.py +24 -0
- remote_cli-0.1.0/src/remote_cli/cli.py +303 -0
- remote_cli-0.1.0/src/remote_cli/client.py +164 -0
- remote_cli-0.1.0/src/remote_cli/daemon.py +296 -0
- remote_cli-0.1.0/src/remote_cli/protocol.py +66 -0
- remote_cli-0.1.0/src/remote_cli/screen.py +68 -0
- remote_cli-0.1.0/src/remote_cli/session.py +339 -0
- remote_cli-0.1.0/src/remote_cli/terminal.py +137 -0
- remote_cli-0.1.0/src/remote_cli/utils.py +40 -0
- remote_cli-0.1.0/tests/test_cli.py +22 -0
- remote_cli-0.1.0/tests/test_daemon_and_client.py +102 -0
- remote_cli-0.1.0/tests/test_e2e_cli.py +87 -0
- remote_cli-0.1.0/tests/test_multiplexing.py +120 -0
- remote_cli-0.1.0/tests/test_protocol.py +42 -0
- remote_cli-0.1.0/tests/test_screen.py +33 -0
- remote_cli-0.1.0/tests/test_session.py +58 -0
- remote_cli-0.1.0/uv.lock +342 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
- "[0-9]+.[0-9]+.[0-9]+*"
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
name: Run Tests
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
steps:
|
|
14
|
+
- name: Checkout code
|
|
15
|
+
uses: actions/checkout@v4
|
|
16
|
+
with:
|
|
17
|
+
fetch-depth: 0
|
|
18
|
+
|
|
19
|
+
- name: Set up uv
|
|
20
|
+
uses: astral-sh/setup-uv@v5
|
|
21
|
+
with:
|
|
22
|
+
enable-cache: true
|
|
23
|
+
|
|
24
|
+
- name: Install dependencies & run tests
|
|
25
|
+
run: |
|
|
26
|
+
uv sync
|
|
27
|
+
uv run pytest -v
|
|
28
|
+
|
|
29
|
+
build-and-publish:
|
|
30
|
+
name: Build and Publish to PyPI
|
|
31
|
+
needs: test
|
|
32
|
+
runs-on: ubuntu-latest
|
|
33
|
+
environment:
|
|
34
|
+
name: pypi
|
|
35
|
+
url: https://pypi.org/p/remote-cli
|
|
36
|
+
permissions:
|
|
37
|
+
id-token: write # Mandatory for PyPI Trusted Publishing
|
|
38
|
+
contents: write # For creating GitHub Releases
|
|
39
|
+
|
|
40
|
+
steps:
|
|
41
|
+
- name: Checkout repository
|
|
42
|
+
uses: actions/checkout@v4
|
|
43
|
+
with:
|
|
44
|
+
fetch-depth: 0 # Necessary for hatch-vcs to resolve version from tag
|
|
45
|
+
|
|
46
|
+
- name: Set up uv
|
|
47
|
+
uses: astral-sh/setup-uv@v5
|
|
48
|
+
with:
|
|
49
|
+
enable-cache: true
|
|
50
|
+
|
|
51
|
+
- name: Build package distributions
|
|
52
|
+
run: uv build
|
|
53
|
+
|
|
54
|
+
- name: Publish to PyPI
|
|
55
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
56
|
+
with:
|
|
57
|
+
# Works with PyPI Trusted Publishing (OIDC) or PYPI_API_TOKEN secret
|
|
58
|
+
password: ${{ secrets.PYPI_API_TOKEN }}
|
|
59
|
+
skip-existing: true
|
|
60
|
+
|
|
61
|
+
- name: Create GitHub Release
|
|
62
|
+
uses: softprops/action-gh-release@v2
|
|
63
|
+
if: startsWith(github.ref, 'refs/tags/')
|
|
64
|
+
with:
|
|
65
|
+
files: dist/*
|
|
66
|
+
generate_release_notes: true
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# Virtual environments
|
|
7
|
+
.venv/
|
|
8
|
+
venv/
|
|
9
|
+
ENV/
|
|
10
|
+
env/
|
|
11
|
+
|
|
12
|
+
# Distribution / packaging
|
|
13
|
+
dist/
|
|
14
|
+
build/
|
|
15
|
+
*.egg-info/
|
|
16
|
+
src/remote_cli/_version.py
|
|
17
|
+
|
|
18
|
+
# Testing & Coverage
|
|
19
|
+
.pytest_cache/
|
|
20
|
+
.coverage
|
|
21
|
+
htmlcov/
|
|
22
|
+
|
|
23
|
+
# Operating System & Editors
|
|
24
|
+
.DS_Store
|
|
25
|
+
.AppleDouble
|
|
26
|
+
.LSOverride
|
|
27
|
+
._*
|
|
28
|
+
.idea/
|
|
29
|
+
.vscode/
|
|
30
|
+
*.swp
|
|
31
|
+
*.swo
|
|
32
|
+
*~
|
|
33
|
+
|
|
34
|
+
# remote-cli local runtime files
|
|
35
|
+
.remote-cli/
|
|
36
|
+
*.sock
|
|
37
|
+
*.pid
|
|
38
|
+
*.log
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.12
|
remote_cli-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 8DE4732A
|
|
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.
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: remote-cli
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A shared SSH CLI tool for AI Agent and human co-piloting
|
|
5
|
+
License-File: LICENSE
|
|
6
|
+
Requires-Python: >=3.12
|
|
7
|
+
Requires-Dist: pydantic>=2.10.0
|
|
8
|
+
Requires-Dist: pyte>=0.8.2
|
|
9
|
+
Requires-Dist: rich>=13.9.0
|
|
10
|
+
Requires-Dist: typer>=0.15.0
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
|
|
13
|
+
# remote-cli
|
|
14
|
+
|
|
15
|
+
> **Shared SSH & Terminal CLI tool for AI Agent and Human Co-piloting.**
|
|
16
|
+
|
|
17
|
+
`remote-cli` allows a human user to start an interactive SSH session (handling passwords, 2FA, bastion hosts, and SSH keys themselves) and share that session with an AI Agent via a unique `session-id`.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Key Features
|
|
22
|
+
|
|
23
|
+
- 🤝 **Real-Time Human & Agent Co-piloting**:
|
|
24
|
+
- The human sees everything the Agent does in their original terminal window in real-time.
|
|
25
|
+
- The human can continue typing and operating in the same session at any time.
|
|
26
|
+
- ⚡ **Zero External Binary Dependencies**:
|
|
27
|
+
- Pure Python + POSIX PTY (`pty.openpty`, `termios`, `tty`).
|
|
28
|
+
- No need to install `tmux` or `screen` on local or remote servers.
|
|
29
|
+
- 🤖 **First-Class AI Agent Support**:
|
|
30
|
+
- `exec`: Structured execution of shell commands with stdout capture and return codes.
|
|
31
|
+
- `snapshot`: In-memory 2D virtual terminal rendering (`pyte`) for clean screen capture (even for ncurses / curses / colored prompts).
|
|
32
|
+
- `send`: Keystrokes and control signals (`Ctrl+C`, `Ctrl+D`, confirmation answers `y/n`).
|
|
33
|
+
- `logs`: Fast access to recent scrollback history.
|
|
34
|
+
- 🔌 **Seamless Background Daemon**:
|
|
35
|
+
- Communicates via Unix Domain Sockets (`~/.remote-cli/remote-cli.sock`).
|
|
36
|
+
- Transparently auto-starts in the background on demand.
|
|
37
|
+
- Safely detach (`Ctrl+]`) and re-attach (`remote-cli attach <session-id>`) anytime.
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Installation & Setup
|
|
42
|
+
|
|
43
|
+
Using [`uv`](https://github.com/astral-sh/uv):
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
# Clone the repository
|
|
47
|
+
git clone https://github.com/your-username/remote-cli.git
|
|
48
|
+
cd remote-cli
|
|
49
|
+
|
|
50
|
+
# Install dependencies and create venv
|
|
51
|
+
uv sync
|
|
52
|
+
|
|
53
|
+
# Run directly via uv
|
|
54
|
+
uv run remote-cli --help
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## Quickstart & Workflow
|
|
60
|
+
|
|
61
|
+
### 1. Human Starts SSH Session
|
|
62
|
+
The user initiates the SSH connection to the remote machine. Once connected and authenticated, a `Session ID` is displayed:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
uv run remote-cli ssh user@server.example.com
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Output:
|
|
69
|
+
```text
|
|
70
|
+
╭────────────────────── remote-cli SSH Session ──────────────────────╮
|
|
71
|
+
│ Session Created: s_7f8a9b2c │
|
|
72
|
+
│ Agent Command: remote-cli exec s_7f8a9b2c "<command>" │
|
|
73
|
+
│ Press Ctrl+] to detach from session at any time. │
|
|
74
|
+
╰────────────────────────────────────────────────────────────────────╯
|
|
75
|
+
user@server.example.com's password: ***
|
|
76
|
+
user@server:~$ _
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
> **Tip**: You can also create local shell sessions for testing:
|
|
80
|
+
> ```bash
|
|
81
|
+
> uv run remote-cli session create --name my-session -- /bin/bash
|
|
82
|
+
> ```
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
### 2. Share `session-id` with AI Agent
|
|
87
|
+
|
|
88
|
+
Simply tell your AI Agent:
|
|
89
|
+
> *"I have logged into the server. The session ID is `s_7f8a9b2c`. Please check the disk space and restart Nginx."*
|
|
90
|
+
|
|
91
|
+
The Agent can now execute commands on the remote server via `remote-cli`:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
# Agent runs a command and captures return code and stdout
|
|
95
|
+
uv run remote-cli exec s_7f8a9b2c "df -h"
|
|
96
|
+
|
|
97
|
+
# Agent runs a command with JSON output
|
|
98
|
+
uv run remote-cli exec s_7f8a9b2c "systemctl status nginx" --json
|
|
99
|
+
|
|
100
|
+
# Agent inspects the current 2D screen state
|
|
101
|
+
uv run remote-cli snapshot s_7f8a9b2c
|
|
102
|
+
|
|
103
|
+
# Agent sends an interactive response (e.g. confirming a prompt)
|
|
104
|
+
uv run remote-cli send s_7f8a9b2c "y"
|
|
105
|
+
|
|
106
|
+
# Agent sends Ctrl+C to interrupt a long-running process
|
|
107
|
+
uv run remote-cli send s_7f8a9b2c --ctrl-c
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
### 3. Human Observation & Intervention
|
|
113
|
+
|
|
114
|
+
While the Agent is executing commands, the human user sees all command text and outputs scrolling in real time in their terminal window. If needed, the human can type commands directly into that same terminal window.
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## CLI Command Reference
|
|
119
|
+
|
|
120
|
+
| Command | Description |
|
|
121
|
+
| :--- | :--- |
|
|
122
|
+
| `remote-cli ssh [SSH_ARGS...]` | Start SSH session, print Session ID, and attach immediately |
|
|
123
|
+
| `remote-cli session create [-d] [-- <CMD...>]` | Create a new session (default: `/bin/bash`) |
|
|
124
|
+
| `remote-cli session list` (or `ls`) | List all active and recent sessions |
|
|
125
|
+
| `remote-cli session attach <ID>` (or `attach`) | Attach terminal in raw mode to existing session |
|
|
126
|
+
| `remote-cli session close <ID>` | Close and terminate a session |
|
|
127
|
+
| `remote-cli exec <ID> "<COMMAND>"` | Execute command in session, capture output & exit code |
|
|
128
|
+
| `remote-cli send <ID> [TEXT]` | Send raw keystrokes or control keys (`--ctrl-c`, `--ctrl-d`) |
|
|
129
|
+
| `remote-cli snapshot <ID>` | Capture 2D terminal screen state (ANSI-rendered) |
|
|
130
|
+
| `remote-cli logs <ID> [-n LINES]` | View recent output scrollback logs |
|
|
131
|
+
| `remote-cli daemon start / stop / status` | Manage background daemon lifecycle |
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Architecture
|
|
136
|
+
|
|
137
|
+
```text
|
|
138
|
+
┌─────────────────────────┐ ┌───────────────────────────┐
|
|
139
|
+
│ Human User Terminal │ │ AI Agent / Script │
|
|
140
|
+
│ (Raw Mode) │ │ (remote-cli exec/snapshot)│
|
|
141
|
+
└────────────┬────────────┘ └─────────────┬─────────────┘
|
|
142
|
+
│ │
|
|
143
|
+
│ Attach (Stdin/Stdout stream) │ JSON Request/Response
|
|
144
|
+
▼ ▼
|
|
145
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
146
|
+
│ remote-cli Daemon Process │
|
|
147
|
+
│ (Unix Domain Socket: ~/.remote-cli/remote-cli.sock) │
|
|
148
|
+
│ │
|
|
149
|
+
│ ┌────────────────────────────────────────────────────────┐ │
|
|
150
|
+
│ │ Session (e.g. s_7f8a9b2c) │ │
|
|
151
|
+
│ │ - Master/Slave PTY (`pty.openpty`) │ │
|
|
152
|
+
│ │ - Pyte Virtual Terminal Screen (`pyte.HistoryScreen`) │ │
|
|
153
|
+
│ │ - Scrollback Ring Buffer │ │
|
|
154
|
+
│ │ - Exec Sentinel Detection Engine │ │
|
|
155
|
+
│ │ - Process: `ssh user@remote-server` (or local shell) │ │
|
|
156
|
+
│ └────────────────────────────────────────────────────────┘ │
|
|
157
|
+
└─────────────────────────────────────────────────────────────┘
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Running Tests
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
uv run pytest -v
|
|
166
|
+
```
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# remote-cli
|
|
2
|
+
|
|
3
|
+
> **Shared SSH & Terminal CLI tool for AI Agent and Human Co-piloting.**
|
|
4
|
+
|
|
5
|
+
`remote-cli` allows a human user to start an interactive SSH session (handling passwords, 2FA, bastion hosts, and SSH keys themselves) and share that session with an AI Agent via a unique `session-id`.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Key Features
|
|
10
|
+
|
|
11
|
+
- 🤝 **Real-Time Human & Agent Co-piloting**:
|
|
12
|
+
- The human sees everything the Agent does in their original terminal window in real-time.
|
|
13
|
+
- The human can continue typing and operating in the same session at any time.
|
|
14
|
+
- ⚡ **Zero External Binary Dependencies**:
|
|
15
|
+
- Pure Python + POSIX PTY (`pty.openpty`, `termios`, `tty`).
|
|
16
|
+
- No need to install `tmux` or `screen` on local or remote servers.
|
|
17
|
+
- 🤖 **First-Class AI Agent Support**:
|
|
18
|
+
- `exec`: Structured execution of shell commands with stdout capture and return codes.
|
|
19
|
+
- `snapshot`: In-memory 2D virtual terminal rendering (`pyte`) for clean screen capture (even for ncurses / curses / colored prompts).
|
|
20
|
+
- `send`: Keystrokes and control signals (`Ctrl+C`, `Ctrl+D`, confirmation answers `y/n`).
|
|
21
|
+
- `logs`: Fast access to recent scrollback history.
|
|
22
|
+
- 🔌 **Seamless Background Daemon**:
|
|
23
|
+
- Communicates via Unix Domain Sockets (`~/.remote-cli/remote-cli.sock`).
|
|
24
|
+
- Transparently auto-starts in the background on demand.
|
|
25
|
+
- Safely detach (`Ctrl+]`) and re-attach (`remote-cli attach <session-id>`) anytime.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Installation & Setup
|
|
30
|
+
|
|
31
|
+
Using [`uv`](https://github.com/astral-sh/uv):
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
# Clone the repository
|
|
35
|
+
git clone https://github.com/your-username/remote-cli.git
|
|
36
|
+
cd remote-cli
|
|
37
|
+
|
|
38
|
+
# Install dependencies and create venv
|
|
39
|
+
uv sync
|
|
40
|
+
|
|
41
|
+
# Run directly via uv
|
|
42
|
+
uv run remote-cli --help
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Quickstart & Workflow
|
|
48
|
+
|
|
49
|
+
### 1. Human Starts SSH Session
|
|
50
|
+
The user initiates the SSH connection to the remote machine. Once connected and authenticated, a `Session ID` is displayed:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
uv run remote-cli ssh user@server.example.com
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Output:
|
|
57
|
+
```text
|
|
58
|
+
╭────────────────────── remote-cli SSH Session ──────────────────────╮
|
|
59
|
+
│ Session Created: s_7f8a9b2c │
|
|
60
|
+
│ Agent Command: remote-cli exec s_7f8a9b2c "<command>" │
|
|
61
|
+
│ Press Ctrl+] to detach from session at any time. │
|
|
62
|
+
╰────────────────────────────────────────────────────────────────────╯
|
|
63
|
+
user@server.example.com's password: ***
|
|
64
|
+
user@server:~$ _
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
> **Tip**: You can also create local shell sessions for testing:
|
|
68
|
+
> ```bash
|
|
69
|
+
> uv run remote-cli session create --name my-session -- /bin/bash
|
|
70
|
+
> ```
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
### 2. Share `session-id` with AI Agent
|
|
75
|
+
|
|
76
|
+
Simply tell your AI Agent:
|
|
77
|
+
> *"I have logged into the server. The session ID is `s_7f8a9b2c`. Please check the disk space and restart Nginx."*
|
|
78
|
+
|
|
79
|
+
The Agent can now execute commands on the remote server via `remote-cli`:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
# Agent runs a command and captures return code and stdout
|
|
83
|
+
uv run remote-cli exec s_7f8a9b2c "df -h"
|
|
84
|
+
|
|
85
|
+
# Agent runs a command with JSON output
|
|
86
|
+
uv run remote-cli exec s_7f8a9b2c "systemctl status nginx" --json
|
|
87
|
+
|
|
88
|
+
# Agent inspects the current 2D screen state
|
|
89
|
+
uv run remote-cli snapshot s_7f8a9b2c
|
|
90
|
+
|
|
91
|
+
# Agent sends an interactive response (e.g. confirming a prompt)
|
|
92
|
+
uv run remote-cli send s_7f8a9b2c "y"
|
|
93
|
+
|
|
94
|
+
# Agent sends Ctrl+C to interrupt a long-running process
|
|
95
|
+
uv run remote-cli send s_7f8a9b2c --ctrl-c
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
### 3. Human Observation & Intervention
|
|
101
|
+
|
|
102
|
+
While the Agent is executing commands, the human user sees all command text and outputs scrolling in real time in their terminal window. If needed, the human can type commands directly into that same terminal window.
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## CLI Command Reference
|
|
107
|
+
|
|
108
|
+
| Command | Description |
|
|
109
|
+
| :--- | :--- |
|
|
110
|
+
| `remote-cli ssh [SSH_ARGS...]` | Start SSH session, print Session ID, and attach immediately |
|
|
111
|
+
| `remote-cli session create [-d] [-- <CMD...>]` | Create a new session (default: `/bin/bash`) |
|
|
112
|
+
| `remote-cli session list` (or `ls`) | List all active and recent sessions |
|
|
113
|
+
| `remote-cli session attach <ID>` (or `attach`) | Attach terminal in raw mode to existing session |
|
|
114
|
+
| `remote-cli session close <ID>` | Close and terminate a session |
|
|
115
|
+
| `remote-cli exec <ID> "<COMMAND>"` | Execute command in session, capture output & exit code |
|
|
116
|
+
| `remote-cli send <ID> [TEXT]` | Send raw keystrokes or control keys (`--ctrl-c`, `--ctrl-d`) |
|
|
117
|
+
| `remote-cli snapshot <ID>` | Capture 2D terminal screen state (ANSI-rendered) |
|
|
118
|
+
| `remote-cli logs <ID> [-n LINES]` | View recent output scrollback logs |
|
|
119
|
+
| `remote-cli daemon start / stop / status` | Manage background daemon lifecycle |
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## Architecture
|
|
124
|
+
|
|
125
|
+
```text
|
|
126
|
+
┌─────────────────────────┐ ┌───────────────────────────┐
|
|
127
|
+
│ Human User Terminal │ │ AI Agent / Script │
|
|
128
|
+
│ (Raw Mode) │ │ (remote-cli exec/snapshot)│
|
|
129
|
+
└────────────┬────────────┘ └─────────────┬─────────────┘
|
|
130
|
+
│ │
|
|
131
|
+
│ Attach (Stdin/Stdout stream) │ JSON Request/Response
|
|
132
|
+
▼ ▼
|
|
133
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
134
|
+
│ remote-cli Daemon Process │
|
|
135
|
+
│ (Unix Domain Socket: ~/.remote-cli/remote-cli.sock) │
|
|
136
|
+
│ │
|
|
137
|
+
│ ┌────────────────────────────────────────────────────────┐ │
|
|
138
|
+
│ │ Session (e.g. s_7f8a9b2c) │ │
|
|
139
|
+
│ │ - Master/Slave PTY (`pty.openpty`) │ │
|
|
140
|
+
│ │ - Pyte Virtual Terminal Screen (`pyte.HistoryScreen`) │ │
|
|
141
|
+
│ │ - Scrollback Ring Buffer │ │
|
|
142
|
+
│ │ - Exec Sentinel Detection Engine │ │
|
|
143
|
+
│ │ - Process: `ssh user@remote-server` (or local shell) │ │
|
|
144
|
+
│ └────────────────────────────────────────────────────────┘ │
|
|
145
|
+
└─────────────────────────────────────────────────────────────┘
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## Running Tests
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
uv run pytest -v
|
|
154
|
+
```
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "remote-cli"
|
|
3
|
+
dynamic = ["version"]
|
|
4
|
+
description = "A shared SSH CLI tool for AI Agent and human co-piloting"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.12"
|
|
7
|
+
dependencies = [
|
|
8
|
+
"pydantic>=2.10.0",
|
|
9
|
+
"pyte>=0.8.2",
|
|
10
|
+
"rich>=13.9.0",
|
|
11
|
+
"typer>=0.15.0",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
[project.scripts]
|
|
15
|
+
remote-cli = "remote_cli.cli:app"
|
|
16
|
+
|
|
17
|
+
[build-system]
|
|
18
|
+
requires = ["hatchling", "hatch-vcs"]
|
|
19
|
+
build-backend = "hatchling.build"
|
|
20
|
+
|
|
21
|
+
[tool.hatch.version]
|
|
22
|
+
source = "vcs"
|
|
23
|
+
|
|
24
|
+
[tool.hatch.build.hooks.vcs]
|
|
25
|
+
version-file = "src/remote_cli/_version.py"
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
[dependency-groups]
|
|
29
|
+
dev = [
|
|
30
|
+
"pytest>=8.0.0",
|
|
31
|
+
"pytest-asyncio>=0.24.0",
|
|
32
|
+
"ruff>=0.16.5",
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
[tool.pytest.ini_options]
|
|
36
|
+
asyncio_mode = "auto"
|
|
37
|
+
asyncio_default_fixture_loop_scope = "function"
|
|
38
|
+
|
|
39
|
+
[tool.ruff]
|
|
40
|
+
line-length = 100
|
|
41
|
+
target-version = "py312"
|
|
42
|
+
|
|
43
|
+
[tool.ruff.lint]
|
|
44
|
+
select = ["E", "F", "I", "W", "UP", "B"]
|
|
45
|
+
ignore = ["E501", "B008"]
|
|
46
|
+
|
|
47
|
+
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: remote-cli
|
|
3
|
+
description: >-
|
|
4
|
+
Operate shared remote SSH and terminal sessions with human co-pilots using remote-cli.
|
|
5
|
+
Use when the user provides a session ID to perform remote server operations, deployments,
|
|
6
|
+
debugging, inspecting terminal outputs, or sending inputs to active SSH sessions.
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Remote CLI Agent Skill (`remote-cli`)
|
|
10
|
+
|
|
11
|
+
`remote-cli` enables an AI Agent to co-pilot an active SSH or terminal session with a human user. The human logs into the server (handling passwords, 2FA, bastion hosts, and SSH keys) and provides a `session-id` to the Agent. The Agent can then execute commands, inspect terminal output, send keystrokes, and read screen state while the human observes the operations in real-time in their terminal window.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 1. Installation
|
|
16
|
+
|
|
17
|
+
If `remote-cli` is not already installed in the environment:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# Recommended installation via uv tool:
|
|
21
|
+
uv tool install remote-cli
|
|
22
|
+
|
|
23
|
+
# Or via pip:
|
|
24
|
+
pip install remote-cli
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
*(If running from local source repository during development: `uv run remote-cli ...`)*
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## 2. Typical Interaction Workflow
|
|
32
|
+
|
|
33
|
+
```text
|
|
34
|
+
1. User logs into remote server:
|
|
35
|
+
$ remote-cli ssh user@remote-host
|
|
36
|
+
-> Outputs Session ID: s_7f8a9b2c
|
|
37
|
+
|
|
38
|
+
2. User gives Session ID to Agent:
|
|
39
|
+
"I've logged in. The session ID is s_7f8a9b2c. Please check disk space and Docker containers."
|
|
40
|
+
|
|
41
|
+
3. Agent runs commands via remote-cli:
|
|
42
|
+
$ remote-cli exec s_7f8a9b2c "df -h"
|
|
43
|
+
$ remote-cli exec s_7f8a9b2c "docker ps"
|
|
44
|
+
|
|
45
|
+
4. Human sees output in real time in their terminal and can intervene anytime.
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## 3. Command Reference for Agents
|
|
51
|
+
|
|
52
|
+
### 3.1. Execute Commands (`remote-cli exec`)
|
|
53
|
+
|
|
54
|
+
Executes a command inside the remote shell, captures stdout, and returns the exit code.
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
# Standard execution (prints output; returns remote exit code)
|
|
58
|
+
remote-cli exec <session-id> "<command>"
|
|
59
|
+
|
|
60
|
+
# Example:
|
|
61
|
+
remote-cli exec s_7f8a9b2c "systemctl status nginx"
|
|
62
|
+
|
|
63
|
+
# Structured JSON output (returns JSON object with exit_code, output, duration, timed_out)
|
|
64
|
+
remote-cli exec s_7f8a9b2c "uname -a" --json
|
|
65
|
+
|
|
66
|
+
# Custom timeout (default: 30s)
|
|
67
|
+
remote-cli exec s_7f8a9b2c "sleep 5 && echo done" --timeout 60
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
> **JSON Output Format**:
|
|
71
|
+
> ```json
|
|
72
|
+
> {
|
|
73
|
+
> "session_id": "s_7f8a9b2c",
|
|
74
|
+
> "command": "uname -a",
|
|
75
|
+
> "exit_code": 0,
|
|
76
|
+
> "output": "Linux server 5.15.0-88-generic ...",
|
|
77
|
+
> "duration": 0.045,
|
|
78
|
+
> "timed_out": false
|
|
79
|
+
> }
|
|
80
|
+
> ```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
### 3.2. Inspect 2D Screen Snapshot (`remote-cli snapshot`)
|
|
85
|
+
|
|
86
|
+
Captures the rendered 2D terminal screen state (ANSI escapes rendered into clean text lines).
|
|
87
|
+
Use this when you need to see what is currently visible on the user's screen (e.g. interactive prompts, curses/ncurses UIs, `top`, menus).
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
remote-cli snapshot <session-id>
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
### 3.3. Send Interactive Input & Control Keys (`remote-cli send`)
|
|
96
|
+
|
|
97
|
+
Sends raw text, keystrokes, or control characters into the active session. Useful when answering interactive prompts (like `y/n`, sudo password, confirmation dialogues) or interrupting long processes.
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
# Answer confirmation prompt (appends newline by default):
|
|
101
|
+
remote-cli send <session-id> "y"
|
|
102
|
+
|
|
103
|
+
# Send text without newline:
|
|
104
|
+
remote-cli send <session-id> "some-text" --no-newline
|
|
105
|
+
|
|
106
|
+
# Send Ctrl+C (SIGINT) to interrupt a process:
|
|
107
|
+
remote-cli send <session-id> --ctrl-c
|
|
108
|
+
|
|
109
|
+
# Send Ctrl+D (EOF):
|
|
110
|
+
remote-cli send <session-id> --ctrl-d
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
### 3.4. View Recent Scrollback Logs (`remote-cli logs`)
|
|
116
|
+
|
|
117
|
+
Retrieves the recent stream output buffer.
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
# Get last 100 lines (default)
|
|
121
|
+
remote-cli logs <session-id>
|
|
122
|
+
|
|
123
|
+
# Get last N lines
|
|
124
|
+
remote-cli logs <session-id> --lines 50
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
### 3.5. List Active Sessions (`remote-cli session list` / `remote-cli ls`)
|
|
130
|
+
|
|
131
|
+
Discovers active and recent sessions.
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
remote-cli ls
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## 4. Agent Guidelines & Best Practices
|
|
140
|
+
|
|
141
|
+
1. **Check Session Status**:
|
|
142
|
+
- If the user provided a session ID, you can verify it exists with `remote-cli ls` or directly execute a probe command like `remote-cli exec <session-id> "echo ok"`.
|
|
143
|
+
2. **Handle Exit Codes**:
|
|
144
|
+
- Always check the exit code. If `exit_code != 0`, analyze the error output before proceeding with dependent operations.
|
|
145
|
+
3. **Interactive Prompts**:
|
|
146
|
+
- If a command blocks or you suspect an interactive prompt (e.g., `Do you want to continue? [Y/n]`), use `remote-cli snapshot <session-id>` to read the screen, and then use `remote-cli send <session-id> "y"` to reply.
|
|
147
|
+
4. **Transparent Communication**:
|
|
148
|
+
- Inform the user of the operations you are performing. Remember that the user can see your commands and their outputs on their screen in real time!
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""remote-cli: Shared SSH CLI tool for AI Agent and human co-piloting."""
|
|
2
|
+
|
|
3
|
+
try:
|
|
4
|
+
from ._version import __version__, __version_tuple__
|
|
5
|
+
except ImportError:
|
|
6
|
+
try:
|
|
7
|
+
from importlib.metadata import version
|
|
8
|
+
|
|
9
|
+
__version__ = version("remote-cli")
|
|
10
|
+
__version_tuple__ = (0, 1, 0)
|
|
11
|
+
except Exception:
|
|
12
|
+
__version__ = "0.1.0"
|
|
13
|
+
__version_tuple__ = (0, 1, 0)
|
|
14
|
+
|
|
15
|
+
__all__ = ["__version__", "__version_tuple__"]
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# file generated by vcs-versioning
|
|
2
|
+
# don't change, don't track in version control
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
__all__ = [
|
|
6
|
+
"__version__",
|
|
7
|
+
"__version_tuple__",
|
|
8
|
+
"version",
|
|
9
|
+
"version_tuple",
|
|
10
|
+
"__commit_id__",
|
|
11
|
+
"commit_id",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
version: str
|
|
15
|
+
__version__: str
|
|
16
|
+
__version_tuple__: tuple[int | str, ...]
|
|
17
|
+
version_tuple: tuple[int | str, ...]
|
|
18
|
+
commit_id: str | None
|
|
19
|
+
__commit_id__: str | None
|
|
20
|
+
|
|
21
|
+
__version__ = version = '0.1.0'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 1, 0)
|
|
23
|
+
|
|
24
|
+
__commit_id__ = commit_id = None
|