Skip to content

Commit ae0af59

Browse files
committed
feat: add one-click launcher and PyInstaller build support
- Add launcher.py that auto-starts OpenCode server + GUI together - Add PyInstaller spec file for building standalone .exe - Add build.bat script for easy executable building - Add run.bat for quick development launching - Update pyproject.toml with build dependencies and new entry point
1 parent ac99953 commit ae0af59

5 files changed

Lines changed: 179 additions & 0 deletions

File tree

build.bat

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
@echo off
2+
echo ========================================
3+
echo Building tp-opencode Executable
4+
echo ========================================
5+
echo.
6+
7+
cd /d "%~dp0"
8+
9+
echo Installing build dependencies...
10+
pip install -e ".[build]" -q
11+
12+
echo.
13+
echo Building with PyInstaller...
14+
pyinstaller --clean tp-opencode.spec
15+
16+
echo.
17+
echo ========================================
18+
echo Build complete!
19+
echo Executable: dist\tp-opencode\tp-opencode.exe
20+
echo ========================================
21+
pause

pyproject.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,14 @@ dev = [
4646
"ruff>=0.9",
4747
"mypy>=1.14",
4848
]
49+
build = [
50+
"pyinstaller>=6.0",
51+
]
4952

5053
[project.scripts]
5154
opencode-tg = "opencode_telegram_bot.main:main"
5255
opencode-telegram = "opencode_telegram_bot.main:main"
56+
opencode-tg-app = "opencode_telegram_bot.launcher:launch"
5357

5458
[project.urls]
5559
Homepage = "https://github.com/2241812/tp-opencode"

run.bat

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
@echo off
2+
echo ========================================
3+
echo tp-opencode — OpenCode Telegram Bot
4+
echo ========================================
5+
echo.
6+
7+
cd /d "%~dp0"
8+
9+
echo Starting tp-opencode...
10+
python -m opencode_telegram_bot.launcher
11+
12+
pause
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
from __future__ import annotations
2+
3+
import logging
4+
import shutil
5+
import sys
6+
import time
7+
from pathlib import Path
8+
9+
from dotenv import load_dotenv
10+
11+
from opencode_telegram_bot.api import OpenCodeServer
12+
from opencode_telegram_bot.core.config import DEFAULT_CONFIG_DIR
13+
14+
logger = logging.getLogger("tp-opencode-launcher")
15+
16+
17+
def _find_opencode() -> str:
18+
if cmd := shutil.which("opencode"):
19+
return cmd
20+
candidates = [
21+
Path.home() / ".local" / "bin" / "opencode",
22+
Path.home() / ".config" / "opencode" / "bin" / "opencode",
23+
Path.home() / "AppData" / "Local" / "Programs" / "opencode" / "opencode.exe",
24+
Path.home() / "scoop" / "apps" / "opencode" / "current" / "opencode.exe",
25+
Path("C:/Program Files/opencode/opencode.exe"),
26+
]
27+
for c in candidates:
28+
if c.exists():
29+
return str(c)
30+
return "opencode"
31+
32+
33+
def launch() -> None:
34+
env_file = DEFAULT_CONFIG_DIR / ".env"
35+
if env_file.exists():
36+
load_dotenv(env_file, override=True)
37+
38+
from opencode_telegram_bot.core.config import Settings
39+
40+
settings = Settings()
41+
opencode_cmd = settings.opencode_command or _find_opencode()
42+
43+
server = OpenCodeServer(
44+
command=opencode_cmd,
45+
work_dir=settings.opencode_work_dir or None,
46+
)
47+
48+
if settings.opencode_auto_start and not server.is_running:
49+
try:
50+
logger.info("Starting OpenCode server...")
51+
server.start()
52+
time.sleep(3)
53+
logger.info("OpenCode server started.")
54+
except FileNotFoundError:
55+
logger.warning("opencode command not found. GUI will still open.")
56+
57+
from opencode_telegram_bot.gui import main as gui_main
58+
gui_main()
59+
60+
61+
if __name__ == "__main__":
62+
launch()

tp-opencode.spec

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# -*- mode: python ; coding: utf-8 -*-
2+
import sys
3+
from pathlib import Path
4+
5+
block_cipher = None
6+
7+
a = Analysis(
8+
['src/opencode_telegram_bot/launcher.py'],
9+
pathex=['src'],
10+
binaries=[],
11+
datas=[
12+
('src/opencode_telegram_bot/locales', 'opencode_telegram_bot/locales'),
13+
],
14+
hiddenimports=[
15+
'opencode_telegram_bot.api',
16+
'opencode_telegram_bot.api.client',
17+
'opencode_telegram_bot.api.server',
18+
'opencode_telegram_bot.bot',
19+
'opencode_telegram_bot.bot.handler',
20+
'opencode_telegram_bot.core',
21+
'opencode_telegram_bot.core.config',
22+
'opencode_telegram_bot.core.session',
23+
'opencode_telegram_bot.utils',
24+
'opencode_telegram_bot.utils.i18n',
25+
'opencode_telegram_bot.utils.scheduler',
26+
'opencode_telegram_bot.utils.voice',
27+
'opencode_telegram_bot.gui',
28+
'opencode_telegram_bot.web',
29+
'opencode_telegram_bot.web.gui',
30+
'telegram',
31+
'telegram.ext',
32+
'telegram.ext.filters',
33+
'customtkinter',
34+
'flask',
35+
'apscheduler',
36+
'httpx',
37+
'dotenv',
38+
'pydantic',
39+
'pydantic_settings',
40+
],
41+
hookspath=[],
42+
hooksconfig={},
43+
runtime_hooks=[],
44+
excludes=['tkinter.tests', 'PIL.ImageDraw', 'PIL.ImageFont'],
45+
win_no_prefer_redirects=False,
46+
win_private_assemblies=False,
47+
cipher=block_cipher,
48+
noarchive=False,
49+
)
50+
51+
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
52+
53+
exe = EXE(
54+
pyz,
55+
a.scripts,
56+
[],
57+
exclude_binaries=True,
58+
name='tp-opencode',
59+
debug=False,
60+
bootloader_ignore_signals=False,
61+
strip=False,
62+
upx=True,
63+
console=True,
64+
disable_windowed_traceback=False,
65+
argv_emulation=False,
66+
target_arch=None,
67+
codesign_identity=None,
68+
entitlements_file=None,
69+
)
70+
71+
coll = COLLECT(
72+
exe,
73+
a.binaries,
74+
a.zipfiles,
75+
a.datas,
76+
strip=False,
77+
upx=True,
78+
upx_exclude=[],
79+
name='tp-opencode',
80+
)

0 commit comments

Comments
 (0)