remote-coder 0.4.1__py3-none-any.whl

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 (78) hide show
  1. app/__init__.py +3 -0
  2. app/admin/__init__.py +0 -0
  3. app/admin/advanced_settings.py +88 -0
  4. app/admin/database_browser.py +301 -0
  5. app/admin/router.py +528 -0
  6. app/admin/static/i18n.js +401 -0
  7. app/admin/static/icons/advanced.svg +8 -0
  8. app/admin/static/icons/database.svg +5 -0
  9. app/admin/static/icons/download.svg +3 -0
  10. app/admin/static/icons/home.svg +4 -0
  11. app/admin/static/icons/logs.svg +3 -0
  12. app/admin/static/icons/projects.svg +5 -0
  13. app/admin/static/summary.js +73 -0
  14. app/admin/templates/admin.html +511 -0
  15. app/admin/templates/advanced.html +635 -0
  16. app/admin/templates/database.html +880 -0
  17. app/admin/templates/logs.html +686 -0
  18. app/admin/templates/projects.html +878 -0
  19. app/ai/__init__.py +0 -0
  20. app/ai/base.py +129 -0
  21. app/ai/claude.py +20 -0
  22. app/ai/codex.py +34 -0
  23. app/ai/factory.py +27 -0
  24. app/ai/gemini.py +20 -0
  25. app/ai/model_catalog.py +47 -0
  26. app/ai/usage.py +134 -0
  27. app/cli.py +238 -0
  28. app/config.py +130 -0
  29. app/git/__init__.py +0 -0
  30. app/git/ai_commit.py +88 -0
  31. app/git/branch_naming.py +21 -0
  32. app/git/commit_message.py +279 -0
  33. app/git/service.py +669 -0
  34. app/jobs/__init__.py +0 -0
  35. app/jobs/manager.py +770 -0
  36. app/jobs/schemas.py +116 -0
  37. app/jobs/store.py +334 -0
  38. app/main.py +265 -0
  39. app/models.py +20 -0
  40. app/monitoring/__init__.py +10 -0
  41. app/monitoring/code.py +161 -0
  42. app/monitoring/events.py +33 -0
  43. app/monitoring/git.py +103 -0
  44. app/monitoring/log_buffer.py +245 -0
  45. app/monitoring/memory.py +19 -0
  46. app/monitoring/model.py +598 -0
  47. app/projects/__init__.py +19 -0
  48. app/projects/registry.py +384 -0
  49. app/security/__init__.py +0 -0
  50. app/security/auth.py +19 -0
  51. app/system_startup.py +34 -0
  52. app/telegram/__init__.py +0 -0
  53. app/telegram/bot_instances.py +67 -0
  54. app/telegram/commands/__init__.py +64 -0
  55. app/telegram/commands/base.py +222 -0
  56. app/telegram/commands/branch.py +366 -0
  57. app/telegram/commands/clear_stop.py +221 -0
  58. app/telegram/commands/fix.py +219 -0
  59. app/telegram/commands/model.py +93 -0
  60. app/telegram/commands/monitor.py +185 -0
  61. app/telegram/commands/registry.py +110 -0
  62. app/telegram/commands/status.py +243 -0
  63. app/telegram/commands/system.py +201 -0
  64. app/telegram/confirmations.py +36 -0
  65. app/telegram/conversation.py +789 -0
  66. app/telegram/i18n.py +742 -0
  67. app/telegram/model_preferences.py +53 -0
  68. app/telegram/notifier.py +387 -0
  69. app/telegram/parser.py +267 -0
  70. app/telegram/webhook.py +988 -0
  71. app/telegram/webhook_registration.py +172 -0
  72. app/tunnel.py +104 -0
  73. remote_coder-0.4.1.dist-info/METADATA +520 -0
  74. remote_coder-0.4.1.dist-info/RECORD +78 -0
  75. remote_coder-0.4.1.dist-info/WHEEL +5 -0
  76. remote_coder-0.4.1.dist-info/entry_points.txt +2 -0
  77. remote_coder-0.4.1.dist-info/licenses/LICENSE +201 -0
  78. remote_coder-0.4.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,520 @@
1
+ Metadata-Version: 2.4
2
+ Name: remote-coder
3
+ Version: 0.4.1
4
+ Summary: Telegram-based remote AI coding automation server
5
+ Author: Remote AI Coder contributors
6
+ License: Apache License
7
+ Version 2.0, January 2004
8
+ http://www.apache.org/licenses/
9
+
10
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
11
+
12
+ 1. Definitions.
13
+
14
+ "License" shall mean the terms and conditions for use, reproduction,
15
+ and distribution as defined by Sections 1 through 9 of this document.
16
+
17
+ "Licensor" shall mean the copyright owner or entity authorized by
18
+ the copyright owner that is granting the License.
19
+
20
+ "Legal Entity" shall mean the union of the acting entity and all
21
+ other entities that control, are controlled by, or are under common
22
+ control with that entity. For the purposes of this definition,
23
+ "control" means (i) the power, direct or indirect, to cause the
24
+ direction or management of such entity, whether by contract or
25
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
26
+ outstanding shares, or (iii) beneficial ownership of such entity.
27
+
28
+ "You" (or "Your") shall mean an individual or Legal Entity
29
+ exercising permissions granted by this License.
30
+
31
+ "Source" form shall mean the preferred form for making modifications,
32
+ including but not limited to software source code, documentation
33
+ source, and configuration files.
34
+
35
+ "Object" form shall mean any form resulting from mechanical
36
+ transformation or translation of a Source form, including but
37
+ not limited to compiled object code, generated documentation,
38
+ and conversions to other media types.
39
+
40
+ "Work" shall mean the work of authorship, whether in Source or
41
+ Object form, made available under the License, as indicated by a
42
+ copyright notice that is included in or attached to the work
43
+ (an example is provided in the Appendix below).
44
+
45
+ "Derivative Works" shall mean any work, whether in Source or Object
46
+ form, that is based on (or derived from) the Work and for which the
47
+ editorial revisions, annotations, elaborations, or other modifications
48
+ represent, as a whole, an original work of authorship. For the purposes
49
+ of this License, Derivative Works shall not include works that remain
50
+ separable from, or merely link (or bind by name) to the interfaces of,
51
+ the Work and Derivative Works thereof.
52
+
53
+ "Contribution" shall mean any work of authorship, including
54
+ the original version of the Work and any modifications or additions
55
+ to that Work or Derivative Works thereof, that is intentionally
56
+ submitted to Licensor for inclusion in the Work by the copyright owner
57
+ or by an individual or Legal Entity authorized to submit on behalf of
58
+ the copyright owner. For the purposes of this definition, "submitted"
59
+ means any form of electronic, verbal, or written communication sent
60
+ to the Licensor or its representatives, including but not limited to
61
+ communication on electronic mailing lists, source code control systems,
62
+ and issue tracking systems that are managed by, or on behalf of, the
63
+ Licensor for the purpose of discussing and improving the Work, but
64
+ excluding communication that is conspicuously marked or otherwise
65
+ designated in writing by the copyright owner as "Not a Contribution."
66
+
67
+ "Contributor" shall mean Licensor and any individual or Legal Entity
68
+ on behalf of whom a Contribution has been received by Licensor and
69
+ subsequently incorporated within the Work.
70
+
71
+ 2. Grant of Copyright License. Subject to the terms and conditions of
72
+ this License, each Contributor hereby grants to You a perpetual,
73
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
74
+ copyright license to reproduce, prepare Derivative Works of,
75
+ publicly display, publicly perform, sublicense, and distribute the
76
+ Work and such Derivative Works in Source or Object form.
77
+
78
+ 3. Grant of Patent License. Subject to the terms and conditions of
79
+ this License, each Contributor hereby grants to You a perpetual,
80
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
81
+ (except as stated in this section) patent license to make, have made,
82
+ use, offer to sell, sell, import, and otherwise transfer the Work,
83
+ where such license applies only to those patent claims licensable
84
+ by such Contributor that are necessarily infringed by their
85
+ Contribution(s) alone or by combination of their Contribution(s)
86
+ with the Work to which such Contribution(s) was submitted. If You
87
+ institute patent litigation against any entity (including a
88
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
89
+ or a Contribution incorporated within the Work constitutes direct
90
+ or contributory patent infringement, then any patent licenses
91
+ granted to You under this License for that Work shall terminate
92
+ as of the date such litigation is filed.
93
+
94
+ 4. Redistribution. You may reproduce and distribute copies of the
95
+ Work or Derivative Works thereof in any medium, with or without
96
+ modifications, and in Source or Object form, provided that You
97
+ meet the following conditions:
98
+
99
+ (a) You must give any other recipients of the Work or
100
+ Derivative Works a copy of this License; and
101
+
102
+ (b) You must cause any modified files to carry prominent notices
103
+ stating that You changed the files; and
104
+
105
+ (c) You must retain, in the Source form of any Derivative Works
106
+ that You distribute, all copyright, patent, trademark, and
107
+ attribution notices from the Source form of the Work,
108
+ excluding those notices that do not pertain to any part of
109
+ the Derivative Works; and
110
+
111
+ (d) If the Work includes a "NOTICE" text file as part of its
112
+ distribution, then any Derivative Works that You distribute must
113
+ include a readable copy of the attribution notices contained
114
+ within such NOTICE file, excluding those notices that do not
115
+ pertain to any part of the Derivative Works, in at least one
116
+ of the following places: within a NOTICE text file distributed
117
+ as part of the Derivative Works; within the Source form or
118
+ documentation, if provided along with the Derivative Works; or,
119
+ within a display generated by the Derivative Works, if and
120
+ wherever such third-party notices normally appear. The contents
121
+ of the NOTICE file are for informational purposes only and
122
+ do not modify the License. You may add Your own attribution
123
+ notices within Derivative Works that You distribute, alongside
124
+ or as an addendum to the NOTICE text from the Work, provided
125
+ that such additional attribution notices cannot be construed
126
+ as modifying the License.
127
+
128
+ You may add Your own copyright statement to Your modifications and
129
+ may provide additional or different license terms and conditions
130
+ for use, reproduction, or distribution of Your modifications, or
131
+ for any such Derivative Works as a whole, provided Your use,
132
+ reproduction, and distribution of the Work otherwise complies with
133
+ the conditions stated in this License.
134
+
135
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
136
+ any Contribution intentionally submitted for inclusion in the Work
137
+ by You to the Licensor shall be under the terms and conditions of
138
+ this License, without any additional terms or conditions.
139
+ Notwithstanding the above, nothing herein shall supersede or modify
140
+ the terms of any separate license agreement you may have executed
141
+ with Licensor regarding such Contributions.
142
+
143
+ 6. Trademarks. This License does not grant permission to use the trade
144
+ names, trademarks, service marks, or product names of the Licensor,
145
+ except as required for reasonable and customary use in describing the
146
+ origin of the Work and reproducing the content of the NOTICE file.
147
+
148
+ 7. Disclaimer of Warranty. Unless required by applicable law or
149
+ agreed to in writing, Licensor provides the Work (and each
150
+ Contributor provides its Contributions) on an "AS IS" BASIS,
151
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
152
+ implied, including, without limitation, any warranties or conditions
153
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
154
+ PARTICULAR PURPOSE. You are solely responsible for determining the
155
+ appropriateness of using or redistributing the Work and assume any
156
+ risks associated with Your exercise of permissions under this License.
157
+
158
+ 8. Limitation of Liability. In no event and under no legal theory,
159
+ whether in tort (including negligence), contract, or otherwise,
160
+ unless required by applicable law (such as deliberate and grossly
161
+ negligent acts) or agreed to in writing, shall any Contributor be
162
+ liable to You for damages, including any direct, indirect, special,
163
+ incidental, or consequential damages of any character arising as a
164
+ result of this License or out of the use or inability to use the
165
+ Work (including but not limited to damages for loss of goodwill,
166
+ work stoppage, computer failure or malfunction, or any and all
167
+ other commercial damages or losses), even if such Contributor
168
+ has been advised of the possibility of such damages.
169
+
170
+ 9. Accepting Warranty or Additional Liability. While redistributing
171
+ the Work or Derivative Works thereof, You may choose to offer,
172
+ and charge a fee for, acceptance of support, warranty, indemnity,
173
+ or other liability obligations and/or rights consistent with this
174
+ License. However, in accepting such obligations, You may act only
175
+ on Your own behalf and on Your sole responsibility, not on behalf
176
+ of any other Contributor, and only if You agree to indemnify,
177
+ defend, and hold each Contributor harmless for any liability
178
+ incurred by, or claims asserted against, such Contributor by reason
179
+ of your accepting any such warranty or additional liability.
180
+
181
+ END OF TERMS AND CONDITIONS
182
+
183
+ APPENDIX: How to apply the Apache License to your work.
184
+
185
+ To apply the Apache License to your work, attach the following
186
+ boilerplate notice, with the fields enclosed by brackets "[]"
187
+ replaced with your own identifying information. (Don't include
188
+ the brackets!) The text should be enclosed in the appropriate
189
+ comment syntax for the file format. We also recommend that a
190
+ file or class name and description of purpose be included on the
191
+ same "printed page" as the copyright notice for easier
192
+ identification within third-party archives.
193
+
194
+ Copyright 2026 maroomir
195
+
196
+ Licensed under the Apache License, Version 2.0 (the "License");
197
+ you may not use this file except in compliance with the License.
198
+ You may obtain a copy of the License at
199
+
200
+ http://www.apache.org/licenses/LICENSE-2.0
201
+
202
+ Unless required by applicable law or agreed to in writing, software
203
+ distributed under the License is distributed on an "AS IS" BASIS,
204
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
205
+ See the License for the specific language governing permissions and
206
+ limitations under the License.
207
+ Requires-Python: >=3.11
208
+ Description-Content-Type: text/markdown
209
+ License-File: LICENSE
210
+ Requires-Dist: fastapi
211
+ Requires-Dist: httpx
212
+ Requires-Dist: pydantic
213
+ Requires-Dist: pydantic-settings
214
+ Requires-Dist: python-dotenv
215
+ Requires-Dist: pyyaml
216
+ Requires-Dist: uvicorn[standard]
217
+ Provides-Extra: dev
218
+ Requires-Dist: pytest; extra == "dev"
219
+ Requires-Dist: pytest-asyncio; extra == "dev"
220
+ Requires-Dist: respx; extra == "dev"
221
+ Dynamic: license-file
222
+
223
+ # Remote AI Coder
224
+
225
+ 텔레그램 메시지를 통해 로컬 개발 머신에서 AI 코딩 작업을 실행하고 Git 브랜치/커밋 결과를 알림으로 받는 MVP 프로젝트입니다.
226
+
227
+ > [!WARNING]
228
+ > 이 프로젝트는 Telegram 메시지를 통해 로컬 머신의 AI CLI와 Git 작업을 실행합니다. 공개 인터넷에 서버나 관리 UI를 직접 노출하지 말고, 반드시 Telegram allowlist와(선택) webhook secret을 설정한 뒤 개인·신뢰 환경에서만 사용하세요.
229
+
230
+ ## 멀티봇 모델 (요약)
231
+
232
+ - **등록 프로젝트마다 별도 Telegram 봇**을 둡니다. 채팅에서 대상 저장소를 바꾸는 `/project` 명령은 없습니다.
233
+ - Webhook 주소는 봇마다 다릅니다: `POST /telegram/webhook/{SHA256(봇토큰)의 16진 문자열 앞 16자리}` (토큰 자체는 URL에 넣지 않음).
234
+ - 봇 토큰·허용 Chat/User ID·(선택) webhook secret은 **프로젝트 레지스트리**(`projects.json` 등)에 저장됩니다. **토큰은 평문**이므로 파일 권한과 백업 정책을 엄격히 하세요.
235
+ - 상세 절차는 [`docs/multi-bot-setup.md`](docs/multi-bot-setup.md)를 참고하세요.
236
+ - 프로젝트를 **비활성화하거나 삭제**하면 서버는 해당 토큰 해시 prefix로 들어오는 업데이트를 더 이상 라우팅하지 않습니다. Telegram에 예전 URL이 남아 있어도 이 앱에서는 처리되지 않습니다. 봇 쪽 webhook을 비우거나 새 URL로 맞추려면 Bot API `deleteWebhook` 또는 [`scripts/set_webhook.py`](scripts/set_webhook.py)를 레지스트리에 맞게 다시 실행하세요.
237
+
238
+ ## 공개/보안 안내
239
+
240
+ - `TELEGRAM_BOT_TOKEN`(시드용 선택), 레지스트리의 `bot_token`, Chat/User ID, webhook secret, AI API key, 개인 경로는 코드나 문서에 커밋하지 마세요.
241
+ - `.env`, `.remote-coder/`(특히 `projects.json`), worktree, 로그, SQLite 대화 기억 파일은 로컬 전용 데이터입니다. 이 저장소의 `.gitignore`는 기본적으로 이 파일들을 제외합니다.
242
+ - 관리 UI(`/`, `/projects`, `/advanced`, `/logs`, `/database`)는 localhost 전용으로 설계되어 있습니다. reverse proxy, ngrok, 포트포워딩 등으로 외부에 공개하지 마세요.
243
+ - Claude `--dangerously-skip-permissions`, Gemini `--approval-mode yolo`, Codex `danger-full-access` 같은 옵션은 로컬 파일을 수정할 수 있으므로 허용 프로젝트와 신뢰 사용자 범위를 제한한 뒤 사용하세요.
244
+ - 대화 기억 SQLite에는 사용자의 Telegram 요청과 Job 요약이 저장될 수 있습니다. 민감한 코드를 메시지에 붙여넣지 말고, 필요 시 `/clear memory` 또는 관리 UI 고급 설정으로 정리하세요.
245
+
246
+ 취약점 제보와 공개 전 점검 절차는 [`SECURITY.md`](SECURITY.md)를 참고하세요.
247
+
248
+ ## 사전 준비
249
+
250
+ - Python 3.11 이상 또는 Conda
251
+ - 프로젝트마다 Telegram Bot Token(BotFather)과 허용할 Chat ID(필수)·User ID(선택)
252
+ - HTTPS 터널 도구(개발용 예: ngrok)
253
+ - Claude Code CLI, Codex CLI, Gemini CLI 중 사용할 도구 1개 이상
254
+ - 대상 Git 프로젝트와 worktree를 둘 로컬 디렉터리
255
+
256
+ ## 빠른 시작 (권장)
257
+
258
+ 별도의 Conda 환경 없이 `pip` 한 줄로 설치합니다. `remote-coder` CLI가 설치되고, 전제조건(ngrok·AI CLI)은 `remote-coder doctor`로 점검할 수 있습니다.
259
+
260
+ ```bash
261
+ pip install remote-coder
262
+ ```
263
+
264
+ > PyPI 첫 발행 전에는 git 소스에서 바로 설치하세요(이것도 `pip`입니다).
265
+ >
266
+ > ```bash
267
+ > pip install git+https://github.com/maroomir/remote-coder.git
268
+ > ```
269
+
270
+ 설치 후에는 두 단계면 됩니다.
271
+
272
+ ```bash
273
+ remote-coder init # 봇 토큰·허용 Chat ID·대상 저장소 경로를 입력 → 전역 설정과 프로젝트 레지스트리 생성
274
+ remote-coder up # ngrok 터널 + Telegram webhook 등록 + 서버 실행을 한 번에 (종료: Ctrl+C)
275
+ ```
276
+
277
+ - 전역 설정은 `REMOTE_CODER_HOME`(기본 `~/.remote-coder`)의 `.env`에 저장되므로 **어느 디렉터리에서 실행해도** 동작합니다. (봇 토큰이 평문으로 들어가므로 파일 권한은 `0600`으로 생성됩니다.)
278
+ - 전제조건: `ngrok`(설치 후 `ngrok config add-authtoken <token>`)과 AI CLI(`claude`/`codex`/`gemini`) 중 1개 이상. `remote-coder doctor`로 점검할 수 있습니다.
279
+ - 터널 없이 서버만 띄우려면 `remote-coder up --no-tunnel`.
280
+
281
+ ### 다른 설치 방법
282
+
283
+ 격리 설치를 선호하면 [pipx](https://pipx.pypa.io/)나 [uv](https://docs.astral.sh/uv/)를 쓸 수 있습니다. (PyPI 발행 전에는 패키지명 대신 `git+https://github.com/maroomir/remote-coder.git`을 넣으세요.)
284
+
285
+ ```bash
286
+ pipx install remote-coder
287
+ uv tool install remote-coder
288
+ ```
289
+
290
+ 전제조건 점검까지 한 번에 처리하는 설치 스크립트도 있습니다(uv로 격리 설치).
291
+
292
+ ```bash
293
+ curl -fsSL https://raw.githubusercontent.com/maroomir/remote-coder/main/scripts/install.sh | bash
294
+ ```
295
+
296
+ ### 개발용 설치
297
+
298
+ 소스 체크아웃에서 editable 설치:
299
+
300
+ ```bash
301
+ python -m pip install -e ".[dev]"
302
+ remote-coder up --no-tunnel --reload
303
+ ```
304
+
305
+ `remote-coder up --no-tunnel`은 터널·webhook 등록 없이 서버만 실행하며 `uvicorn app.main:app` 와 동일합니다.
306
+
307
+ ### 배포 패키지 빌드
308
+
309
+ ```bash
310
+ python -m pip install build
311
+ python -m build
312
+ ```
313
+
314
+ 생성물은 `dist/remote_coder-<버전>.tar.gz`와 `dist/remote_coder-<버전>-py3-none-any.whl`입니다. 태그(`vX.Y.Z`)를 push하면 GitHub Actions가 빌드·PyPI 발행(Trusted Publishing)·GitHub Release를 자동으로 수행합니다.
315
+
316
+ ### Homebrew 배포
317
+
318
+ 이 프로젝트는 CLI/서버 패키지이므로 macOS 앱 번들용 `brew install --cask remote-coder`보다 Formula 방식인 `brew install remote-coder`가 적합합니다. Formula 초안은 [`packaging/homebrew/remote-coder.rb`](packaging/homebrew/remote-coder.rb)에 있습니다.
319
+
320
+ 릴리스 후 필요한 작업:
321
+
322
+ - `homepage`를 실제 저장소 URL로 교체
323
+ - PyPI 또는 GitHub Release의 `remote_coder-<버전>.tar.gz` URL로 `url` 교체
324
+ - `shasum -a 256 dist/remote_coder-<버전>.tar.gz` 값으로 `sha256` 교체
325
+ - Python 의존성 `resource` 블록은 `brew pypi-poet remote-coder` 같은 도구로 생성해 Formula에 추가
326
+
327
+ > 아래 “1) ~ 3)” 절은 `remote-coder init`/`up` 대신 저장소에서 직접 개발하거나 설정을 수동으로 다루려는 **개발/기여자용** 안내입니다. 빠른 시작만으로 충분하다면 건너뛰어도 됩니다.
328
+
329
+ ## 1) 환경 준비 (개발/기여자용 Conda)
330
+
331
+ ```bash
332
+ conda env create -f environment.yml
333
+ conda activate remote-coder
334
+ ```
335
+
336
+ ## 2) 설정
337
+
338
+ `remote-coder init`을 쓰면 이 `.env`를 자동으로 생성합니다. 수동으로 다룰 때만 아래처럼 복사·편집하세요. (전역 실행 시에는 `REMOTE_CODER_HOME/.env`가, 저장소 내 개발 시에는 현재 디렉터리의 `.env`가 우선됩니다.)
339
+
340
+ ```bash
341
+ cp .env.example .env
342
+ ```
343
+
344
+ `.env`에 다음 값을 채웁니다.
345
+
346
+ - 선택(초기 시드): `TELEGRAM_BOT_TOKEN`, `TELEGRAM_ALLOWED_CHAT_IDS`, `TELEGRAM_ALLOWED_USER_IDS`, `TELEGRAM_WEBHOOK_SECRET` — 레지스트리가 비어 있을 때 첫 프로젝트 생성에만 쓰일 수 있습니다. 운영 설정은 관리 UI 또는 `projects.json`의 **프로젝트별** 필드를 우선합니다.
347
+ - 선택: `GIT_REMOTE_NAME` (기본 `origin`) — 커밋 후 push 및 `/rebase`, `/pr`, `/clear` 시 사용
348
+ - 선택: `PROJECTS_CONFIG_PATH` — 여러 Git 프로젝트 등록 파일(JSON 또는 `.yaml`) 경로
349
+ - 선택: `CONVERSATION_DB_PATH` — 프로젝트+채팅별 대화 기억 SQLite 경로 (미설정 시 `PROJECT_ROOT/.remote-coder/conversations.sqlite3`)
350
+ - 선택: `CONVERSATION_RECENT_LIMIT` — 모호한 후속 요청 시 runner에 붙이는 최근 기록 개수 (기본 `10`)
351
+ - 선택: `CODEX_SANDBOX` — Codex `codex exec --sandbox` 값 (`read-only`, `workspace-write`, `danger-full-access`). 기본 `workspace-write`(Job worktree에서 파일 수정 가능)
352
+ - 선택: Gemini 사용 시 `npm install -g @google/gemini-cli`로 Gemini CLI를 설치하고 `gemini` 명령이 PATH에 잡히도록 설정
353
+ - 초기 시드(1회용): `DEFAULT_PROJECT`, `PROJECT_ROOT`, `WORKTREE_BASE_DIR`
354
+
355
+ 기존 단일 `.env`만 쓰던 경우 → 관리 UI에서 각 프로젝트에 `bot_token`·allowlist를 옮기거나, 시드 생성 후 `.env`의 민감 값을 정리하는 것을 권장합니다. [`docs/multi-bot-setup.md`](docs/multi-bot-setup.md) 마이그레이션 절을 참고하세요.
356
+
357
+ ## 2.5) 로컬 관리 UI (프로젝트 등록)
358
+
359
+ 서버를 띄운 뒤 **같은 머신**에서 브라우저로 접속합니다.
360
+
361
+ - 관리 허브: `http://127.0.0.1:8000/` (요약·다른 페이지로 이동)
362
+ - 프로젝트 등록: `http://127.0.0.1:8000/projects` (목록, 추가·수정·삭제, 폴백 기본값, **봇 토큰·allowlist·webhook secret**, 봇별 webhook 경로 표시. `remote-coder up` 실행 중에는 등록·수정한 활성 프로젝트의 Telegram webhook과 `/` 명령어 메뉴도 즉시 갱신)
363
+ - 고급 설정: `http://127.0.0.1:8000/advanced`
364
+ - 서버 로그: `http://127.0.0.1:8000/logs` (`app` 로거 기준 인메모리 링 버퍼, 자동 새로고침·카테고리·`chat_id`/`job_id` 필터)
365
+ - 데이터 조회: `http://127.0.0.1:8000/database` (대화 기억 SQLite 테이블 조회·CSV보내기)
366
+ - 자연어 작업 대상 프로젝트는 **해당 봇에 고정**되어 있습니다. `project:` 토큰은 지원하지 않습니다.
367
+ - `PROJECTS_CONFIG_PATH`가 없으면 기본 경로 `PROJECT_ROOT/.remote-coder/projects.json`을 사용합니다.
368
+ - 레지스트리 파일이 없으면 `.env`의 초기 시드 값(`DEFAULT_PROJECT`, `PROJECT_ROOT`, `WORKTREE_BASE_DIR`)으로 자동 생성됩니다.
369
+
370
+ ### 서버 로그(이벤트) 로거 네임 규약
371
+
372
+ 관리 UI `/logs`와 API `GET /api/logs`에 쌓이는 항목은 `app` 패키지 로거로 기록됩니다. 주요 로거 이름과 용도는 다음과 같습니다.
373
+
374
+ | 로거 이름 | 용도 |
375
+ |-----------|------|
376
+ | `app.telegram.inbound` | Webhook 수신·빈 메시지 스킵 |
377
+ | `app.telegram.outbound` | `sendMessage` 성공/실패, Job 접수·결과 알림 발송 |
378
+ | `app.telegram.command` | 슬래시 명령 처리, 자연어 Job 접수, `/init`·`/clear` 확인 등 상태 변경 |
379
+ | `app.security.auth` | Webhook secret 불일치, allowlist 거부 |
380
+ | `app.jobs.lifecycle` | Job 제출·단계(`git_worktree`/`runner`/…)·성공·실패 |
381
+ | `app.git.service` | worktree 생성·커밋·push·정리·rebase 통합 등 Git Adapter |
382
+ | `app.ai.claude` / `app.ai.codex` / `app.ai.gemini` | Runner 시작·종료·timeout |
383
+
384
+ 구조화 필드(`category`, `chat_id`, `user_id`, `project`, `job_id`)는 UI 필터·배지로 조회할 수 있습니다. 코드에서는 `app.monitoring.events.EventLogger`와 `app.monitoring.log_buffer.LOG_RECORD_CONTEXT_KEYS` 화이트리스트를 사용합니다.
385
+
386
+ ### 고급 설정 (위험 옵션)
387
+
388
+ 관리 UI의 **고급 설정** 페이지(`http://127.0.0.1:8000/advanced`)에서 전역 설정 파일 `PROJECT_ROOT/.remote-coder/advanced_settings.json`을 읽고 저장할 수 있습니다. **Interface language** (`ui_language`): 기본값은 **English**이며, Telegram 봇이 보내는 안내·버튼 라벨뿐 아니라 **관리 UI(`/`, `/projects`, `/advanced`, `/logs`, `/database`) 전체**가 이 언어를 따릅니다. **한국어**로 바꾼 뒤 저장하고 페이지를 새로고침하면 관리 UI와 Telegram 응답이 모두 한국어로 표시됩니다. (관리 UI는 영어를 기본값으로 렌더링하고, 한국어는 클라이언트에서 오버레이합니다.)
389
+
390
+ 옵션마다 기본값이 다르며(예: 서버 생명주기 Telegram 알림은 기본 켜짐, 서버 시작 시 저장소 `git pull`은 기본 꺼짐), 켜지 않은 옵션은 해당 기능이 비활성인 것과 같습니다. 예전 버전에서만 쓰이던 키는 로드 시 무시됩니다(예: 제거된 `auto_pull_on_project_switch`).
391
+
392
+ > [!WARNING]
393
+ > “요청 결과를 즉시 main/master에 반영 후 push” 옵션은 AI가 만든 변경을 통합 브랜치에 자동 반영합니다. 개인 실험용 저장소가 아니라면 기본값(off)을 유지하고, 사용 전 원격 브랜치 보호와 백업 정책을 확인하세요.
394
+
395
+ - **요청 결과를 즉시 main/master에 반영 후 push**: Job이 변경을 커밋·브랜치 push까지 성공하면, `/rebase`와 유사하게 해당 브랜치를 통합 브랜치(`main` 또는 `master`)에 fast-forward 병합한 뒤 원격에 push합니다. 충돌·non-ff 등으로 통합에 실패하면 Job은 실패로 기록됩니다.
396
+ - **SQLite 대화 기억 저장량 제한**: 켜면 `conversation_entries` 테이블 전체를 대상으로, 오래된 행부터 삭제합니다. **최대 행 수**와 **최대 DB 용량(bytes)** 중 하나 이상을 양수로 지정해야 하며, 둘 다 지정하면 행 수 제한을 먼저 맞춘 뒤 용량 제한을 맞추기 위해 삭제·`VACUUM`을 반복합니다. `message_branch_links`는 고아 링크를 정리합니다.
397
+
398
+ ## 3) 한 번에 실행하기
399
+
400
+ 설치형 CLI를 쓴다면 `remote-coder up` 한 줄이 ngrok 실행, Webhook 등록, 서버 실행을 모두 처리합니다. ngrok 공개 URL을 `TELEGRAM_WEBHOOK_PUBLIC_BASE_URL`로 서버에 전달하므로, 서버를 재시작하지 않아도 관리 UI에서 등록·수정한 활성 프로젝트의 Telegram webhook과 `/` 명령어 메뉴가 즉시 갱신됩니다.
401
+
402
+ ```bash
403
+ remote-coder up
404
+ ```
405
+
406
+ 멀티봇은 공개 HTTPS Base URL만 넘겨 활성 프로젝트마다 webhook과 명령어 메뉴를 등록하는 `python scripts/set_webhook.py <URL>` 을 사용할 수도 있습니다.
407
+
408
+ Windows PowerShell에서는 다음 스크립트를 사용할 수 있습니다.
409
+
410
+ ```powershell
411
+ .\run.ps1
412
+ ```
413
+
414
+ 또는 PowerShell 실행 정책을 자동 우회하는 배치 래퍼를 사용할 수 있습니다.
415
+
416
+ ```bat
417
+ run.bat
418
+ ```
419
+
420
+ Windows 실행 전에는 `ngrok.exe`가 설치되어 있고 PATH에서 실행 가능해야 합니다. 확인:
421
+
422
+ ```powershell
423
+ ngrok version
424
+ ```
425
+
426
+ - 스크립트 실행 후 텔레그램에서 바로 봇에게 말을 걸면 동작합니다.
427
+ - 서버를 종료하려면 `Ctrl+C`를 누르면 ngrok도 함께 종료됩니다.
428
+
429
+ ## 4) 지원 명령어 (MVP)
430
+
431
+ `remote-coder up` 또는 `python scripts/set_webhook.py <URL>` 로 Telegram 등록을 갱신하면 BotFather에서 설정하는 것과 같은 `/` 명령어 메뉴가 각 프로젝트 봇에 등록됩니다.
432
+
433
+ - `/start` : 인라인 메뉴 허브 (모델·모니터·정리·관리 항목별 버튼 바로가기)
434
+ - `/help` : 명령어 도움말 (model·monitor·clear 항목별 인라인 버튼 제공)
435
+ - `/model` : 기본 모델 확인 (인라인 버튼으로 선택)
436
+ - `/model claude` : 현재 chat의 기본 모델을 claude로 변경
437
+ - `/model codex` : 현재 chat의 기본 모델을 codex로 변경
438
+ - `/model gemini` : 현재 chat의 기본 모델을 gemini로 변경
439
+ - `/status` : 최근 Job 목록에서 인라인 버튼으로 선택
440
+ - `/status <job_id>` : 작업 상태 조회
441
+ - `/init` : 이 채팅의 기본 모델 오버라이드·`/clear` 및 자연어 Job 확인 대기 상태를 초기화(봇에 묶인 프로젝트는 변하지 않음; SQLite·Git은 변경 없음)
442
+ - `/reports` : 현재 채팅·현재 작업 프로젝트 기준으로 SQLite 대화 기억을 SQL 집계해 요약 리포트
443
+ - `/branch` : 이 채팅 **적용 프로젝트** 저장소의 현재 checkout 브랜치 표시
444
+ - `/branch <이름>` : 적용 프로젝트에서 로컬 브랜치가 있을 때만 `git switch` (없으면 오류, 원격만 있는 브랜치는 자동 생성하지 않음)
445
+ - `/pull` : 원격 저장소의 모든 브랜치 정보를 가져오고(fetch), 현재 브랜치를 pull 합니다. 체크아웃되지 않은 다른 로컬 브랜치(main 포함)들에 대해서도 fast-forward 업데이트를 시도합니다.
446
+ - `/rebase` : 인라인 버튼으로 로컬과 원격에 모두 있는 브랜치 선택 (main/master 제외) 후 `main`(또는 `master`) 기준으로 rebase → fast-forward 병합 → 원격 push
447
+ - `/rebase <branch>` : 직접 브랜치를 지정해 rebase
448
+ - `/pr` : 인라인 버튼으로 로컬 브랜치 선택 후 GitHub Pull Request 생성. PR 본문에는 해당 브랜치 작업 시 주고받은 요청과 AI 결과가 포함됩니다. GitHub CLI(`gh`)가 필요합니다 (`gh auth login`).
449
+ - `/pr <branch>` : 직접 브랜치를 지정해 PR 생성
450
+ - `/clear branch` : **이 봇에 묶인 프로젝트**에서만 `remote-*` 로컬·원격 브랜치와 연결된 linked worktree 정리
451
+ - `/clear worktrees` : **이 봇 프로젝트**의 관리 대상 worktree 정리 + stale entry prune
452
+ - `/clear memory` : **이 봇 프로젝트 + 현재 채팅**의 대화 기억(SQLite)만 삭제
453
+ - `/stop` : 진행 중인 Job 목록에서 인라인 버튼으로 선택해 중단
454
+ - `/stop <job_id>` : 지정한 Job 강제 중단 (queued/running 상태만 가능)
455
+ - `/fix` : 이전 Job의 커밋 메시지(`commit`)나 소스(`source`)를 재작업. 기존 커밋을 `git commit --amend`로 덮고 `git push --force-with-lease`로 원격에 반영합니다. 커밋 trailer의 `committed by remote-coder: <id>` 는 **원본 Job ID**를 유지합니다.
456
+ - `/fix commit <job_id>` : AI 커밋 메시지만 재생성해서 미리보기 → `y`/`Y` 확인 시 amend
457
+ - `/fix source <job_id>` : 후속 메시지를 수정 지시로 받아 같은 브랜치 worktree에서 다시 AI 실행 → `y`/`Y` 확인 시 amend + push
458
+ - `fix: <지시>` (또는 `수정: <지시>`)로 봇이 보낸 이전 메시지에 답장하면 해당 Job에 대한 source 모드 fix 확인을 바로 보여줍니다. 대상 Job은 `SUCCEEDED + branch + commit` 상태여야 합니다.
459
+ - `/monitor model` : 현재 채팅 기본 모델 기준 Claude(`claude auth status`) / Codex(`codex --version`) / Gemini(`gemini --version`) 등 CLI Probe + 로컬 CLI 로그에서 관측한 실제 사용량 요약. Codex 세션 로그에 `rate_limits`가 있으면 5시간/주간 잔여율과 리셋 시각도 표시하고, Claude/Gemini는 로컬 transcript/chat 로그의 세부 모델·토큰·요청 수를 표시합니다.
460
+ - `/monitor memory` : 이 채팅·현재 **적용 프로젝트** 기준 SQLite 대화 기억 행 수·역할별 행 수·DB 파일 크기
461
+ - `/monitor branch` : 적용 프로젝트 저장소의 브랜치 요약(로컬/원격 개수 및 목록)
462
+ - `/monitor worktrees` : linked worktree 목록·detached 개수·Remote Coder managed 후보 요약
463
+ - `/monitor code` : 적용 프로젝트 루트 기준 코드 파일 수·줄 수 추정(확장자 화이트리스트, `.git`·`node_modules` 등 제외)
464
+ - `/monitor project` : **이 봇에 묶인** 프로젝트 레코드 요약(이름, 활성 여부, 경로, 기본 모델, worktree 디렉터리)
465
+ - 자연어 메시지: agent·plan·ask 모두 파싱 성공 후 현재 프로젝트·작업 브랜치·사용 모델·모드를 표시하고 `y`/`Y`(또는 고급 설정 시 인라인 확인 버튼)를 받은 뒤 AI 작업 요청(Job)을 생성합니다. `plan:`/`ask:`/`계획:`/`질문:` 접두(콜론 `:` 또는 `:`) 또는 `/plan`/`/ask`로 시작하면 **읽기 전용** plan/ask 모드이며, Job 실행 시에는 커밋·push를 하지 않습니다.
466
+
467
+ 예: `plan: 로그인 플로우 리팩터링 방안만 정리해줘`, `/plan model: codex 위험만`, `ask: 이 저장소에서 테스트 실행 명령이 뭐야?`, `/ask JobManager 역할`
468
+
469
+ 참고:
470
+
471
+ - `/model`로 채팅별로 덮어쓴 기본 모델은 인메모리입니다. 서버 재시작 시 레지스트리의 프로젝트 `default_model`로 돌아갑니다.
472
+ - **적용 프로젝트는 항상 이 봇 인스턴스에 바인딩된 이름**입니다. **`/branch`, `/rebase`, `/monitor memory|branch|worktrees|code|project` 등은 그 저장소를 기준으로 동작합니다.**
473
+ - `/init`으로 채팅별 모델 오버라이드와 확인 대기 상태를 되돌릴 수 있습니다(대화 기억 SQLite·Git 저장소는 건드리지 않음).
474
+ - AI Job은 **요청에 사용된 프로젝트 저장소**의 **현재 `HEAD` 커밋**에서 detached worktree를 만든 뒤 실행합니다. **워킹 트리에 변경이 있을 때만** 작업 브랜치를 만들고 커밋합니다. 커밋이 있으면 `GIT_REMOTE_NAME`(기본 `origin`)으로 push합니다. 저장소 브랜치를 바꾸려면 먼저 `/branch <이름>`으로 로컬 브랜치를 전환하세요.
475
+ - 자동 생성 커밋 메시지는 다음 형식을 사용합니다.
476
+
477
+ ```text
478
+ type: title
479
+ - contents1
480
+ - contents2
481
+
482
+ committed by remote-coder: job-id
483
+ ```
484
+
485
+ `title`은 기능 수정 내용을 한 줄로 요약하고, 첫 번째 본문 항목은 사용자 원문이나 최근 수정 파일 목록이 아니라 AI Agent가 수행한 변경 내용을 설명합니다. 변경 파일 목록은 Job 결과 알림에서 별도로 확인합니다.
486
+
487
+ - 자연어 메시지에서 `model: codex`, `model: gemini`, `branch: my-branch`, `no commit` 토큰을 함께 사용할 수 있습니다. (`branch:` 값은 `/branch`와 동일 규칙으로 검증됩니다. `plan:`/`ask:` 모드에서는 `branch:`·`no commit`은 무시됩니다.)
488
+ - 자연어 요청은 파싱 직후 실행되지 않습니다. 확인 메시지에 현재 프로젝트, 작업 브랜치, 사용 모델·모드를 표시하며 `y` 또는 `Y`(또는 인라인 확인) 후에만 Job이 생성됩니다. 확인 대기 중 파싱 가능한 새 자연어가 오면 이전 대기를 조용히 바꾸고, 파싱되지 않는 입력이 오면 대기가 취소됩니다.
489
+ - **대화 기억(SQLite)**: 같은 텔레그램 채팅·같은 작업 프로젝트 기준으로 사용자 메시지와 Job 접수/결과 요약이 SQLite에 쌓입니다. 서버를 재시작해도 유지됩니다. 이전에 구체적인 지시를 보낸 뒤 `작업 시작해줘`, `진행해줘`, `그거 해줘`, `시작해줘`처럼 짧은 후속 문장만내면, 최근 기록을 합쳐 AI 지시문으로 만듭니다. 맥락이 없으면 봇이 안내 메시지를 보냅니다.
490
+ - **Reply 체인**: 이전 메시지에 답장(reply)으로 보낸 자연어 요청마다, SQLite에 남은 조상 메시지들의 본문과 각 메시지에 연결된 Job 결과 요약을 `[Reply 체인 맥락]` 블록으로 Codex/Claude instruction 앞에 붙입니다. (봇이 해당 메시지를 수신·저장한 경우에만 복원됩니다.)
491
+ - `/reports 7`처럼 최근 표시 개수를 함께 줄 수 있습니다. 허용 범위는 `1~10`이며, 기본값은 `5`입니다.
492
+ - worktree 생성 직후 쓰기 가능 여부를 점검합니다. AI 출력에 읽기 전용·수정 불가 등의 표현이 있고 Git 변경이 없으면 성공이 아니라 **실패**로 처리됩니다.
493
+ - 작업 완료/실패 메시지에는 AI 실행 결과 요약(`stdout`/`stderr`)이 함께 포함됩니다.
494
+ - 전체 출력 원문은 worktree 로그 파일(`WORKTREE_BASE_DIR/_logs/<job_id>.log`)에서 확인할 수 있습니다.
495
+
496
+ ## 5) 모델별 사용 가이드
497
+
498
+ - 멀티봇·Webhook·마이그레이션: [`docs/multi-bot-setup.md`](docs/multi-bot-setup.md)
499
+ - Claude 사용자: [`docs/claude-guide.md`](docs/claude-guide.md)
500
+ - Codex 사용자: [`docs/codex-guide.md`](docs/codex-guide.md)
501
+ - Gemini 사용자: [`docs/gemini-guide.md`](docs/gemini-guide.md)
502
+ - Worktree가 read-only로 실패할 때: [`docs/read-only-workspace.md`](docs/read-only-workspace.md)
503
+
504
+ **Runner 운영 시 참고:** Gemini CLI는 비대화형 실행 위주로 붙어 있어 대화형 TUI와 기대가 다를 수 있습니다. Codex CLI는 샌드박스·승인 정책에 따라 네트워크나 일부 도구 호출이 제한될 수 있습니다.
505
+
506
+ ## 6) 테스트
507
+
508
+ 멀티봇 라우팅·알림 격리·프로젝트 스코프 상태는 `tests/test_webhook_multibot.py`, `tests/test_bot_instance_manager.py`, `tests/test_project_scoped_state.py` 등에서 다룹니다.
509
+
510
+ ```bash
511
+ conda activate remote-coder
512
+ PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 pytest -q -p pytest_asyncio.plugin -p respx.fixtures
513
+ ```
514
+
515
+ ## 7) 공개 저장소 관리
516
+
517
+ - 라이선스: [Apache License 2.0](LICENSE)
518
+ - 기여 방법: [CONTRIBUTING.md](CONTRIBUTING.md)
519
+ - 보안 정책: [SECURITY.md](SECURITY.md)
520
+ - Pull Request 전에는 `PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 conda run -n remote-coder pytest -q -p pytest_asyncio.plugin -p respx.fixtures`를 실행해 주세요.
@@ -0,0 +1,78 @@
1
+ app/__init__.py,sha256=Jm4vfeH2m4Gr3-kO1U-IZy-rwa8E4np3QSAYgKCnLgk,66
2
+ app/cli.py,sha256=qmZCanMaYlNIgrPleYeTU_teG7oQhss7FzvNqohrK9c,8543
3
+ app/config.py,sha256=b-6drGNNYNdC-U5EAE4LtT3eQTJhzyz9ZWV8VgKsS0U,5514
4
+ app/main.py,sha256=C9qolQf0DggMz9BG4NcPGhTzopyrt0XkgN0XVA5mlQ4,10282
5
+ app/models.py,sha256=lwbnvfspxQ5kptEXWqrFzCpR2Q6CfVWCl5lb0PO1jk4,416
6
+ app/system_startup.py,sha256=bZLi0cEK5rMtndtsnGudhf7sl6oDLj1JEVHjHl8r3k8,1069
7
+ app/tunnel.py,sha256=gW0pkXH9POTnyvZwWpLnUtRDwAPFBIVrjehX46Eo6Uo,3174
8
+ app/admin/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
+ app/admin/advanced_settings.py,sha256=UbW2rwtxfAB6cWG2yxlJNCJ6to0dRcuIQpq7RfXQ8yU,3788
10
+ app/admin/database_browser.py,sha256=Z_dJ-ToKlZQKQv91zlEnt0vf5IUcW773B8wov4BOYNQ,9929
11
+ app/admin/router.py,sha256=-egRpGFNDMeUP5SKYuiZs7osXmYZuGAaCg3fl3RJEas,22351
12
+ app/admin/static/i18n.js,sha256=ioMbtW18ZlBGKs24tQBuowDEi2S2gxTcKZNJ787zfw4,24291
13
+ app/admin/static/summary.js,sha256=MVKmMpO0MqUBPbYHc-l71G8D-t87_lPVqZBdsCSjrPY,3652
14
+ app/admin/static/icons/advanced.svg,sha256=r6dkoK9FgEAJVN3dhwSBGpbp9qA85V00q3kE30Afe-E,676
15
+ app/admin/static/icons/database.svg,sha256=S0i7nkrha1ChuV-kguAGMcLE4Wvt4O4G-89WyRsZB50,421
16
+ app/admin/static/icons/download.svg,sha256=Fgcs0sZRA3YQw-fr-fx5-ieF9SrqMyPpG_FxN3SeWNc,254
17
+ app/admin/static/icons/home.svg,sha256=wt2T0Mfl_KzuoqpmByJsrlP34YGI3r56SIutRt4c0S8,296
18
+ app/admin/static/icons/logs.svg,sha256=80SZZuaK_hDLSW7fmujAQyq85k588UOzY00n09XDx1c,219
19
+ app/admin/static/icons/projects.svg,sha256=-N5c30M2bIhHZMSfZYr61Dz_CGbGIQQEUeZMm8ld8yo,396
20
+ app/admin/templates/admin.html,sha256=ckwQDXSBuWRiGethYTHIz1E7d5M_lKfsC-sVmcgfKNU,15342
21
+ app/admin/templates/advanced.html,sha256=iZK4qgOxY7bY-qUxqn9lgXalTqxO-M8UF1gTqyFAbxE,22910
22
+ app/admin/templates/database.html,sha256=zuFlVeWPyiex5jJMGlL1tPNcRKdaWblTydzxWbeD1Uo,26880
23
+ app/admin/templates/logs.html,sha256=P2D1vVWLmo36_uAF49JdCPUzMJIR-jCoogpBk4rjc5Y,22476
24
+ app/admin/templates/projects.html,sha256=OuhHNGFEMaT8mxEVsLJ-8DhhhxIlGxgDq_a3R8biZb8,28127
25
+ app/ai/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
26
+ app/ai/base.py,sha256=P-mMJyThRO3_LKFsiZdmbh0ZNJNE5yYj4lrAANbvrPQ,3970
27
+ app/ai/claude.py,sha256=cmsLKmbXwFbYzsjZpemzffHimGAkZAmI-7W7DjALvvc,828
28
+ app/ai/codex.py,sha256=lRnSfUVKq-bztHdyyPOjumt8HR1cZuKPCtcKnxlWW94,1384
29
+ app/ai/factory.py,sha256=wRrvrXkEaf2s_y8MQSCUPKzlMHML8hHvDEv8xXeFVl4,919
30
+ app/ai/gemini.py,sha256=b2KffbocKOH5DiztBj55L0mXHcQvp6zFo23Dzq_1mec,824
31
+ app/ai/model_catalog.py,sha256=U0MEl_p7CSIchfLtqjv0TZZiGNCTvcAvEveCkc0eLqE,1508
32
+ app/ai/usage.py,sha256=R9PPrqF9Ont6QqrM7T7bgIkXg3A7cocgNCAqFUGeHnc,4149
33
+ app/git/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
34
+ app/git/ai_commit.py,sha256=vuAtv0XbkBjauZDZYYAHwqvzL6co72YVo-2yCvag8NM,3201
35
+ app/git/branch_naming.py,sha256=yOCY848-qD8VeRqR_d04rbQhm1rOv46CH1ZjduWoyC0,650
36
+ app/git/commit_message.py,sha256=iMmlrl2wjqCe00h6-V4NkT6Ds6PnLZAuv8BmZOebyfc,9519
37
+ app/git/service.py,sha256=NoF-jMy43kDfYbdgeG_uDrYh9-wvK691BR4Yq0bJBA8,29503
38
+ app/jobs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
39
+ app/jobs/manager.py,sha256=oj0f6EPHr5HKFRNytO3qewbJG-CDLzJQ3H5Az-Bm1hc,32591
40
+ app/jobs/schemas.py,sha256=8XLSViaWhM7OPMXAWT2VCLZFZD6Sdx0zBnHD5iK3FYI,3763
41
+ app/jobs/store.py,sha256=jg6sJI1xqZf-1OivVG-VJ2G6Bc76bP4xIuFc2Bq1DRk,10575
42
+ app/monitoring/__init__.py,sha256=LZ37COJbHd6ocla0QmOB3JiO0l6pkUuZ5BDkug92ew4,320
43
+ app/monitoring/code.py,sha256=GRbv2gUMdGNwDltUlU7ic5IekgO9W5DWnPHd2mRd6dg,3763
44
+ app/monitoring/events.py,sha256=23Pb860mWtrAdm0c93Rh9vg-ajJ8gePYnA8t6tQMpN0,1234
45
+ app/monitoring/git.py,sha256=dQRw4MNNiwyDR_3KfHGP0czv_u4BU-SSsElV9N6jBNM,3284
46
+ app/monitoring/log_buffer.py,sha256=Zd6XmohhwW37pVw_c_duR1Wqbzl8ec13wrmXW_H4Bjg,7679
47
+ app/monitoring/memory.py,sha256=hb2i_gsyM07gniIYFtDEJmkZhpfSaaSE-6fTcrvBe3Y,750
48
+ app/monitoring/model.py,sha256=pCkIDvfulW5ntma-eCMIic3W9BPzoODdQ98jXm8q654,21311
49
+ app/projects/__init__.py,sha256=al8Pc9sK00qfgicP4fhWcoCSgDS4_rti1blipNvXcGI,469
50
+ app/projects/registry.py,sha256=YsL4LhKcWa0akxyPFXDXBp4LYc7zTca_Mi6g-j3kPoo,14597
51
+ app/security/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
52
+ app/security/auth.py,sha256=3eyav6h8bUkIPaBdMofLi-Qh72IZAWSbZV30gI436YQ,729
53
+ app/telegram/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
54
+ app/telegram/bot_instances.py,sha256=LsJfEF0zqbgO5SUvBpvotbJnPFPlVcF7pcPRZWRcfaE,2206
55
+ app/telegram/confirmations.py,sha256=DRXyHsrwN2wN8nD4xD4aC-iYfrQFIMKCM23h5LxV5aY,1163
56
+ app/telegram/conversation.py,sha256=BGga5GUKYMRm5kc6EdAYZ8qvQXj-8C-jGQSnSperWc4,29437
57
+ app/telegram/i18n.py,sha256=AI2oDNURuTmTRIur4tC8ocFKnRh9zIqG03gnZNduUTE,36792
58
+ app/telegram/model_preferences.py,sha256=2B0AMvYe_lP_w9Lb0gHxvVEWpEWczb4fMcvyOnOIPYg,1751
59
+ app/telegram/notifier.py,sha256=dS3zZLh3GeXAyMjTDwyIV7wVNQ0m80T1nbBup98o2Bw,13660
60
+ app/telegram/parser.py,sha256=gOJ67-3GGPDoQUMjv66X_YjHCqDATUArF0SmYlrBF_s,10030
61
+ app/telegram/webhook.py,sha256=Ak3N79IYiHb7V8kj52f8wJsMOgBHYWRwLc7IThb5EKc,38508
62
+ app/telegram/webhook_registration.py,sha256=x1K1TQONHYZtFZNQGGSn9ZZ5Z7i53Igi4-HEUsk1qOQ,5957
63
+ app/telegram/commands/__init__.py,sha256=IKDnP8K876gnLHopbZVYJeU2IWlFGMSclTqAnl425Rc,1785
64
+ app/telegram/commands/base.py,sha256=FEfGeuERZzXKqTqEQD1zDbDqFDfVkSDGneg6rLCvbTM,6988
65
+ app/telegram/commands/branch.py,sha256=-LbYq8hTieho9Z9dDQpSYFMr9JILnjPv_3G1S54H8Bc,14246
66
+ app/telegram/commands/clear_stop.py,sha256=_IOdaYHNrDK6RVf2qiHhU21_sZm7wgnes__seb1c2do,8791
67
+ app/telegram/commands/fix.py,sha256=PWQd7c3l7Q-17AewRaYkRNDbZVEHGANfli-5VpceQio,8396
68
+ app/telegram/commands/model.py,sha256=OKbc6RWx2OLrxcIvH8PpugZw0mEfiWHBguAHJzT-IQE,3784
69
+ app/telegram/commands/monitor.py,sha256=ZVJlQH6P3ciniPSHeoHOOyeGKfWRIj5aoiLTo3BFUpE,7037
70
+ app/telegram/commands/registry.py,sha256=CGiuE0yLOS31E6I8OPQxRy06SstE7-cbnYuxF4EU9MI,4208
71
+ app/telegram/commands/status.py,sha256=Fu3J_jl-AsnpUZJYdX1djIbyPiLRg_nuUhaAAf-zvOw,9374
72
+ app/telegram/commands/system.py,sha256=N7bA2IsmxvICg2vqlhc6Vh7Gms8x3nO-mD61swvJko4,7484
73
+ remote_coder-0.4.1.dist-info/licenses/LICENSE,sha256=FFfCUXYXk8mH1AvSko1CKJHPX0V_mYScxk3-93glzO8,11337
74
+ remote_coder-0.4.1.dist-info/METADATA,sha256=0AgMnlkaNkv2GT6oL2pLEBpLsV6LpFWw3DAS2b6GPxk,37792
75
+ remote_coder-0.4.1.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
76
+ remote_coder-0.4.1.dist-info/entry_points.txt,sha256=-K8RVbObDXZhMoZFhEqL-wQdgZCIYw6eVj-tWXB8T9U,46
77
+ remote_coder-0.4.1.dist-info/top_level.txt,sha256=io9g7LCbfmTG1SFKgEOGXmCFB9uMP2H5lerm0HiHWQE,4
78
+ remote_coder-0.4.1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ remote-coder = app.cli:main