vibego 0.2.52__py3-none-any.whl → 1.0.0__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.
Potentially problematic release.
This version of vibego might be problematic. Click here for more details.
- bot.py +1557 -1431
- logging_setup.py +25 -18
- master.py +799 -508
- project_repository.py +42 -40
- scripts/__init__.py +1 -2
- scripts/bump_version.sh +57 -55
- scripts/log_writer.py +19 -16
- scripts/master_healthcheck.py +44 -44
- scripts/models/claudecode.sh +4 -4
- scripts/models/codex.sh +1 -1
- scripts/models/common.sh +24 -6
- scripts/models/gemini.sh +2 -2
- scripts/publish.sh +50 -50
- scripts/run_bot.sh +38 -17
- scripts/start.sh +136 -116
- scripts/start_tmux_codex.sh +8 -8
- scripts/stop_all.sh +21 -21
- scripts/stop_bot.sh +31 -10
- scripts/test_deps_check.sh +32 -28
- tasks/__init__.py +1 -1
- tasks/commands.py +4 -4
- tasks/constants.py +1 -1
- tasks/fsm.py +9 -9
- tasks/models.py +7 -7
- tasks/service.py +56 -56
- vibego-1.0.0.dist-info/METADATA +236 -0
- {vibego-0.2.52.dist-info → vibego-1.0.0.dist-info}/RECORD +36 -35
- vibego-1.0.0.dist-info/licenses/LICENSE +201 -0
- vibego_cli/__init__.py +5 -4
- vibego_cli/__main__.py +1 -2
- vibego_cli/config.py +9 -9
- vibego_cli/deps.py +8 -9
- vibego_cli/main.py +63 -63
- vibego-0.2.52.dist-info/METADATA +0 -197
- {vibego-0.2.52.dist-info → vibego-1.0.0.dist-info}/WHEEL +0 -0
- {vibego-0.2.52.dist-info → vibego-1.0.0.dist-info}/entry_points.txt +0 -0
- {vibego-0.2.52.dist-info → vibego-1.0.0.dist-info}/top_level.txt +0 -0
scripts/master_healthcheck.py
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
"""Master
|
|
2
|
+
"""Master Post-startup health check script.
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
1.
|
|
6
|
-
2.
|
|
7
|
-
3.
|
|
8
|
-
4.
|
|
9
|
-
5.
|
|
4
|
+
Process:
|
|
5
|
+
1. Wait for a startup flag to appear in the master log.
|
|
6
|
+
2. Call MasterManager to start the specified worker (default hyphavibebotbackend).
|
|
7
|
+
3. Automatically discover the worker's chat_id(Prioritize the state file, then read the latest log).
|
|
8
|
+
4. Send a probe message to the chat through the Telegram Bot API to confirm that the sending is successful.
|
|
9
|
+
5. If any step fails, an exception is thrown and an attempt is made to notify the administrator.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Note: This script will not automatically retry the restart and will only return a non-zero exit code for processing by the outer script.
|
|
12
12
|
"""
|
|
13
13
|
from __future__ import annotations
|
|
14
14
|
|
|
@@ -24,11 +24,11 @@ from typing import Optional
|
|
|
24
24
|
from urllib.error import URLError, HTTPError
|
|
25
25
|
from urllib.request import Request, urlopen
|
|
26
26
|
|
|
27
|
-
#
|
|
27
|
+
# Import the configuration and tools in master and reuse the project parsing logic
|
|
28
28
|
ROOT_DIR = Path(__file__).resolve().parent.parent
|
|
29
29
|
ROOT_DIR_STR = str(ROOT_DIR)
|
|
30
30
|
if ROOT_DIR_STR not in sys.path:
|
|
31
|
-
#
|
|
31
|
+
# Make sure the master module can be imported from the repository root
|
|
32
32
|
sys.path.insert(0, ROOT_DIR_STR)
|
|
33
33
|
|
|
34
34
|
import master # type: ignore
|
|
@@ -41,19 +41,19 @@ REPOSITORY = ProjectRepository(master.CONFIG_DB_PATH, master.CONFIG_PATH)
|
|
|
41
41
|
|
|
42
42
|
|
|
43
43
|
def _load_project(project_id: str) -> master.ProjectConfig:
|
|
44
|
-
"""
|
|
44
|
+
"""Get the project configuration based on the slug or bot name, and list the options on failure."""
|
|
45
45
|
|
|
46
46
|
record = REPOSITORY.get_by_slug(project_id)
|
|
47
47
|
if record is None:
|
|
48
48
|
record = REPOSITORY.get_by_bot_name(project_id)
|
|
49
49
|
if record is None:
|
|
50
50
|
available = [r.project_slug for r in REPOSITORY.list_projects()]
|
|
51
|
-
raise RuntimeError(f"
|
|
51
|
+
raise RuntimeError(f"No items found {project_id}, Optional items: {available}")
|
|
52
52
|
return master.ProjectConfig.from_dict(record.to_dict())
|
|
53
53
|
|
|
54
54
|
|
|
55
55
|
def _wait_for_log_flag(path: Path, pattern: str, timeout: float) -> None:
|
|
56
|
-
"""
|
|
56
|
+
"""Waits for a specific mark in the log within the timeout period."""
|
|
57
57
|
|
|
58
58
|
deadline = time.monotonic() + timeout
|
|
59
59
|
position = 0
|
|
@@ -72,11 +72,11 @@ def _wait_for_log_flag(path: Path, pattern: str, timeout: float) -> None:
|
|
|
72
72
|
if pattern in line:
|
|
73
73
|
return
|
|
74
74
|
time.sleep(0.5)
|
|
75
|
-
raise TimeoutError(f"
|
|
75
|
+
raise TimeoutError(f"exist {timeout:.0f} No log markers detected in seconds: {pattern}")
|
|
76
76
|
|
|
77
77
|
|
|
78
78
|
def _extract_chat_id_from_logs(log_path: Path) -> Optional[int]:
|
|
79
|
-
"""
|
|
79
|
+
"""Find the most recent chat from the log file in reverse order_id."""
|
|
80
80
|
|
|
81
81
|
if not log_path.exists():
|
|
82
82
|
return None
|
|
@@ -85,7 +85,7 @@ def _extract_chat_id_from_logs(log_path: Path) -> Optional[int]:
|
|
|
85
85
|
lines = log_path.read_text(encoding="utf-8", errors="ignore").splitlines()
|
|
86
86
|
except Exception:
|
|
87
87
|
return None
|
|
88
|
-
for line in reversed(lines[-200:]): #
|
|
88
|
+
for line in reversed(lines[-200:]): # Reverse search for recent records
|
|
89
89
|
match = pattern.search(line)
|
|
90
90
|
if match:
|
|
91
91
|
try:
|
|
@@ -96,25 +96,25 @@ def _extract_chat_id_from_logs(log_path: Path) -> Optional[int]:
|
|
|
96
96
|
|
|
97
97
|
|
|
98
98
|
def _ensure_chat_id(cfg: master.ProjectConfig, manager: master.MasterManager) -> int:
|
|
99
|
-
"""
|
|
99
|
+
"""Make sure the task is assigned chat_id, Backfill from log and write back to state if necessary."""
|
|
100
100
|
|
|
101
101
|
state = manager.state_store.data.get(cfg.project_slug)
|
|
102
102
|
if state and state.chat_id:
|
|
103
103
|
return int(state.chat_id)
|
|
104
|
-
#
|
|
104
|
+
# Fall back to log search
|
|
105
105
|
log_dir = master.LOG_ROOT_PATH / (cfg.default_model.lower()) / cfg.project_slug
|
|
106
106
|
chat_id = _extract_chat_id_from_logs(log_dir / "run_bot.log")
|
|
107
107
|
if chat_id is None:
|
|
108
108
|
raise RuntimeError(
|
|
109
|
-
"
|
|
109
|
+
"Unable to get chat automatically_id, Please manually have a conversation with the bot to write the state/log"
|
|
110
110
|
)
|
|
111
|
-
#
|
|
111
|
+
# will discover chat_id Write back the state for easy reuse next time
|
|
112
112
|
manager.state_store.update(cfg.project_slug, chat_id=chat_id)
|
|
113
113
|
return chat_id
|
|
114
114
|
|
|
115
115
|
|
|
116
116
|
def _send_probe(bot_token: str, chat_id: int, text: str, timeout: float) -> None:
|
|
117
|
-
"""
|
|
117
|
+
"""Send a probe message to the specified chat to verify that the Telegram API is available."""
|
|
118
118
|
|
|
119
119
|
url = f"https://api.telegram.org/bot{bot_token}/sendMessage"
|
|
120
120
|
payload = json.dumps({"chat_id": chat_id, "text": text, "disable_notification": True}).encode("utf-8")
|
|
@@ -122,26 +122,26 @@ def _send_probe(bot_token: str, chat_id: int, text: str, timeout: float) -> None
|
|
|
122
122
|
try:
|
|
123
123
|
with urlopen(request, timeout=timeout) as resp:
|
|
124
124
|
data = json.loads(resp.read().decode("utf-8"))
|
|
125
|
-
except HTTPError as exc: # pragma: no cover -
|
|
126
|
-
raise RuntimeError(f"
|
|
127
|
-
except URLError as exc: # pragma: no cover -
|
|
128
|
-
raise RuntimeError(f"
|
|
125
|
+
except HTTPError as exc: # pragma: no cover - Thrown when network exception occurs
|
|
126
|
+
raise RuntimeError(f"Failed to send probe message, HTTP {exc.code}: {exc.reason}") from exc
|
|
127
|
+
except URLError as exc: # pragma: no cover - Thrown when network exception occurs
|
|
128
|
+
raise RuntimeError(f"Failed to send probe message: {exc}") from exc
|
|
129
129
|
if not data.get("ok"):
|
|
130
|
-
raise RuntimeError(f"
|
|
130
|
+
raise RuntimeError(f"Failed to send probe message: {data}")
|
|
131
131
|
|
|
132
132
|
|
|
133
133
|
def _format_admin_notice(reason: str) -> str:
|
|
134
|
-
"""
|
|
134
|
+
"""Generate alarm text to notify the administrator."""
|
|
135
135
|
|
|
136
136
|
return (
|
|
137
|
-
"Master
|
|
138
|
-
f"
|
|
139
|
-
"
|
|
137
|
+
"Master Restart health check failed\n"
|
|
138
|
+
f"reason:{reason}\n"
|
|
139
|
+
"Please log in to the server as soon as possible to troubleshoot (start.log / vibe.log)."
|
|
140
140
|
)
|
|
141
141
|
|
|
142
142
|
|
|
143
143
|
def _notify_admins(reason: str) -> None:
|
|
144
|
-
"""
|
|
144
|
+
"""If the master token is available, the failure reason is broadcast to the administrator list."""
|
|
145
145
|
|
|
146
146
|
master_token = os.environ.get("MASTER_BOT_TOKEN")
|
|
147
147
|
if not master_token:
|
|
@@ -164,7 +164,7 @@ def _notify_admins(reason: str) -> None:
|
|
|
164
164
|
|
|
165
165
|
|
|
166
166
|
def _ensure_worker(cfg: master.ProjectConfig) -> master.MasterManager:
|
|
167
|
-
"""
|
|
167
|
+
"""Starts the specified project worker and returns the temporarily constructed MasterManager."""
|
|
168
168
|
|
|
169
169
|
records = REPOSITORY.list_projects()
|
|
170
170
|
configs = [master.ProjectConfig.from_dict(record.to_dict()) for record in records]
|
|
@@ -174,8 +174,8 @@ def _ensure_worker(cfg: master.ProjectConfig) -> master.MasterManager:
|
|
|
174
174
|
manager = master.MasterManager(configs, state_store=state_store)
|
|
175
175
|
|
|
176
176
|
async def _run() -> None:
|
|
177
|
-
"""
|
|
178
|
-
#
|
|
177
|
+
"""The coroutine performs the actual stop/start process."""
|
|
178
|
+
# Make sure to stop the old instance first(If it existsexist)
|
|
179
179
|
try:
|
|
180
180
|
await manager.stop_worker(cfg)
|
|
181
181
|
except Exception:
|
|
@@ -187,20 +187,20 @@ def _ensure_worker(cfg: master.ProjectConfig) -> master.MasterManager:
|
|
|
187
187
|
|
|
188
188
|
|
|
189
189
|
def main() -> int:
|
|
190
|
-
"""
|
|
190
|
+
"""Command line entry, performs master health check and returns exit code."""
|
|
191
191
|
|
|
192
|
-
parser = argparse.ArgumentParser(description="Master
|
|
193
|
-
parser.add_argument("--project", default="hyphavibebotbackend", help="
|
|
194
|
-
parser.add_argument("--master-log", default=str(DEFAULT_MASTER_LOG), help="master
|
|
195
|
-
parser.add_argument("--master-timeout", type=float, default=DEFAULT_TIMEOUT_MASTER, help="master
|
|
196
|
-
parser.add_argument("--probe-timeout", type=float, default=DEFAULT_TIMEOUT_PROBE, help="Telegram
|
|
192
|
+
parser = argparse.ArgumentParser(description="Master Post-launch health check")
|
|
193
|
+
parser.add_argument("--project", default="hyphavibebotbackend", help="Project slug or bot name")
|
|
194
|
+
parser.add_argument("--master-log", default=str(DEFAULT_MASTER_LOG), help="master Log path")
|
|
195
|
+
parser.add_argument("--master-timeout", type=float, default=DEFAULT_TIMEOUT_MASTER, help="master Log wait timeout (Second)")
|
|
196
|
+
parser.add_argument("--probe-timeout", type=float, default=DEFAULT_TIMEOUT_PROBE, help="Telegram Probe timeout (Second)")
|
|
197
197
|
args = parser.parse_args()
|
|
198
198
|
|
|
199
199
|
project_id = master._sanitize_slug(args.project)
|
|
200
200
|
master_log = Path(args.master_log)
|
|
201
201
|
|
|
202
202
|
try:
|
|
203
|
-
_wait_for_log_flag(master_log, "Master
|
|
203
|
+
_wait_for_log_flag(master_log, "Master Started, listening for administrator commands.", args.master_timeout)
|
|
204
204
|
cfg = _load_project(project_id)
|
|
205
205
|
manager = _ensure_worker(cfg)
|
|
206
206
|
chat_id = _ensure_chat_id(cfg, manager)
|
|
@@ -208,12 +208,12 @@ def main() -> int:
|
|
|
208
208
|
except Exception as exc:
|
|
209
209
|
reason = str(exc)
|
|
210
210
|
_notify_admins(reason)
|
|
211
|
-
print(f"[healthcheck]
|
|
211
|
+
print(f"[healthcheck] fail: {reason}", file=sys.stderr)
|
|
212
212
|
return 1
|
|
213
213
|
else:
|
|
214
214
|
print(
|
|
215
|
-
"[healthcheck]
|
|
216
|
-
f"worker={cfg.display_name}
|
|
215
|
+
"[healthcheck] success: master ready,"
|
|
216
|
+
f"worker={cfg.display_name} Startup completed, chat_id={chat_id}, Probe message sent"
|
|
217
217
|
)
|
|
218
218
|
return 0
|
|
219
219
|
|
scripts/models/claudecode.sh
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
# ClaudeCode
|
|
2
|
+
# ClaudeCode Model configuration
|
|
3
3
|
|
|
4
|
-
#
|
|
5
|
-
# Claude
|
|
4
|
+
# Convert the working directory to Claude CLI default project key.
|
|
5
|
+
# Claude The official implementation simply replaces slashes in absolute paths with hyphens, and preserve case.
|
|
6
6
|
claude_project_key_from_workdir() {
|
|
7
7
|
local path="$1"
|
|
8
8
|
if [[ -z "$path" ]]; then
|
|
@@ -20,7 +20,7 @@ claude_project_key_from_workdir() {
|
|
|
20
20
|
model_configure() {
|
|
21
21
|
MODEL_NAME="ClaudeCode"
|
|
22
22
|
MODEL_WORKDIR="${CLAUDE_WORKDIR:-${MODEL_WORKDIR:-$ROOT_DIR}}"
|
|
23
|
-
#
|
|
23
|
+
# File snapshot is turned off by default, avoid orphans CLI Continuous writing jsonl
|
|
24
24
|
CLAUDE_DISABLE_FILE_CHECKPOINTING="${CLAUDE_DISABLE_FILE_CHECKPOINTING:-1}"
|
|
25
25
|
CLAUDE_CODE_DISABLE_FILE_CHECKPOINTING="${CLAUDE_CODE_DISABLE_FILE_CHECKPOINTING:-$CLAUDE_DISABLE_FILE_CHECKPOINTING}"
|
|
26
26
|
export CLAUDE_CODE_DISABLE_FILE_CHECKPOINTING
|
scripts/models/codex.sh
CHANGED
scripts/models/common.sh
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
#
|
|
2
|
+
# Public Tools: Model Scripts/run script/Stop script sharing
|
|
3
3
|
|
|
4
|
-
#
|
|
4
|
+
# Avoid overwriting when repeating definitions
|
|
5
5
|
if [[ -n "${_MODEL_COMMON_LOADED:-}" ]]; then
|
|
6
6
|
return
|
|
7
7
|
fi
|
|
@@ -9,10 +9,29 @@ _MODEL_COMMON_LOADED=1
|
|
|
9
9
|
|
|
10
10
|
COMMON_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
11
|
ROOT_DIR="${ROOT_DIR:-$(cd "$COMMON_DIR/.." && pwd)}"
|
|
12
|
-
|
|
12
|
+
resolve_config_root() {
|
|
13
|
+
local raw=""
|
|
14
|
+
if [[ -n "${MASTER_CONFIG_ROOT:-}" ]]; then
|
|
15
|
+
raw="$MASTER_CONFIG_ROOT"
|
|
16
|
+
elif [[ -n "${VIBEGO_CONFIG_DIR:-}" ]]; then
|
|
17
|
+
raw="$VIBEGO_CONFIG_DIR"
|
|
18
|
+
elif [[ -n "${XDG_CONFIG_HOME:-}" ]]; then
|
|
19
|
+
raw="${XDG_CONFIG_HOME%/}/vibego"
|
|
20
|
+
else
|
|
21
|
+
raw="$HOME/.config/vibego"
|
|
22
|
+
fi
|
|
23
|
+
if [[ "$raw" == ~* ]]; then
|
|
24
|
+
printf '%s' "${raw/#\~/$HOME}"
|
|
25
|
+
else
|
|
26
|
+
printf '%s' "$raw"
|
|
27
|
+
fi
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
CONFIG_ROOT="${CONFIG_ROOT:-$(resolve_config_root)}"
|
|
31
|
+
LOG_ROOT="${LOG_ROOT:-$CONFIG_ROOT/logs}"
|
|
13
32
|
TMUX_SESSION_PREFIX="${TMUX_SESSION_PREFIX:-vibe}"
|
|
14
33
|
|
|
15
|
-
#
|
|
34
|
+
# Change any path/Name converted to tmux/session Wait for a safe slug
|
|
16
35
|
sanitize_slug() {
|
|
17
36
|
local input="$1"
|
|
18
37
|
if [[ -z "$input" ]]; then
|
|
@@ -34,7 +53,7 @@ project_slug_from_workdir() {
|
|
|
34
53
|
printf 'project'
|
|
35
54
|
return
|
|
36
55
|
fi
|
|
37
|
-
#
|
|
56
|
+
# Rewrite the absolute path to something similar to Claude -Users-... form
|
|
38
57
|
local replaced
|
|
39
58
|
replaced=$(printf '%s' "$path" | sed 's#/#-#g')
|
|
40
59
|
replaced="${replaced#-}"
|
|
@@ -87,4 +106,3 @@ find_latest_with_pattern() {
|
|
|
87
106
|
done < <(find "$root" -type f -name "$pattern" -print0 2>/dev/null)
|
|
88
107
|
[[ -n "$latest" ]] && printf '%s\n' "$latest"
|
|
89
108
|
}
|
|
90
|
-
|
scripts/models/gemini.sh
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
# Gemini
|
|
2
|
+
# Gemini Model placeholder configuration (to be implemented)
|
|
3
3
|
|
|
4
4
|
model_configure() {
|
|
5
5
|
MODEL_NAME="gemini"
|
|
6
6
|
MODEL_WORKDIR="${GEMINI_WORKDIR:-${MODEL_WORKDIR:-$ROOT_DIR}}"
|
|
7
|
-
MODEL_CMD="${GEMINI_CMD:-echo 'gemini CLI
|
|
7
|
+
MODEL_CMD="${GEMINI_CMD:-echo 'gemini CLI Not configured yet'; sleep 1}"
|
|
8
8
|
MODEL_SESSION_ROOT="${GEMINI_SESSION_ROOT:-$LOG_ROOT/gemini-placeholder}"
|
|
9
9
|
MODEL_SESSION_GLOB="${GEMINI_SESSION_GLOB:-*.jsonl}"
|
|
10
10
|
MODEL_POINTER_BASENAME="${MODEL_POINTER_BASENAME:-current_session.txt}"
|
scripts/publish.sh
CHANGED
|
@@ -1,33 +1,33 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
# VibeGo
|
|
3
|
-
#
|
|
2
|
+
# VibeGo Full release script
|
|
3
|
+
# Use keyring for PyPI authentication without manually entering tokens
|
|
4
4
|
#
|
|
5
|
-
#
|
|
6
|
-
# 1.
|
|
7
|
-
# 2.
|
|
5
|
+
# Prerequisites:
|
|
6
|
+
# 1. keyring installed: pip install keyring
|
|
7
|
+
# 2. PyPI token stored in keyring:
|
|
8
8
|
# python3.11 -c "import keyring; keyring.set_password('https://upload.pypi.org/legacy/', '__token__', 'your-token')"
|
|
9
9
|
#
|
|
10
|
-
#
|
|
11
|
-
# ./scripts/publish.sh #
|
|
12
|
-
# ./scripts/publish.sh minor #
|
|
13
|
-
# ./scripts/publish.sh major #
|
|
10
|
+
# How to use:
|
|
11
|
+
# ./scripts/publish.sh # Publish patch version (default)
|
|
12
|
+
# ./scripts/publish.sh minor # Release minor version
|
|
13
|
+
# ./scripts/publish.sh major # Release major version
|
|
14
14
|
|
|
15
15
|
set -e
|
|
16
16
|
|
|
17
|
-
#
|
|
17
|
+
# color definition
|
|
18
18
|
RED='\033[0;31m'
|
|
19
19
|
GREEN='\033[0;32m'
|
|
20
20
|
YELLOW='\033[1;33m'
|
|
21
21
|
BLUE='\033[0;34m'
|
|
22
22
|
NC='\033[0m' # No Color
|
|
23
23
|
|
|
24
|
-
#
|
|
24
|
+
# Print colored messages
|
|
25
25
|
print_info() {
|
|
26
26
|
echo -e "${BLUE}ℹ️ $1${NC}"
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
print_success() {
|
|
30
|
-
echo -e "${GREEN}
|
|
30
|
+
echo -e "${GREEN}OK: $1${NC}"
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
print_warning() {
|
|
@@ -35,92 +35,92 @@ print_warning() {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
print_error() {
|
|
38
|
-
echo -e "${RED}
|
|
38
|
+
echo -e "${RED}ERROR: $1${NC}"
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
#
|
|
41
|
+
# Project root directory
|
|
42
42
|
PROJECT_ROOT="/Users/david/hypha/tools/vibeBot"
|
|
43
43
|
cd "$PROJECT_ROOT"
|
|
44
44
|
|
|
45
|
-
print_info "
|
|
45
|
+
print_info "Start the VibeGo publishing process..."
|
|
46
46
|
echo ""
|
|
47
47
|
|
|
48
|
-
#
|
|
49
|
-
print_info "
|
|
48
|
+
# Step 1: Check if PyPI token is stored in keyring
|
|
49
|
+
print_info "Check keyring configuration..."
|
|
50
50
|
if ! python3.11 -c "import keyring; token = keyring.get_password('https://upload.pypi.org/legacy/', '__token__'); exit(0 if token else 1)" 2>/dev/null; then
|
|
51
|
-
print_error "
|
|
51
|
+
print_error "PyPI token not found in keyring"
|
|
52
52
|
echo ""
|
|
53
|
-
echo "
|
|
53
|
+
echo "Please execute the following command to store the token first:"
|
|
54
54
|
echo " python3.11 -c \"import keyring; keyring.set_password('https://upload.pypi.org/legacy/', '__token__', 'your-pypi-token')\""
|
|
55
55
|
echo ""
|
|
56
56
|
exit 1
|
|
57
57
|
fi
|
|
58
|
-
print_success "Keyring
|
|
58
|
+
print_success "Keyring Configured correctly"
|
|
59
59
|
echo ""
|
|
60
60
|
|
|
61
|
-
#
|
|
62
|
-
print_info "
|
|
61
|
+
# Step 2: create/Activate virtual environment
|
|
62
|
+
print_info "createBuild a virtual environment..."
|
|
63
63
|
python3.11 -m venv ~/.venvs/vibego-build
|
|
64
64
|
source ~/.venvs/vibego-build/bin/activate
|
|
65
|
-
print_success "
|
|
65
|
+
print_success "Virtual environment is activated"
|
|
66
66
|
echo ""
|
|
67
67
|
|
|
68
|
-
#
|
|
69
|
-
print_info "
|
|
68
|
+
# Step 3: Upgrade pip and install build tools
|
|
69
|
+
print_info "Install build dependencies..."
|
|
70
70
|
pip install --upgrade pip build twine keyring > /dev/null 2>&1
|
|
71
|
-
print_success "
|
|
71
|
+
print_success "Build dependencies installed"
|
|
72
72
|
echo ""
|
|
73
73
|
|
|
74
|
-
#
|
|
75
|
-
print_info "
|
|
74
|
+
# Step 4: Clean up old build artifacts
|
|
75
|
+
print_info "Clean up old build artifacts..."
|
|
76
76
|
rm -rf "$PROJECT_ROOT/dist"
|
|
77
|
-
print_success "
|
|
77
|
+
print_success "Build artifacts cleaned"
|
|
78
78
|
echo ""
|
|
79
79
|
|
|
80
|
-
#
|
|
81
|
-
VERSION_TYPE="${1:-patch}" #
|
|
82
|
-
print_info "
|
|
80
|
+
# Step 5: Increment version number
|
|
81
|
+
VERSION_TYPE="${1:-patch}" # Default is patch
|
|
82
|
+
print_info "Increment version number (type:$VERSION_TYPE)..."
|
|
83
83
|
./scripts/bump_version.sh "$VERSION_TYPE"
|
|
84
84
|
echo ""
|
|
85
85
|
|
|
86
|
-
#
|
|
87
|
-
print_info "
|
|
86
|
+
# Step 6: Build distribution package
|
|
87
|
+
print_info "Build the Python distribution..."
|
|
88
88
|
python3.11 -m build
|
|
89
|
-
print_success "
|
|
89
|
+
print_success "The distribution package is built"
|
|
90
90
|
echo ""
|
|
91
91
|
|
|
92
|
-
#
|
|
93
|
-
print_info "
|
|
92
|
+
# Step 7: Upload to PyPI (automatic authentication using keyring)
|
|
93
|
+
print_info "Upload to PyPI (using keyring authentication)..."
|
|
94
94
|
twine upload dist/*
|
|
95
|
-
print_success "
|
|
95
|
+
print_success "Successfully uploaded to PyPI"
|
|
96
96
|
echo ""
|
|
97
97
|
|
|
98
|
-
#
|
|
99
|
-
print_info "
|
|
98
|
+
# Step 8: Clean and reinstall vibego in pipx
|
|
99
|
+
print_info "Update local pipx installation..."
|
|
100
100
|
rm -rf ~/.cache/pipx
|
|
101
101
|
rm -rf ~/.local/pipx/venvs/vibego
|
|
102
102
|
pipx install --python python3.11 vibego
|
|
103
103
|
pipx upgrade vibego
|
|
104
|
-
print_success "
|
|
104
|
+
print_success "local vibego updated"
|
|
105
105
|
echo ""
|
|
106
106
|
|
|
107
|
-
#
|
|
108
|
-
print_info "
|
|
109
|
-
vibego stop || true #
|
|
107
|
+
# Step 9: Restart vibego service
|
|
108
|
+
print_info "Restart vibego service..."
|
|
109
|
+
vibego stop || true # Ignore stop failure errors
|
|
110
110
|
sleep 2
|
|
111
111
|
vibego start
|
|
112
|
-
print_success "vibego
|
|
112
|
+
print_success "vibego Service has been restarted"
|
|
113
113
|
echo ""
|
|
114
114
|
|
|
115
|
-
#
|
|
115
|
+
# Complete
|
|
116
116
|
print_success "========================================="
|
|
117
|
-
print_success "🎉
|
|
117
|
+
print_success "🎉 The publishing process is complete!"
|
|
118
118
|
print_success "========================================="
|
|
119
119
|
echo ""
|
|
120
|
-
print_info "
|
|
121
|
-
echo " 1.
|
|
120
|
+
print_info "Next steps:"
|
|
121
|
+
echo " 1. Push git commits and tags:"
|
|
122
122
|
echo " git push && git push --tags"
|
|
123
123
|
echo ""
|
|
124
|
-
echo " 2.
|
|
124
|
+
echo " 2. Verify PyPI page:"
|
|
125
125
|
echo " https://pypi.org/project/vibego/"
|
|
126
126
|
echo ""
|
scripts/run_bot.sh
CHANGED
|
@@ -1,11 +1,32 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
set -euo pipefail
|
|
3
3
|
|
|
4
|
+
# shellcheck disable=SC2155
|
|
4
5
|
SOURCE_ROOT="${VIBEGO_PACKAGE_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}"
|
|
5
|
-
|
|
6
|
+
|
|
7
|
+
resolve_config_root() {
|
|
8
|
+
local raw=""
|
|
9
|
+
if [[ -n "${MASTER_CONFIG_ROOT:-}" ]]; then
|
|
10
|
+
raw="$MASTER_CONFIG_ROOT"
|
|
11
|
+
elif [[ -n "${VIBEGO_CONFIG_DIR:-}" ]]; then
|
|
12
|
+
raw="$VIBEGO_CONFIG_DIR"
|
|
13
|
+
elif [[ -n "${XDG_CONFIG_HOME:-}" ]]; then
|
|
14
|
+
raw="${XDG_CONFIG_HOME%/}/vibego"
|
|
15
|
+
else
|
|
16
|
+
raw="$HOME/.config/vibego"
|
|
17
|
+
fi
|
|
18
|
+
if [[ "$raw" == ~* ]]; then
|
|
19
|
+
printf '%s' "${raw/#\~/$HOME}"
|
|
20
|
+
else
|
|
21
|
+
printf '%s' "$raw"
|
|
22
|
+
fi
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
CONFIG_ROOT="$(resolve_config_root)"
|
|
26
|
+
RUNTIME_ROOT="${VIBEGO_RUNTIME_ROOT:-$CONFIG_ROOT/runtime}"
|
|
6
27
|
VENV_DIR="$RUNTIME_ROOT/.venv"
|
|
7
28
|
MODELS_DIR="$SOURCE_ROOT/scripts/models"
|
|
8
|
-
LOG_ROOT="${LOG_ROOT:-$
|
|
29
|
+
LOG_ROOT="${LOG_ROOT:-$CONFIG_ROOT/logs}"
|
|
9
30
|
DEFAULT_LOG_FILE="$LOG_ROOT/run_bot.log"
|
|
10
31
|
LOG_FILE="${LOG_FILE:-$DEFAULT_LOG_FILE}"
|
|
11
32
|
MODEL_DEFAULT="${MODEL_DEFAULT:-codex}"
|
|
@@ -13,11 +34,11 @@ PROJECT_DEFAULT="${PROJECT_NAME:-}"
|
|
|
13
34
|
|
|
14
35
|
usage() {
|
|
15
36
|
cat <<USAGE
|
|
16
|
-
|
|
17
|
-
--model
|
|
18
|
-
--project
|
|
19
|
-
--foreground
|
|
20
|
-
--no-stop
|
|
37
|
+
usage:${0##*/} [--model name] [--project name] [--foreground] [--no-stop]
|
|
38
|
+
--model Start the specified model (codex|claudecode|gemini), default: $MODEL_DEFAULT
|
|
39
|
+
--project Specify project alias for logging/Conversation distinction
|
|
40
|
+
--foreground Run in foreground(for debugging), defaultBackstage
|
|
41
|
+
--no-stop Not executed before startup stop_bot.sh(defaultOld instances will be stopped first)
|
|
21
42
|
USAGE
|
|
22
43
|
}
|
|
23
44
|
|
|
@@ -39,7 +60,7 @@ while [[ $# -gt 0 ]]; do
|
|
|
39
60
|
-h|--help)
|
|
40
61
|
usage; exit 0 ;;
|
|
41
62
|
*)
|
|
42
|
-
echo "
|
|
63
|
+
echo "unknown parameters: $1" >&2
|
|
43
64
|
usage
|
|
44
65
|
exit 1 ;;
|
|
45
66
|
esac
|
|
@@ -47,14 +68,14 @@ done
|
|
|
47
68
|
|
|
48
69
|
MODEL_SCRIPT="$MODELS_DIR/$MODEL.sh"
|
|
49
70
|
if [[ ! -f "$MODEL_SCRIPT" ]]; then
|
|
50
|
-
echo "[run-bot]
|
|
71
|
+
echo "[run-bot] Unsupported model: $MODEL" >&2
|
|
51
72
|
exit 1
|
|
52
73
|
fi
|
|
53
74
|
|
|
54
|
-
#
|
|
75
|
+
# Load public functions + Model configuration
|
|
55
76
|
# shellcheck disable=SC1090
|
|
56
77
|
source "$MODELS_DIR/common.sh"
|
|
57
|
-
#
|
|
78
|
+
# Allow model scripts to reuse environment variables
|
|
58
79
|
MODEL_WORKDIR="${MODEL_WORKDIR:-}"
|
|
59
80
|
# shellcheck disable=SC1090
|
|
60
81
|
source "$MODEL_SCRIPT"
|
|
@@ -83,24 +104,24 @@ expand_model_workdir() {
|
|
|
83
104
|
MODEL_WORKDIR="$(expand_model_workdir "$MODEL_WORKDIR")"
|
|
84
105
|
|
|
85
106
|
if [[ -z "$MODEL_WORKDIR" ]]; then
|
|
86
|
-
echo "[run-bot]
|
|
107
|
+
echo "[run-bot] Configuration is missing MODEL_WORKDIR, Please check config/projects.json" >&2
|
|
87
108
|
exit 1
|
|
88
109
|
fi
|
|
89
110
|
|
|
90
111
|
if [[ ! -d "$MODEL_WORKDIR" ]]; then
|
|
91
|
-
echo "[run-bot]
|
|
112
|
+
echo "[run-bot] Working directory does not exist: $MODEL_WORKDIR" >&2
|
|
92
113
|
exit 1
|
|
93
114
|
fi
|
|
94
115
|
|
|
95
116
|
if ! command -v tmux >/dev/null 2>&1; then
|
|
96
|
-
echo "[run-bot]
|
|
117
|
+
echo "[run-bot] tmux not detected, pass 'brew install tmux' Install" >&2
|
|
97
118
|
exit 1
|
|
98
119
|
fi
|
|
99
120
|
|
|
100
121
|
if [[ -n "$MODEL_CMD" ]]; then
|
|
101
122
|
IFS=' ' read -r MODEL_CMD_BIN _ <<<"$MODEL_CMD"
|
|
102
123
|
if [[ -n "$MODEL_CMD_BIN" ]] && ! command -v "$MODEL_CMD_BIN" >/dev/null 2>&1; then
|
|
103
|
-
echo "[run-bot]
|
|
124
|
+
echo "[run-bot] Model command not detected: $MODEL_CMD_BIN" >&2
|
|
104
125
|
exit 1
|
|
105
126
|
fi
|
|
106
127
|
fi
|
|
@@ -112,7 +133,7 @@ if (( FOREGROUND == 0 )); then
|
|
|
112
133
|
CMD=("$0" --model "$MODEL" --project "$PROJECT_NAME" --foreground)
|
|
113
134
|
(( NO_STOP )) && CMD+=(--no-stop)
|
|
114
135
|
nohup "${CMD[@]}" >>"$RUN_LOG" 2>&1 &
|
|
115
|
-
echo "[run-bot]
|
|
136
|
+
echo "[run-bot] Start in background (model=$MODEL project=$PROJECT_NAME) log: $RUN_LOG"
|
|
116
137
|
exit 0
|
|
117
138
|
fi
|
|
118
139
|
|
|
@@ -129,7 +150,7 @@ fi
|
|
|
129
150
|
source "$VENV_DIR/bin/activate"
|
|
130
151
|
REQUIREMENTS_PATH="${VIBEGO_REQUIREMENTS_PATH:-$SOURCE_ROOT/scripts/requirements.txt}"
|
|
131
152
|
if [[ ! -f "$REQUIREMENTS_PATH" ]]; then
|
|
132
|
-
echo "[run-bot]
|
|
153
|
+
echo "[run-bot] Dependency list not found: $REQUIREMENTS_PATH" >&2
|
|
133
154
|
exit 1
|
|
134
155
|
fi
|
|
135
156
|
if [[ ! -f "$VENV_DIR/.requirements.installed" ]] || [[ "$REQUIREMENTS_PATH" -nt "$VENV_DIR/.requirements.installed" ]]; then
|