telegram-assistant 0.2.1__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 (92) hide show
  1. telegram_assistant-0.2.1/LICENSE +21 -0
  2. telegram_assistant-0.2.1/PKG-INFO +201 -0
  3. telegram_assistant-0.2.1/README.md +162 -0
  4. telegram_assistant-0.2.1/pyproject.toml +92 -0
  5. telegram_assistant-0.2.1/setup.cfg +4 -0
  6. telegram_assistant-0.2.1/src/telegram_assistant/__init__.py +3 -0
  7. telegram_assistant-0.2.1/src/telegram_assistant/cli/__init__.py +5 -0
  8. telegram_assistant-0.2.1/src/telegram_assistant/cli/main.py +3164 -0
  9. telegram_assistant-0.2.1/src/telegram_assistant/config/__init__.py +33 -0
  10. telegram_assistant-0.2.1/src/telegram_assistant/config/loader.py +139 -0
  11. telegram_assistant-0.2.1/src/telegram_assistant/config/models.py +190 -0
  12. telegram_assistant-0.2.1/src/telegram_assistant/domain/__init__.py +1 -0
  13. telegram_assistant-0.2.1/src/telegram_assistant/folders/__init__.py +37 -0
  14. telegram_assistant-0.2.1/src/telegram_assistant/folders/service.py +229 -0
  15. telegram_assistant-0.2.1/src/telegram_assistant/folders/telethon_backend.py +128 -0
  16. telegram_assistant-0.2.1/src/telegram_assistant/groups/__init__.py +37 -0
  17. telegram_assistant-0.2.1/src/telegram_assistant/groups/service.py +731 -0
  18. telegram_assistant-0.2.1/src/telegram_assistant/groups/telethon_backend.py +299 -0
  19. telegram_assistant-0.2.1/src/telegram_assistant/health.py +202 -0
  20. telegram_assistant-0.2.1/src/telegram_assistant/http_api/__init__.py +5 -0
  21. telegram_assistant-0.2.1/src/telegram_assistant/http_api/app.py +333 -0
  22. telegram_assistant-0.2.1/src/telegram_assistant/http_api/auth.py +45 -0
  23. telegram_assistant-0.2.1/src/telegram_assistant/http_api/folders.py +133 -0
  24. telegram_assistant-0.2.1/src/telegram_assistant/http_api/groups.py +233 -0
  25. telegram_assistant-0.2.1/src/telegram_assistant/http_api/members.py +272 -0
  26. telegram_assistant-0.2.1/src/telegram_assistant/http_api/messages.py +296 -0
  27. telegram_assistant-0.2.1/src/telegram_assistant/http_api/topics.py +406 -0
  28. telegram_assistant-0.2.1/src/telegram_assistant/members/__init__.py +57 -0
  29. telegram_assistant-0.2.1/src/telegram_assistant/members/service.py +1071 -0
  30. telegram_assistant-0.2.1/src/telegram_assistant/members/telethon_backend.py +151 -0
  31. telegram_assistant-0.2.1/src/telegram_assistant/messages/__init__.py +33 -0
  32. telegram_assistant-0.2.1/src/telegram_assistant/messages/service.py +528 -0
  33. telegram_assistant-0.2.1/src/telegram_assistant/observability/__init__.py +43 -0
  34. telegram_assistant-0.2.1/src/telegram_assistant/observability/alerts.py +298 -0
  35. telegram_assistant-0.2.1/src/telegram_assistant/observability/factory.py +19 -0
  36. telegram_assistant-0.2.1/src/telegram_assistant/observability/logging.py +205 -0
  37. telegram_assistant-0.2.1/src/telegram_assistant/persistence/__init__.py +35 -0
  38. telegram_assistant-0.2.1/src/telegram_assistant/persistence/idempotency.py +98 -0
  39. telegram_assistant-0.2.1/src/telegram_assistant/persistence/models.py +86 -0
  40. telegram_assistant-0.2.1/src/telegram_assistant/persistence/schema.py +103 -0
  41. telegram_assistant-0.2.1/src/telegram_assistant/persistence/store.py +572 -0
  42. telegram_assistant-0.2.1/src/telegram_assistant/plugins/__init__.py +19 -0
  43. telegram_assistant-0.2.1/src/telegram_assistant/plugins/base.py +127 -0
  44. telegram_assistant-0.2.1/src/telegram_assistant/plugins/planfix.py +182 -0
  45. telegram_assistant-0.2.1/src/telegram_assistant/telegram_client/__init__.py +27 -0
  46. telegram_assistant-0.2.1/src/telegram_assistant/telegram_client/errors.py +28 -0
  47. telegram_assistant-0.2.1/src/telegram_assistant/telegram_client/proxy.py +52 -0
  48. telegram_assistant-0.2.1/src/telegram_assistant/telegram_client/session.py +272 -0
  49. telegram_assistant-0.2.1/src/telegram_assistant/topics/__init__.py +59 -0
  50. telegram_assistant-0.2.1/src/telegram_assistant/topics/service.py +835 -0
  51. telegram_assistant-0.2.1/src/telegram_assistant/topics/telethon_backend.py +159 -0
  52. telegram_assistant-0.2.1/src/telegram_assistant/worker/__init__.py +19 -0
  53. telegram_assistant-0.2.1/src/telegram_assistant/worker/queue.py +221 -0
  54. telegram_assistant-0.2.1/src/telegram_assistant.egg-info/PKG-INFO +201 -0
  55. telegram_assistant-0.2.1/src/telegram_assistant.egg-info/SOURCES.txt +90 -0
  56. telegram_assistant-0.2.1/src/telegram_assistant.egg-info/dependency_links.txt +1 -0
  57. telegram_assistant-0.2.1/src/telegram_assistant.egg-info/entry_points.txt +2 -0
  58. telegram_assistant-0.2.1/src/telegram_assistant.egg-info/requires.txt +20 -0
  59. telegram_assistant-0.2.1/src/telegram_assistant.egg-info/top_level.txt +1 -0
  60. telegram_assistant-0.2.1/tests/test_app_skeleton.py +86 -0
  61. telegram_assistant-0.2.1/tests/test_cli_groups_layout.py +374 -0
  62. telegram_assistant-0.2.1/tests/test_cli_operations.py +251 -0
  63. telegram_assistant-0.2.1/tests/test_config_loader.py +405 -0
  64. telegram_assistant-0.2.1/tests/test_docker_image.py +120 -0
  65. telegram_assistant-0.2.1/tests/test_dry_run_contract.py +287 -0
  66. telegram_assistant-0.2.1/tests/test_dry_run_folders_operations.py +485 -0
  67. telegram_assistant-0.2.1/tests/test_dry_run_groups_topics.py +658 -0
  68. telegram_assistant-0.2.1/tests/test_dry_run_members_messages.py +896 -0
  69. telegram_assistant-0.2.1/tests/test_folders.py +592 -0
  70. telegram_assistant-0.2.1/tests/test_groups.py +1477 -0
  71. telegram_assistant-0.2.1/tests/test_groups_layout.py +558 -0
  72. telegram_assistant-0.2.1/tests/test_health.py +445 -0
  73. telegram_assistant-0.2.1/tests/test_http_groups_layout.py +381 -0
  74. telegram_assistant-0.2.1/tests/test_http_lifespan.py +165 -0
  75. telegram_assistant-0.2.1/tests/test_members.py +716 -0
  76. telegram_assistant-0.2.1/tests/test_members_remove.py +698 -0
  77. telegram_assistant-0.2.1/tests/test_messages.py +793 -0
  78. telegram_assistant-0.2.1/tests/test_observability_alerts.py +300 -0
  79. telegram_assistant-0.2.1/tests/test_observability_logging.py +151 -0
  80. telegram_assistant-0.2.1/tests/test_persistence.py +493 -0
  81. telegram_assistant-0.2.1/tests/test_plugins.py +238 -0
  82. telegram_assistant-0.2.1/tests/test_proxy.py +82 -0
  83. telegram_assistant-0.2.1/tests/test_skill_errors_scope.py +148 -0
  84. telegram_assistant-0.2.1/tests/test_skill_inventory.py +164 -0
  85. telegram_assistant-0.2.1/tests/test_skill_scenarios.py +202 -0
  86. telegram_assistant-0.2.1/tests/test_skill_structure.py +116 -0
  87. telegram_assistant-0.2.1/tests/test_telegram_client.py +351 -0
  88. telegram_assistant-0.2.1/tests/test_topics.py +577 -0
  89. telegram_assistant-0.2.1/tests/test_topics_bulk.py +780 -0
  90. telegram_assistant-0.2.1/tests/test_topics_close.py +519 -0
  91. telegram_assistant-0.2.1/tests/test_topics_telethon_backend.py +344 -0
  92. telegram_assistant-0.2.1/tests/test_worker_queue.py +393 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Stanislav Popov
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,201 @@
1
+ Metadata-Version: 2.4
2
+ Name: telegram-assistant
3
+ Version: 0.2.1
4
+ Summary: Telegram automation service (MTProto/Telethon) with an optional Planfix integration plugin.
5
+ Author-email: Stanislav Popov <popstas@gmail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/popstas/telegram-assistant
8
+ Project-URL: Repository, https://github.com/popstas/telegram-assistant
9
+ Project-URL: Bug Tracker, https://github.com/popstas/telegram-assistant/issues
10
+ Keywords: telegram,telethon,automation,mtproto,planfix
11
+ Classifier: Programming Language :: Python :: 3.12
12
+ Classifier: Framework :: FastAPI
13
+ Classifier: Topic :: Communications :: Chat
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Requires-Python: >=3.12
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE
19
+ Requires-Dist: telethon<2.0,>=1.36
20
+ Requires-Dist: fastapi<1.0,>=0.115
21
+ Requires-Dist: uvicorn[standard]<1.0,>=0.30
22
+ Requires-Dist: pydantic<3.0,>=2.7
23
+ Requires-Dist: pyyaml<7.0,>=6.0
24
+ Requires-Dist: typer<1.0,>=0.12
25
+ Requires-Dist: structlog<25.0,>=24.1
26
+ Requires-Dist: SQLAlchemy<3.0,>=2.0
27
+ Requires-Dist: httpx<1.0,>=0.27
28
+ Requires-Dist: python-socks[asyncio]<3.0,>=2.4
29
+ Provides-Extra: dev
30
+ Requires-Dist: pytest<9.0,>=8.0; extra == "dev"
31
+ Requires-Dist: pytest-asyncio<1.0,>=0.23; extra == "dev"
32
+ Requires-Dist: ruff<1.0,>=0.5; extra == "dev"
33
+ Requires-Dist: git-cliff>=2.0.0; extra == "dev"
34
+ Requires-Dist: pre-commit<5.0,>=3.7; extra == "dev"
35
+ Requires-Dist: build<2.0,>=1.2; extra == "dev"
36
+ Requires-Dist: twine<7.0,>=5.0; extra == "dev"
37
+ Requires-Dist: bump-my-version<1.0,>=0.28; extra == "dev"
38
+ Dynamic: license-file
39
+
40
+ # telegram-assistant
41
+
42
+ Telegram automation service for the Planfix ↔ Telegram integration.
43
+
44
+ Three interfaces share one domain layer:
45
+
46
+ - HTTP API (FastAPI) on port `8085` with bearer-token auth — primary entry point for Planfix and automations.
47
+ - CLI (`telegram-assistant`) — mirrors every HTTP endpoint plus admin commands (`auth`, `operations status`, `operations retry`).
48
+ - Worker/queue — performs Telegram operations with throttling and `FLOOD_WAIT` handling.
49
+
50
+ Runs on MTProto via Telethon under a technical Telegram user account.
51
+
52
+ ## Quick start
53
+
54
+ ```bash
55
+ python3.12 -m venv .venv
56
+ source .venv/bin/activate
57
+ pip install -e ".[dev]"
58
+
59
+ # Place a config file at data/config.yml (see Configuration below)
60
+ telegram-assistant auth # interactive Telethon login
61
+ telegram-assistant health # show current health
62
+ uvicorn telegram_assistant.http_api.app:create_app --factory --port 8085
63
+ ```
64
+
65
+ ## Commands
66
+
67
+ Every CLI subcommand maps 1:1 to an HTTP endpoint (except the admin-only commands `auth`, `operations status`, and `operations retry`). Run any command with `--help` for full flag documentation.
68
+
69
+ Top-level:
70
+
71
+ - `auth` — interactive Telethon login for the technical account.
72
+ - `health` — report service health (Telegram session, database, default folder).
73
+ - `version` — print the installed version.
74
+
75
+ `groups` — manage Telegram supergroups:
76
+
77
+ - `groups create` — create a Telegram supergroup for a Planfix client. Accepts `--topics-layout list|tabs` to pick the forum layout for this group (defaults to `telegram.defaults.topics_layout`).
78
+ - `groups set-layout` — set the topics layout (`list` vs `tabs`) for an existing forum chat.
79
+ - `groups get-layout` — read the current topics layout (`list` or `tabs`) for a forum chat.
80
+
81
+ `topics` — manage forum topics:
82
+
83
+ - `topics create` — create a single forum topic in an existing supergroup.
84
+ - `topics bulk-create` — bulk-create topics from a CSV or JSON file.
85
+ - `topics close` — close an existing forum topic (the topic and its history are kept).
86
+
87
+ `members` — manage group membership:
88
+
89
+ - `members bulk-add` — bulk-add members to an existing supergroup, optionally promoting to admin.
90
+ - `members bulk-remove` — bulk-remove members from a supergroup (kick or permanently ban).
91
+
92
+ `messages` — send messages and service commands:
93
+
94
+ - `messages send` — send a message or service command (targeted or folder-wide mass mode).
95
+
96
+ `folders` — inspect and manage chat folders:
97
+
98
+ - `folders inspect` — inspect a chat folder and list its chats.
99
+ - `folders add-chat` — move an existing chat into a folder.
100
+
101
+ `operations` — inspect and retry queued operations:
102
+
103
+ - `operations status` — show the status of an operation, including per-item summary.
104
+ - `operations retry` — reset a failed/`needs_review` operation (and its items) back to pending.
105
+
106
+ Updating this list: descriptions are sourced from each Typer command's docstring in `src/telegram_assistant/cli/main.py`. When you add or rename a command, update this section, `skills/telegram-assistant/SKILL.md`, and re-run `pytest tests/test_skill_inventory.py` — the inventory guard fails if the README/skill catalog drifts from the CLI.
107
+
108
+ ## Configuration
109
+
110
+ Config is read from `data/config.yml` by default. The `data/` directory is excluded from version control and holds the Telethon session, SQLite database, and secrets.
111
+
112
+ If `./data/config.yml` is absent, the loader falls back to `~/.config/telegram-assistant/config.yml`. On a clean machine, running any CLI command without `--config` will create a template at that path with `REPLACE_ME` placeholders for `api_id`, `api_hash`, and `bearer_token` — fill them in and re-run.
113
+
114
+ To reach Telegram through a proxy, set `telegram.proxy_url` to a single URL — supported schemes are `socks5`, `socks4`, `http`, and `https`. Credentials and explicit ports are optional:
115
+
116
+ ```yaml
117
+ telegram:
118
+ proxy_url: "socks5://user:pass@host:1080" # or http://host:8080, socks4://host, ...
119
+ ```
120
+
121
+ Leave it unset (or remove the line) to connect directly.
122
+
123
+ Defaults applied to new supergroups live under `telegram.defaults`:
124
+
125
+ ```yaml
126
+ telegram:
127
+ defaults:
128
+ enable_topics: true
129
+ create_invite_link: true
130
+ topics_layout: "list" # "list" | "tabs" — applied after groups create
131
+ default_member_permissions:
132
+ create_topics: true # let ordinary members create forum topics
133
+ pin_messages: true # let ordinary members pin messages
134
+ ```
135
+
136
+ `topics_layout` controls how the forum opens after `groups create`: `"list"` shows topics as a vertical list (Telegram's default), `"tabs"` shows them as horizontal tabs. The CLI `groups create --topics-layout` and `groups set-layout --layout` flags, and the `POST /telegram/groups` / `POST /telegram/groups/layout` bodies (`topics_layout`), override the default per call.
137
+
138
+ `default_member_permissions` sets the new group's default banned rights so ordinary members can `create_topics` and `pin_messages`. Other default rights are left untouched.
139
+
140
+ ### Idempotency anchor
141
+
142
+ Group/topic creation is idempotent on a generic `external_ref` (CLI `--external-ref`, HTTP `external_ref`). For backward compatibility the CLI `--planfix-task-id` flag and the HTTP `planfix_task_id` field are accepted as aliases that map onto `external_ref`. With no `external_ref`, groups key on the exact title and topics key on `chat_id + topic_name`.
143
+
144
+ ### Planfix plugin (optional, off by default)
145
+
146
+ Planfix-specific behavior lives behind an opt-in plugin. With it disabled the core has **zero Planfix knowledge** — `external_ref` still anchors idempotency, but there is no `/task <id>` service message, no `@planfix_bot` welcome cleanup, and `@planfix_bot` is not treated as a protected account. Enable it under `plugins`:
147
+
148
+ ```yaml
149
+ plugins:
150
+ planfix:
151
+ enabled: true # turn on Planfix-specific behavior
152
+ bot_username: "@planfix_bot" # group member that receives the /task command
153
+ group_title_postfix: "" # appended to the Telegram chat title at creation
154
+ cleanup_messages: false # delete welcome / /task / bot-reply after creation (opt-in)
155
+ task_reply_wait_seconds: 5 # how long to poll for the bot's /task reply
156
+ ```
157
+
158
+ When enabled and `external_ref` is set on a group whose members include `bot_username`, the plugin sends `/task <external_ref>` after creation. `group_title_postfix` is appended to the Telegram chat title at creation time but deliberately kept out of the idempotency key, so a replay of the same `external_ref` still matches on the raw title. `cleanup_messages` (default `false`) deletes the bot's welcome message, the `/task <id>` command, and the bot's reply to it; `task_reply_wait_seconds` is how long to poll for that reply before deleting only the welcome + command. All cleanup is best-effort: failures are recorded in the operation's `skipped` list and never fail the create.
159
+
160
+ See `docs/plans/20260518-telegram-assistant-mvp.md` for the full configuration schema and feature scope.
161
+
162
+ ## Docker
163
+
164
+ The service ships as a slim Python 3.12 image. Runtime state (Telethon session, SQLite database, `data/config.yml`, bearer token) lives in `/data`, which must be mounted as a volume — nothing sensitive is baked into the image.
165
+
166
+ Build and run with `docker compose`:
167
+
168
+ ```bash
169
+ mkdir -p data
170
+ cp path/to/your/config.yml data/config.yml # fill in api_id, api_hash, bearer_token, etc.
171
+ docker compose up -d
172
+ curl http://127.0.0.1:8085/health
173
+ ```
174
+
175
+ Run a one-shot CLI invocation against the same volume:
176
+
177
+ ```bash
178
+ docker compose run --rm telegram-assistant \
179
+ telegram-assistant health
180
+ ```
181
+
182
+ The `auth` CLI is interactive (it prompts for phone, code, and optional 2FA password), so run it with a TTY attached:
183
+
184
+ ```bash
185
+ docker compose run --rm -it telegram-assistant \
186
+ telegram-assistant auth
187
+ ```
188
+
189
+ The Telethon session is written to `/data` and persists across container restarts.
190
+
191
+ A self-contained smoke script lives at `scripts/docker-smoke.sh`. It builds the image, starts a throwaway container with a temporary `data/config.yml`, polls `GET /health` until it returns `200`, and tears everything down.
192
+
193
+ ```bash
194
+ bash scripts/docker-smoke.sh
195
+ ```
196
+
197
+ ## Tests
198
+
199
+ ```bash
200
+ pytest
201
+ ```
@@ -0,0 +1,162 @@
1
+ # telegram-assistant
2
+
3
+ Telegram automation service for the Planfix ↔ Telegram integration.
4
+
5
+ Three interfaces share one domain layer:
6
+
7
+ - HTTP API (FastAPI) on port `8085` with bearer-token auth — primary entry point for Planfix and automations.
8
+ - CLI (`telegram-assistant`) — mirrors every HTTP endpoint plus admin commands (`auth`, `operations status`, `operations retry`).
9
+ - Worker/queue — performs Telegram operations with throttling and `FLOOD_WAIT` handling.
10
+
11
+ Runs on MTProto via Telethon under a technical Telegram user account.
12
+
13
+ ## Quick start
14
+
15
+ ```bash
16
+ python3.12 -m venv .venv
17
+ source .venv/bin/activate
18
+ pip install -e ".[dev]"
19
+
20
+ # Place a config file at data/config.yml (see Configuration below)
21
+ telegram-assistant auth # interactive Telethon login
22
+ telegram-assistant health # show current health
23
+ uvicorn telegram_assistant.http_api.app:create_app --factory --port 8085
24
+ ```
25
+
26
+ ## Commands
27
+
28
+ Every CLI subcommand maps 1:1 to an HTTP endpoint (except the admin-only commands `auth`, `operations status`, and `operations retry`). Run any command with `--help` for full flag documentation.
29
+
30
+ Top-level:
31
+
32
+ - `auth` — interactive Telethon login for the technical account.
33
+ - `health` — report service health (Telegram session, database, default folder).
34
+ - `version` — print the installed version.
35
+
36
+ `groups` — manage Telegram supergroups:
37
+
38
+ - `groups create` — create a Telegram supergroup for a Planfix client. Accepts `--topics-layout list|tabs` to pick the forum layout for this group (defaults to `telegram.defaults.topics_layout`).
39
+ - `groups set-layout` — set the topics layout (`list` vs `tabs`) for an existing forum chat.
40
+ - `groups get-layout` — read the current topics layout (`list` or `tabs`) for a forum chat.
41
+
42
+ `topics` — manage forum topics:
43
+
44
+ - `topics create` — create a single forum topic in an existing supergroup.
45
+ - `topics bulk-create` — bulk-create topics from a CSV or JSON file.
46
+ - `topics close` — close an existing forum topic (the topic and its history are kept).
47
+
48
+ `members` — manage group membership:
49
+
50
+ - `members bulk-add` — bulk-add members to an existing supergroup, optionally promoting to admin.
51
+ - `members bulk-remove` — bulk-remove members from a supergroup (kick or permanently ban).
52
+
53
+ `messages` — send messages and service commands:
54
+
55
+ - `messages send` — send a message or service command (targeted or folder-wide mass mode).
56
+
57
+ `folders` — inspect and manage chat folders:
58
+
59
+ - `folders inspect` — inspect a chat folder and list its chats.
60
+ - `folders add-chat` — move an existing chat into a folder.
61
+
62
+ `operations` — inspect and retry queued operations:
63
+
64
+ - `operations status` — show the status of an operation, including per-item summary.
65
+ - `operations retry` — reset a failed/`needs_review` operation (and its items) back to pending.
66
+
67
+ Updating this list: descriptions are sourced from each Typer command's docstring in `src/telegram_assistant/cli/main.py`. When you add or rename a command, update this section, `skills/telegram-assistant/SKILL.md`, and re-run `pytest tests/test_skill_inventory.py` — the inventory guard fails if the README/skill catalog drifts from the CLI.
68
+
69
+ ## Configuration
70
+
71
+ Config is read from `data/config.yml` by default. The `data/` directory is excluded from version control and holds the Telethon session, SQLite database, and secrets.
72
+
73
+ If `./data/config.yml` is absent, the loader falls back to `~/.config/telegram-assistant/config.yml`. On a clean machine, running any CLI command without `--config` will create a template at that path with `REPLACE_ME` placeholders for `api_id`, `api_hash`, and `bearer_token` — fill them in and re-run.
74
+
75
+ To reach Telegram through a proxy, set `telegram.proxy_url` to a single URL — supported schemes are `socks5`, `socks4`, `http`, and `https`. Credentials and explicit ports are optional:
76
+
77
+ ```yaml
78
+ telegram:
79
+ proxy_url: "socks5://user:pass@host:1080" # or http://host:8080, socks4://host, ...
80
+ ```
81
+
82
+ Leave it unset (or remove the line) to connect directly.
83
+
84
+ Defaults applied to new supergroups live under `telegram.defaults`:
85
+
86
+ ```yaml
87
+ telegram:
88
+ defaults:
89
+ enable_topics: true
90
+ create_invite_link: true
91
+ topics_layout: "list" # "list" | "tabs" — applied after groups create
92
+ default_member_permissions:
93
+ create_topics: true # let ordinary members create forum topics
94
+ pin_messages: true # let ordinary members pin messages
95
+ ```
96
+
97
+ `topics_layout` controls how the forum opens after `groups create`: `"list"` shows topics as a vertical list (Telegram's default), `"tabs"` shows them as horizontal tabs. The CLI `groups create --topics-layout` and `groups set-layout --layout` flags, and the `POST /telegram/groups` / `POST /telegram/groups/layout` bodies (`topics_layout`), override the default per call.
98
+
99
+ `default_member_permissions` sets the new group's default banned rights so ordinary members can `create_topics` and `pin_messages`. Other default rights are left untouched.
100
+
101
+ ### Idempotency anchor
102
+
103
+ Group/topic creation is idempotent on a generic `external_ref` (CLI `--external-ref`, HTTP `external_ref`). For backward compatibility the CLI `--planfix-task-id` flag and the HTTP `planfix_task_id` field are accepted as aliases that map onto `external_ref`. With no `external_ref`, groups key on the exact title and topics key on `chat_id + topic_name`.
104
+
105
+ ### Planfix plugin (optional, off by default)
106
+
107
+ Planfix-specific behavior lives behind an opt-in plugin. With it disabled the core has **zero Planfix knowledge** — `external_ref` still anchors idempotency, but there is no `/task <id>` service message, no `@planfix_bot` welcome cleanup, and `@planfix_bot` is not treated as a protected account. Enable it under `plugins`:
108
+
109
+ ```yaml
110
+ plugins:
111
+ planfix:
112
+ enabled: true # turn on Planfix-specific behavior
113
+ bot_username: "@planfix_bot" # group member that receives the /task command
114
+ group_title_postfix: "" # appended to the Telegram chat title at creation
115
+ cleanup_messages: false # delete welcome / /task / bot-reply after creation (opt-in)
116
+ task_reply_wait_seconds: 5 # how long to poll for the bot's /task reply
117
+ ```
118
+
119
+ When enabled and `external_ref` is set on a group whose members include `bot_username`, the plugin sends `/task <external_ref>` after creation. `group_title_postfix` is appended to the Telegram chat title at creation time but deliberately kept out of the idempotency key, so a replay of the same `external_ref` still matches on the raw title. `cleanup_messages` (default `false`) deletes the bot's welcome message, the `/task <id>` command, and the bot's reply to it; `task_reply_wait_seconds` is how long to poll for that reply before deleting only the welcome + command. All cleanup is best-effort: failures are recorded in the operation's `skipped` list and never fail the create.
120
+
121
+ See `docs/plans/20260518-telegram-assistant-mvp.md` for the full configuration schema and feature scope.
122
+
123
+ ## Docker
124
+
125
+ The service ships as a slim Python 3.12 image. Runtime state (Telethon session, SQLite database, `data/config.yml`, bearer token) lives in `/data`, which must be mounted as a volume — nothing sensitive is baked into the image.
126
+
127
+ Build and run with `docker compose`:
128
+
129
+ ```bash
130
+ mkdir -p data
131
+ cp path/to/your/config.yml data/config.yml # fill in api_id, api_hash, bearer_token, etc.
132
+ docker compose up -d
133
+ curl http://127.0.0.1:8085/health
134
+ ```
135
+
136
+ Run a one-shot CLI invocation against the same volume:
137
+
138
+ ```bash
139
+ docker compose run --rm telegram-assistant \
140
+ telegram-assistant health
141
+ ```
142
+
143
+ The `auth` CLI is interactive (it prompts for phone, code, and optional 2FA password), so run it with a TTY attached:
144
+
145
+ ```bash
146
+ docker compose run --rm -it telegram-assistant \
147
+ telegram-assistant auth
148
+ ```
149
+
150
+ The Telethon session is written to `/data` and persists across container restarts.
151
+
152
+ A self-contained smoke script lives at `scripts/docker-smoke.sh`. It builds the image, starts a throwaway container with a temporary `data/config.yml`, polls `GET /health` until it returns `200`, and tears everything down.
153
+
154
+ ```bash
155
+ bash scripts/docker-smoke.sh
156
+ ```
157
+
158
+ ## Tests
159
+
160
+ ```bash
161
+ pytest
162
+ ```
@@ -0,0 +1,92 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "telegram-assistant"
7
+ version = "0.2.1"
8
+ description = "Telegram automation service (MTProto/Telethon) with an optional Planfix integration plugin."
9
+ readme = "README.md"
10
+ requires-python = ">=3.12"
11
+ license = { text = "MIT" }
12
+ authors = [{ name = "Stanislav Popov", email = "popstas@gmail.com" }]
13
+ keywords = ["telegram", "telethon", "automation", "mtproto", "planfix"]
14
+ classifiers = [
15
+ "Programming Language :: Python :: 3.12",
16
+ "Framework :: FastAPI",
17
+ "Topic :: Communications :: Chat",
18
+ "Operating System :: OS Independent",
19
+ "License :: OSI Approved :: MIT License",
20
+ ]
21
+ dependencies = [
22
+ "telethon>=1.36,<2.0",
23
+ "fastapi>=0.115,<1.0",
24
+ "uvicorn[standard]>=0.30,<1.0",
25
+ "pydantic>=2.7,<3.0",
26
+ "pyyaml>=6.0,<7.0",
27
+ "typer>=0.12,<1.0",
28
+ "structlog>=24.1,<25.0",
29
+ "SQLAlchemy>=2.0,<3.0",
30
+ "httpx>=0.27,<1.0",
31
+ "python-socks[asyncio]>=2.4,<3.0",
32
+ ]
33
+
34
+ [project.optional-dependencies]
35
+ dev = [
36
+ "pytest>=8.0,<9.0",
37
+ "pytest-asyncio>=0.23,<1.0",
38
+ "ruff>=0.5,<1.0",
39
+ "git-cliff>=2.0.0",
40
+ "pre-commit>=3.7,<5.0",
41
+ "build>=1.2,<2.0",
42
+ "twine>=5.0,<7.0",
43
+ "bump-my-version>=0.28,<1.0",
44
+ ]
45
+
46
+ [project.scripts]
47
+ telegram-assistant = "telegram_assistant.cli.main:app"
48
+
49
+ [project.urls]
50
+ Homepage = "https://github.com/popstas/telegram-assistant"
51
+ Repository = "https://github.com/popstas/telegram-assistant"
52
+ "Bug Tracker" = "https://github.com/popstas/telegram-assistant/issues"
53
+
54
+ [tool.setuptools.packages.find]
55
+ where = ["src"]
56
+
57
+ [tool.pytest.ini_options]
58
+ testpaths = ["tests"]
59
+ asyncio_mode = "auto"
60
+ addopts = "-ra"
61
+
62
+ [tool.ruff]
63
+ line-length = 100
64
+ target-version = "py312"
65
+
66
+ [tool.ruff.lint]
67
+ select = ["E", "F", "W", "I", "B", "UP"]
68
+ ignore = ["E501"]
69
+
70
+ # Version bumping: `bump-my-version bump patch|minor|major` updates both files,
71
+ # commits as `chore(release): vX.Y.Z`, and creates the `vX.Y.Z` tag. Pushing the
72
+ # tag triggers .github/workflows/release.yml (GitHub release + PyPI publish).
73
+ [tool.bumpversion]
74
+ current_version = "0.2.1"
75
+ allow_dirty = false
76
+ commit = true
77
+ message = "chore(release): v{new_version}"
78
+ tag = true
79
+ tag_name = "v{new_version}"
80
+ tag_message = "v{new_version}"
81
+
82
+ [[tool.bumpversion.files]]
83
+ filename = "pyproject.toml"
84
+ search = '''name = "telegram-assistant"
85
+ version = "{current_version}"'''
86
+ replace = '''name = "telegram-assistant"
87
+ version = "{new_version}"'''
88
+
89
+ [[tool.bumpversion.files]]
90
+ filename = "src/telegram_assistant/__init__.py"
91
+ search = '__version__ = "{current_version}"'
92
+ replace = '__version__ = "{new_version}"'
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,3 @@
1
+ """telegram-assistant — Telegram automation service (MTProto/Telethon)."""
2
+
3
+ __version__ = "0.2.1"
@@ -0,0 +1,5 @@
1
+ """CLI surface (Typer)."""
2
+
3
+ from telegram_assistant.cli.main import app
4
+
5
+ __all__ = ["app"]