gramit 0.2.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.
@@ -0,0 +1,56 @@
1
+ name: Release Pipeline
2
+
3
+ on:
4
+ release:
5
+ types: [created]
6
+
7
+ jobs:
8
+ test:
9
+ runs-on: ubuntu-latest
10
+ steps:
11
+ - name: Checkout repository
12
+ uses: actions/checkout@v4
13
+
14
+ - name: Set up Python
15
+ uses: actions/setup-python@v5
16
+ with:
17
+ python-version: "3.12"
18
+
19
+ - name: Install uv
20
+ run: curl -LsSf https://astral.sh/uv/install.sh | sh
21
+
22
+ - name: Install dependencies
23
+ run: uv sync --all-extras --all-groups --no-editable
24
+
25
+ - name: Run format check
26
+ run: uv run ruff check
27
+
28
+ - name: Run tests with coverage
29
+ run: uv run pytest --cov=gramit --cov-report=xml --cov-report=term
30
+
31
+ - name: Upload coverage to Codecov
32
+ uses: codecov/codecov-action@v4
33
+ with:
34
+ files: ./coverage.xml
35
+ fail_ci_if_error: false
36
+
37
+ publish-pypi:
38
+ needs: test
39
+ runs-on: ubuntu-latest
40
+ steps:
41
+ - name: Checkout repository
42
+ uses: actions/checkout@v4
43
+
44
+ - name: Set up Python
45
+ uses: actions/setup-python@v5
46
+ with:
47
+ python-version: "3.12"
48
+
49
+ - name: Install uv
50
+ run: curl -LsSf https://astral.sh/uv/install.sh | sh
51
+
52
+ - name: Build package
53
+ run: uv build
54
+
55
+ - name: Publish to PyPI
56
+ run: uv publish --token ${{ secrets.PYPI_TOKEN }}
@@ -0,0 +1,32 @@
1
+ name: Run Tests
2
+
3
+ on:
4
+ push:
5
+ branches: [ main ]
6
+ pull_request:
7
+ branches: [ main ]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+
13
+ steps:
14
+ - name: Checkout repository
15
+ uses: actions/checkout@v4
16
+
17
+ - name: Set up Python
18
+ uses: actions/setup-python@v5
19
+ with:
20
+ python-version: "3.12"
21
+
22
+ - name: Install uv
23
+ run: curl -LsSf https://astral.sh/uv/install.sh | sh
24
+
25
+ - name: Install dependencies
26
+ run: uv sync --all-extras --all-groups --no-editable
27
+
28
+ - name: Run format check
29
+ run: uv run ruff check
30
+
31
+ - name: Run tests with coverage
32
+ run: uv run pytest --cov=gramit --cov-report=xml --cov-report=term
@@ -0,0 +1,176 @@
1
+ # Created by https://www.toptal.com/developers/gitignore/api/python
2
+ # Edit at https://www.toptal.com/developers/gitignore?templates=python
3
+
4
+ ### Python ###
5
+ # Byte-compiled / optimized / DLL files
6
+ __pycache__/
7
+ *.py[cod]
8
+ *$py.class
9
+
10
+ # C extensions
11
+ *.so
12
+
13
+ # Distribution / packaging
14
+ .Python
15
+ build/
16
+ develop-eggs/
17
+ dist/
18
+ downloads/
19
+ eggs/
20
+ .eggs/
21
+ lib/
22
+ lib64/
23
+ parts/
24
+ sdist/
25
+ var/
26
+ wheels/
27
+ share/python-wheels/
28
+ *.egg-info/
29
+ .installed.cfg
30
+ *.egg
31
+ MANIFEST
32
+
33
+ # PyInstaller
34
+ # Usually these files are written by a python script from a template
35
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
36
+ *.manifest
37
+ *.spec
38
+
39
+ # Installer logs
40
+ pip-log.txt
41
+ pip-delete-this-directory.txt
42
+
43
+ # Unit test / coverage reports
44
+ htmlcov/
45
+ .tox/
46
+ .nox/
47
+ .coverage
48
+ .coverage.*
49
+ .cache
50
+ nosetests.xml
51
+ coverage.xml
52
+ *.cover
53
+ *.py,cover
54
+ .hypothesis/
55
+ .pytest_cache/
56
+ cover/
57
+
58
+ # Translations
59
+ *.mo
60
+ *.pot
61
+
62
+ # Django stuff:
63
+ *.log
64
+ local_settings.py
65
+ db.sqlite3
66
+ db.sqlite3-journal
67
+
68
+ # Flask stuff:
69
+ instance/
70
+ .webassets-cache
71
+
72
+ # Scrapy stuff:
73
+ .scrapy
74
+
75
+ # Sphinx documentation
76
+ docs/_build/
77
+
78
+ # PyBuilder
79
+ .pybuilder/
80
+ target/
81
+
82
+ # Jupyter Notebook
83
+ .ipynb_checkpoints
84
+
85
+ # IPython
86
+ profile_default/
87
+ ipython_config.py
88
+
89
+ # pyenv
90
+ # For a library or package, you might want to ignore these files since the code is
91
+ # intended to run in multiple environments; otherwise, check them in:
92
+ # .python-version
93
+
94
+ # pipenv
95
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
96
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
97
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
98
+ # install all needed dependencies.
99
+ #Pipfile.lock
100
+
101
+ # poetry
102
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
103
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
104
+ # commonly ignored for libraries.
105
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
106
+ #poetry.lock
107
+
108
+ # pdm
109
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
110
+ #pdm.lock
111
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
112
+ # in version control.
113
+ # https://pdm.fming.dev/#use-with-ide
114
+ .pdm.toml
115
+
116
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
117
+ __pypackages__/
118
+
119
+ # Celery stuff
120
+ celerybeat-schedule
121
+ celerybeat.pid
122
+
123
+ # SageMath parsed files
124
+ *.sage.py
125
+
126
+ # Environments
127
+ .env
128
+ .venv
129
+ env/
130
+ venv/
131
+ ENV/
132
+ env.bak/
133
+ venv.bak/
134
+
135
+ # Spyder project settings
136
+ .spyderproject
137
+ .spyproject
138
+
139
+ # Rope project settings
140
+ .ropeproject
141
+
142
+ # mkdocs documentation
143
+ /site
144
+
145
+ # mypy
146
+ .mypy_cache/
147
+ .dmypy.json
148
+ dmypy.json
149
+
150
+ # Pyre type checker
151
+ .pyre/
152
+
153
+ # pytype static type analyzer
154
+ .pytype/
155
+
156
+ # Cython debug symbols
157
+ cython_debug/
158
+
159
+ # PyCharm
160
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
161
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
162
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
163
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
164
+ #.idea/
165
+
166
+ ### Python Patch ###
167
+ # Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration
168
+ poetry.toml
169
+
170
+ # ruff
171
+ .ruff_cache/
172
+
173
+ # LSP config files
174
+ pyrightconfig.json
175
+
176
+ # End of https://www.toptal.com/developers/gitignore/api/python
@@ -0,0 +1 @@
1
+ 3.12
@@ -0,0 +1,53 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [v0.1.2]
9
+
10
+ ### Security
11
+ - Implemented rate-limiting and output trimming in `OutputRouter` and `AsyncDebouncer` to prevent memory exhaustion and respect Telegram's message size limits.
12
+ - Restricted local `.env` file permissions to owner-only (`600`) to protect sensitive tokens.
13
+ - Added a prominent security warning to `README.md` regarding the risks of remote command execution.
14
+
15
+ ### Added
16
+ - Added detailed installation instructions for `pip`, `pipx`, and `uv` to `README.md`.
17
+ - Added project descriptors (keywords, classifiers, and URLs) to `pyproject.toml` for better metadata and discoverability.
18
+
19
+ ### Fixed
20
+ - Corrected a missing f-string in `cli.py` logging.
21
+
22
+ ## [v0.0.1]
23
+
24
+ ### Fixed
25
+ - Ensured `Ctrl+C` triggers graceful shutdown by restructuring `try...except asyncio.CancelledError` block within `async with application:` in `cli.py`.
26
+ - Resolved `UnboundLocalError` for `shutdown_event` by moving its initialization to an earlier point in `cli.py`.
27
+ - Implemented graceful shutdown for `Ctrl+C` and `/quit` command by using `asyncio.Event` to signal shutdown and ensuring all components are properly terminated.
28
+ - Replaced `application.run_until_disconnected()` with `async with application:` and `await asyncio.Future()` for correct asynchronous Telegram bot lifecycle management in `cli.py`.
29
+ - Reverted temporary debugging changes in `cli.py` and `telegram.py` to restore intended application flow.
30
+ - Corrected `SyntaxError` in `src/gramit/telegram.py` related to an unmatched parenthesis.
31
+
32
+ ### Added
33
+ - Initial and goodbye messages sent to Telegram upon gramit startup/shutdown.
34
+ - `/quit` Telegram command to gracefully terminate the orchestrated process.
35
+ - `examples/reverse_echo.py` script for interactive testing.
36
+ - Console script `gramit` for easier execution.
37
+ - `--register` mode to easily find a user's chat ID.
38
+ - Support for `GRAMIT_CHAT_ID` environment variable as an alternative to `--chat-id`.
39
+ - Main application entrypoint (`cli.py`) to integrate all components.
40
+ - `InputRouter` to handle and authorize incoming Telegram messages.
41
+ - `OutputRouter` to process and send output in line-buffered mode.
42
+ - `AsyncDebouncer` utility to batch items after a period of inactivity.
43
+ - I/O handling (`read`/`write`) to the `Orchestrator`.
44
+ - `Orchestrator` class to manage child processes in a pseudo-terminal (PTY).
45
+ - Initial project structure with `uv`, `pytest`, and core directories.
46
+ - `GEMINI.md` with project development guidelines.
47
+ - `DESIGN.md` v2.1, a robust architectural plan for the application.
48
+ - `ROADMAP.md` detailing the phased implementation plan.
49
+ - `CHANGELOG.md` to track notable changes.
50
+ - `journal/` directory for detailed daily progress logs.
51
+
52
+ ### Changed
53
+ - Overhauled the initial system design to address critical security, dependency, and usability issues.
gramit-0.2.0/DESIGN.md ADDED
@@ -0,0 +1,81 @@
1
+ # Gramit: Architectural & System Design Document (v2.1)
2
+
3
+ ## 1. System Overview & Design Principles
4
+
5
+ Gramit is a secure, self-contained Python orchestrator that bridges a local, command-line application with a remote Telegram interface. It allows a single, authorized user to control and monitor any CLI process from their Telegram chat.
6
+
7
+ This design adheres to the following principles:
8
+
9
+ * **Security First:** The system is locked down by default. It requires explicit user authorization and uses secure methods for handling credentials.
10
+ * **Zero External Dependencies:** The application is a pure Python tool and does not require external binaries like `tmux`. This enhances portability and reduces complexity.
11
+ * **Remote-First Interaction:** The primary interface is Telegram. Simultaneous local terminal interaction is not supported, which eliminates input race conditions and simplifies the design.
12
+ * **Intelligent TUI Parsing:** It is designed to extract meaningful text from Terminal User Interfaces (TUIs), filtering out UI "chrome" like borders and control panels.
13
+
14
+ ## 2. Core Architecture
15
+
16
+ Gramit is built on `asyncio`. When launched, it starts a main orchestrator that runs the target command in a pseudo-terminal (PTY) and manages three core asynchronous components.
17
+
18
+ ![Gramit Architecture Diagram](https://i.imgur.com/9A7SO88.png)
19
+
20
+ ### 2.1. The PTY Orchestrator
21
+ This component replaces the `tmux` dependency.
22
+
23
+ * **Initialization:** On startup, the orchestrator uses `os.forkpty()` to create a new child process running inside a pseudo-terminal. This correctly allocates a PTY, ensuring that interactive applications (including TUIs) behave as expected.
24
+ * **Lifecycle Management:** The orchestrator owns the child process and the master file descriptor for the PTY. It is responsible for gracefully shutting down all components when the child process exits.
25
+
26
+ ### 2.2. The Input Router (Telegram → PTY)
27
+ This component handles incoming commands from Telegram.
28
+
29
+ * **Authorization:** It uses a Telegram bot library (e.g., `python-telegram-bot`) to listen for messages. It will **only** process messages from a single, pre-authorized `chat_id` provided at startup. All other messages are discarded.
30
+ * **Injection:** When an authorized message is received, its text content is written directly to the master PTY file descriptor, which passes it to the `stdin` of the running child process.
31
+
32
+ ### 2.3. The Output Router (PTY → Telegram)
33
+ This component intelligently captures, processes, and transmits output from the application back to the user. It operates in one of two modes.
34
+
35
+ #### 2.3.1. TUI Mode (Default)
36
+ This mode is designed for interactive applications like `htop`, `vim`, or other curses-based programs.
37
+
38
+ 1. **Virtual Screen:** The raw byte stream from the master PTY (which includes ANSI escape codes) is fed into an in-memory terminal emulator powered by the `pyte` library.
39
+ 2. **Stateful Rendering:** The `pyte` screen object processes the escape codes and maintains a complete, 2D grid representing the terminal's current visual state.
40
+ 3. **Snapshotting:** A debounced `asyncio` task runs at a configurable interval (e.g., every 2 seconds). In each interval, it dumps the current text content of the `pyte` screen.
41
+ 4. **Heuristic Filtering (Content Extraction):** Before transmission, the raw text snapshot is passed through a filtering pipeline to remove common TUI "chrome." This is a best-effort attempt to extract semantic content and includes:
42
+ * Removing lines that primarily consist of box-drawing characters (e.g., `│`, `─`, `┌`).
43
+ * Stripping common control and menu indicators (e.g., lines containing patterns like "F1 Help", "F10 Quit").
44
+ * Trimming leading/trailing whitespace from each line and removing empty lines from the top and bottom of the snapshot.
45
+ 5. **Transmission:** The **cleaned** text snapshot is wrapped in a Telegram markdown code block and sent using `editMessageText` to update a single, persistent "screen" message. If the snapshot exceeds Telegram's 4096-character limit, it is truncated with a warning.
46
+
47
+ #### 2.3.2. Line Mode (`--line-mode`)
48
+ This mode is for simple, non-interactive applications that produce a stream of log-like output.
49
+
50
+ 1. **Line Buffering:** The raw output from the PTY is decoded and buffered line by line.
51
+ 2. **Debounced Flush:** The debounced task flushes this buffer of lines.
52
+ 3. **Transmission:** The collected lines are joined and sent as one or more *new messages* using `sendMessage`. The router automatically handles splitting content across multiple messages if it exceeds the character limit.
53
+
54
+ ## 3. Security Model
55
+
56
+ The security of the system is paramount and is addressed through two key mechanisms.
57
+
58
+ ### 3.1. Credential Management
59
+ The Telegram Bot Token is treated as a sensitive secret.
60
+
61
+ * **Environment Variable:** The token **must** be provided via an environment variable (`GRAMIT_TELEGRAM_TOKEN`).
62
+ * **`.env` Support:** For ease of local development, the application will automatically load this variable from a `.env` file in the project root if it exists (using `python-dotenv`).
63
+ * The insecure `-t` command-line argument has been removed.
64
+
65
+ ### 3.2. Access Control
66
+ Access to the bot is strictly controlled.
67
+
68
+ * **Required `chat_id`:** The application requires a `--chat-id <ID>` argument on startup. This locks the bot to a specific user or group.
69
+ * **Helper Utility:** A small utility script will be provided (`gramit-get-chat-id`) to help users easily find their `chat_id`.
70
+
71
+ ## 4. Summary of Countermeasures
72
+
73
+ This revised design directly addresses the challenges of the initial proposal:
74
+
75
+ | Issue | Countermeasure |
76
+ | :--- | :--- |
77
+ | **TUI Incompatibility** | Replaced `tail -f` approach with a `pyte`-based virtual screen and added a heuristic filtering layer to extract meaningful content. |
78
+ | **`tmux` Dependency** | Eliminated `tmux` entirely by using Python's native `os.forkpty()` to manage the pseudo-terminal directly. |
79
+ | **Input Race Conditions** | Removed the "local attach" feature. By making Telegram the sole source of input, race conditions are impossible. |
80
+ | **Output Limits** | Implemented two distinct output modes (TUI and Line) with intelligent handling of message edits, new messages, and character limits. |
81
+ | **Security Flaws** | Enforced secure token handling via environment variables and mandated `chat_id` authorization to lock down the bot. |
gramit-0.2.0/GEMINI.md ADDED
@@ -0,0 +1,51 @@
1
+ # Gemini Project Guidelines
2
+
3
+ This document outlines the conventions and procedures to be followed by the Gemini agent for this project.
4
+
5
+ ## Core Workflow
6
+
7
+ A strict, iterative, and well-documented workflow must be followed for all projects. This ensures the project history is clear and documentation stays current with the code.
8
+
9
+ The following files are central to this workflow and must be kept in sync with all development activities:
10
+
11
+ - **`ROADMAP.md`**: Outlines the high-level development plan. It should be updated as major phases or tasks are completed.
12
+ - **`CHANGELOG.md`**: Contains a user-facing summary of notable changes. An entry should be added for every significant feature, fix, or improvement.
13
+ - **`journal/`**: A directory containing detailed, chronological logs of all actions, thoughts, and decisions made during development, with one file per day (e.g., `journal/YYYY-MM-DD.md`).
14
+
15
+ The development process is as follows:
16
+
17
+ 1. **Iterate Step-by-Step**: Work in small, incremental steps, following the project's specific development methodology.
18
+ 2. **Document as You Go**: After each step, immediately update all relevant documentation (`ROADMAP.md`, `CHANGELOG.md`, `journal/`).
19
+ 3. **Commit Often**: After each meaningful and atomic change (including its documentation), create a commit with a clear message.
20
+
21
+ ---
22
+
23
+ ## Project-Specific Guidelines
24
+
25
+ This section details the specific tooling and methodologies for the **gramit** project.
26
+
27
+ ### Project Overview
28
+ This is a Python 3.12 project.
29
+
30
+ ### Environment and Dependency Management
31
+ - **Tooling:** We will use `uv` for all environment and package management tasks.
32
+ - **Running commands:** Any scripts or commands should be executed within the `uv` environment using `uv run`. For example: `uv run python my_script.py` or `uv run pytest`.
33
+ - **Adding dependencies:** Dependencies must be added using `uv add <package_name>`. For dev-only dependencies, use `uv add --dev <package_name>`.
34
+ - **Dependency file:** Do not manually edit the `dependencies` or `dev-dependencies` sections in `pyproject.toml`.
35
+
36
+ ### Development Methodology
37
+ - **Test-Driven Development (TDD):** We will strictly follow TDD.
38
+ 1. Write a failing test that clearly defines the desired functionality.
39
+ 2. Run the test to confirm that it fails as expected.
40
+ 3. Write the minimum amount of code necessary to make the test pass.
41
+ 4. Run all tests to confirm they all pass.
42
+ 5. Refactor the code as needed, ensuring tests continue to pass.
43
+
44
+ ---
45
+
46
+ ## General Coding Standards
47
+
48
+ ### Documentation and Commenting
49
+ - **Public Functions:** All public functions must have clear and comprehensive docstrings explaining their purpose, arguments, and return values.
50
+ - **Inline Comments:** Avoid unnecessary inline comments. Code should be as self-documenting as possible.
51
+ - **Comment Style:** When comments are necessary, they should explain the *why* (the logic or reasoning) behind a piece of code, not the *what* (the implementation details).
gramit-0.2.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Alejandro Piad
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.
gramit-0.2.0/PKG-INFO ADDED
@@ -0,0 +1,137 @@
1
+ Metadata-Version: 2.4
2
+ Name: gramit
3
+ Version: 0.2.0
4
+ Summary: A tool to bridge local CLI applications with a remote Telegram interface.
5
+ Project-URL: Homepage, https://github.com/apiad/gramit
6
+ Project-URL: Repository, https://github.com/apiad/gramit
7
+ Project-URL: Issues, https://github.com/apiad/gramit/issues
8
+ Project-URL: Changelog, https://github.com/apiad/gramit/blob/main/CHANGELOG.md
9
+ Author-email: Alejandro Piad <alepiad@gmail.com>
10
+ License: MIT
11
+ License-File: LICENSE
12
+ Keywords: bridge,cli,remote-control,telegram,terminal
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Environment :: Console
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Intended Audience :: System Administrators
17
+ Classifier: License :: OSI Approved :: MIT License
18
+ Classifier: Operating System :: POSIX :: Linux
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: Communications :: Chat
21
+ Classifier: Topic :: System :: Systems Administration
22
+ Classifier: Topic :: Utilities
23
+ Requires-Python: >=3.12
24
+ Requires-Dist: pyte>=0.8.2
25
+ Requires-Dist: python-dotenv>=1.2.1
26
+ Requires-Dist: python-telegram-bot>=22.6
27
+ Description-Content-Type: text/markdown
28
+
29
+ # Gramit
30
+
31
+ [![Run Tests](https://github.com/apiad/gramit/actions/workflows/tests.yaml/badge.svg)](https://github.com/apiad/gramit/actions/workflows/tests.yaml)
32
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
33
+ [![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue.svg)](https://www.python.org/downloads/release/python-3120/)
34
+
35
+ > [!CAUTION]
36
+ > **SECURITY WARNING: REMOTE ACCESS RISK**
37
+ >
38
+ > Gramit provides a bridge between your local machine and a remote Telegram interface. **This allows remote command execution.**
39
+ >
40
+ > If you run a shell (like `/bin/bash` or `cmd.exe`) or any interactive tool through Gramit, anyone with access to your Telegram bot (and whose Chat ID is authorized) has **full control over your machine**.
41
+ >
42
+ > **USE ONLY IF YOU ARE HIGHLY SECURITY-AWARE.**
43
+ > - Never share your `GRAMIT_TELEGRAM_TOKEN`.
44
+ > - Ensure your `GRAMIT_CHAT_ID` is correctly configured to *your* ID only.
45
+ > - Be extremely cautious when bridging shells or administrative tools.
46
+
47
+ Gramit bridges a local CLI application with a remote Telegram interface. It allows you to run any long-running command on your machine and interact with it from anywhere using Telegram. While designed to be generic for any CLI, it's particularly useful for interactive AI CLIs like **Gemini CLI**, **Claude Code**, or similar tools where you want to maintain a persistent session and interact remotely.
48
+
49
+ ## How it Works
50
+
51
+ Gramit acts as a conduit between your local command-line application and your Telegram bot.
52
+ - **Input Redirection:** Any message you send to your Telegram bot is piped directly to the `stdin` of the running local command.
53
+ - **Output Capture:** All `stdout` from your local command is captured and sent back to you as a Telegram message.
54
+ - **Session Management:** It maintains a persistent session, allowing for continuous interaction with your CLI application.
55
+
56
+ ## Setup
57
+
58
+ 1. **Installation**
59
+
60
+ You can install Gramit using your favorite Python package manager:
61
+
62
+ **Using `pip`:**
63
+ ```sh
64
+ pip install gramit
65
+ ```
66
+
67
+ **Using `pipx` (Recommended for CLI tools):**
68
+ ```sh
69
+ pipx install gramit
70
+ ```
71
+
72
+ **Using `uv`:**
73
+ ```sh
74
+ # Run without installing
75
+ uvx gramit --help
76
+
77
+ # Or install as a tool
78
+ uv tool install gramit
79
+ ```
80
+
81
+ 2. **Get a Telegram Bot Token**
82
+ - Talk to the [@BotFather](https://t.me/BotFather) on Telegram.
83
+ - Create a new bot and copy the token it gives you.
84
+
85
+ 3. **Set Environment Variables**
86
+ - Create a file named `.env` in the project root.
87
+ - Add the following line to it, replacing `YOUR_TOKEN_HERE` with the token you just got:
88
+ ```
89
+ GRAMIT_TELEGRAM_TOKEN="YOUR_TOKEN_HERE"
90
+ ```
91
+ - You can also optionally add your Chat ID to this file (see step 4):
92
+ ```
93
+ GRAMIT_CHAT_ID="YOUR_CHAT_ID_HERE"
94
+ ```
95
+
96
+ 4. **Find Your Chat ID**
97
+ - The easiest way to find your chat ID is to use Gramit's built-in registration mode. Run the following command:
98
+ ```sh
99
+ gramit --register
100
+ ```
101
+ - Now, send any message to your bot on Telegram. Gramit will print your Chat ID to the console and also reply with it.
102
+ - Once you have your ID, you can stop the command (`Ctrl_C`).
103
+
104
+ ## Usage
105
+
106
+ Run `gramit` with your command. If you have not set `GRAMIT_CHAT_ID` in your `.env` file, you must also provide the `--chat-id` argument.
107
+
108
+ **Basic Example:**
109
+ ```sh
110
+ # If GRAMIT_CHAT_ID is set in .env
111
+ gramit ping 8.8.8.8
112
+
113
+ # If GRAMIT_CHAT_ID is NOT set
114
+ gramit --chat-id YOUR_CHAT_ID ping 8.8.8.8
115
+ ```
116
+
117
+ - Any text you send to your bot on Telegram will be piped to the `stdin` of the running command.
118
+ - Any `stdout` from the command will be sent back to you as a Telegram message.
119
+
120
+ **Interactive Example (Reverse Echo):**
121
+ ```sh
122
+ gramit python examples/reverse_echo.py
123
+ ```
124
+ Then, send messages to your bot on Telegram. It will echo them back in reverse.
125
+
126
+ **Features:**
127
+ - Upon starting, Gramit sends an initial message to Telegram indicating the command being run.
128
+ - When the orchestrated process ends, a "goodbye" message is sent to Telegram.
129
+ - Send `/quit` to your bot to gracefully terminate the running command from Telegram.
130
+
131
+ ## License
132
+
133
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
134
+
135
+ ## Contributions
136
+
137
+ Contributions are welcome! If you have suggestions for improvements, new features, or bug fixes, please open an issue or submit a pull request.