xb-init 2.2.2__tar.gz → 2.2.3__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.
- {xb_init-2.2.2 → xb_init-2.2.3}/PKG-INFO +4 -1
- {xb_init-2.2.2 → xb_init-2.2.3}/README.md +3 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/pyproject.toml +1 -1
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/root/README.md.j2 +12 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/root/build.py.j2 +105 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/root/dev.py.j2 +106 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/.gitignore +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/docs/screenshot.png +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/tests/test_cli.py +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/tests/test_update_templates.py +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/tests/test_upgrade.py +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/uv.lock +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/__init__.py +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/cli.py +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/commands/__init__.py +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/commands/build.py +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/commands/dev.py +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/commands/doctor.py +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/commands/init.py +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/commands/upgrade.py +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/commands/version.py +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/backend/api/__init__.py.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/backend/api/config.py.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/backend/api/ports.py.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/backend/api/terminal/__init__.py.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/backend/api/terminal/routes.py.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/backend/api/update/__init__.py.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/backend/app_version.py.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/backend/backend_build.py.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/backend/main.py.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/backend/managers/__init__.py.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/backend/managers/logger_manager.py.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/backend/managers/path_manager.py.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/backend/managers/secret_obfuscator.py.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/backend/managers/sudoers_manager.py.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/backend/requirements.txt.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/backend/services/__init__.py.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/backend/services/feishu_client.py.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/backend/services/updater.py.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/configs/config_changes.json.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/configs/global_config.yaml.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/configs/secrets.yaml.example.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/configs/secrets.yaml.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/electron/launcher.js.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/electron/main.js.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/electron/package.json.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/electron/port_diagnostics.js.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/electron/preload.js.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/electron/prepare.js.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/electron/resources/postinst.py.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/electron/resources/postrm.py.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/electron/resources/uninstaller.nsh.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/frontend/index.html.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/frontend/package.json.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/frontend/src/App.vue.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/frontend/src/components/ConfigSetup.vue.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/frontend/src/components/DashboardHome.vue.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/frontend/src/components/FileManager.vue.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/frontend/src/components/GitVersionBadge.vue.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/frontend/src/components/RefreshButton.vue.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/frontend/src/components/TerminalPanel.vue.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/frontend/src/components/TerminalView.vue.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/frontend/src/components/ThemeToggle.vue.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/frontend/src/components/version/CommitHistoryPanel.vue.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/frontend/src/components/version/UpdatePanel.vue.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/frontend/src/composables/useTerminalSessions.js.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/frontend/src/composables/useUpdate.js.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/frontend/src/main.js.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/frontend/src/style.css.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/frontend/vite.config.js.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/root/.gitignore.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/root/AGENTS.md.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/root/pyproject.toml.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/scripts/example.py.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/scripts/feishu_upload.py.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/version/hooks/pre-commit.py.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/version/scripts/gui_version_manager.py.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/version/scripts/install_hooks.py.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/version/scripts/version_manager.py.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/version/scripts/web_version_manager.py.j2 +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/utils/__init__.py +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/utils/click_helpers.py +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/utils/template_engine.py +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/utils/validators.py +0 -0
- {xb_init-2.2.2 → xb_init-2.2.3}/xb/utils/version_check.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: xb-init
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.3
|
|
4
4
|
Summary: Project management tool for UV + FastAPI + Vue3 + Electron desktop applications
|
|
5
5
|
Project-URL: Homepage, https://github.com/xuebli/xb
|
|
6
6
|
Project-URL: Documentation, https://github.com/xuebli/xb#readme
|
|
@@ -126,6 +126,9 @@ Electron 二进制镜像通过 `ELECTRON_MIRROR` 环境变量注入。
|
|
|
126
126
|
> 到最快的(未安装 nrm 时自动全局安装);项目不放 `.npmrc`,npm 源完全由
|
|
127
127
|
> nrm 全局管理
|
|
128
128
|
> - electron 约 200MB 二进制走华为云镜像下载
|
|
129
|
+
> - uv 源同样自动优化:首次依赖同步(dev.py)与后端构建(build.py -b/-a)
|
|
130
|
+
> 前用 [chsrc](https://github.com/RubyMetric/chsrc) 测速切换最快镜像
|
|
131
|
+
> (`chsrc set uv first`,未安装 chsrc 时自动安装)
|
|
129
132
|
> - 若安装失败或超时,会打印提示但不中断项目创建,可稍后手动重试
|
|
130
133
|
> - 执行 `git init` 并提交首个 commit(包含所有文件和 lock 文件)
|
|
131
134
|
> - 若检测到 PyPI 有新版 xb,会询问是否先升级再创建项目
|
|
@@ -97,6 +97,9 @@ Electron 二进制镜像通过 `ELECTRON_MIRROR` 环境变量注入。
|
|
|
97
97
|
> 到最快的(未安装 nrm 时自动全局安装);项目不放 `.npmrc`,npm 源完全由
|
|
98
98
|
> nrm 全局管理
|
|
99
99
|
> - electron 约 200MB 二进制走华为云镜像下载
|
|
100
|
+
> - uv 源同样自动优化:首次依赖同步(dev.py)与后端构建(build.py -b/-a)
|
|
101
|
+
> 前用 [chsrc](https://github.com/RubyMetric/chsrc) 测速切换最快镜像
|
|
102
|
+
> (`chsrc set uv first`,未安装 chsrc 时自动安装)
|
|
100
103
|
> - 若安装失败或超时,会打印提示但不中断项目创建,可稍后手动重试
|
|
101
104
|
> - 执行 `git init` 并提交首个 commit(包含所有文件和 lock 文件)
|
|
102
105
|
> - 若检测到 PyPI 有新版 xb,会询问是否先升级再创建项目
|
|
@@ -395,6 +395,18 @@ Set-Location frontend
|
|
|
395
395
|
npm install
|
|
396
396
|
```
|
|
397
397
|
|
|
398
|
+
**Python 依赖同步慢或失败**
|
|
399
|
+
|
|
400
|
+
uv 镜像源由 [chsrc](https://github.com/RubyMetric/chsrc) 自动管理:首次依赖同步
|
|
401
|
+
(`dev.py`)与后端构建(`build.py -b/-a`)前会自动 `chsrc set uv first`
|
|
402
|
+
测速并切换到最快源;没有 chsrc 时会自动安装
|
|
403
|
+
(`curl https://chsrc.run/posix | sudo bash`)。手动操作:
|
|
404
|
+
|
|
405
|
+
```bash
|
|
406
|
+
chsrc set uv first # 测速并切换最快 uv 源
|
|
407
|
+
chsrc set uv reset # 恢复默认源
|
|
408
|
+
```
|
|
409
|
+
|
|
398
410
|
**npm install 慢或超时**
|
|
399
411
|
|
|
400
412
|
项目的 npm 源由 [nrm](https://github.com/Pana/nrm) 全局管理。`./build.py` 在
|
|
@@ -68,6 +68,110 @@ def require(path: Path, label: str) -> None:
|
|
|
68
68
|
raise SystemExit(f"{label}构建失败,未找到产物: {path}")
|
|
69
69
|
|
|
70
70
|
|
|
71
|
+
def _sudo_password() -> str:
|
|
72
|
+
"""从 configs/secrets.yaml 读 sudo 密码;支持 obf1: 混淆形态(与后端同算法)。"""
|
|
73
|
+
import base64
|
|
74
|
+
|
|
75
|
+
import yaml
|
|
76
|
+
|
|
77
|
+
secrets_file = ROOT / "configs" / "secrets.yaml"
|
|
78
|
+
if not secrets_file.exists():
|
|
79
|
+
return ""
|
|
80
|
+
try:
|
|
81
|
+
data = yaml.safe_load(secrets_file.read_text(encoding="utf-8")) or {}
|
|
82
|
+
value = str(data.get("sudo_password") or "")
|
|
83
|
+
except Exception:
|
|
84
|
+
return ""
|
|
85
|
+
if value.startswith("obf1:"):
|
|
86
|
+
key = b"[[ package_name ]]$SecretObfuscation#2026"
|
|
87
|
+
try:
|
|
88
|
+
raw = base64.urlsafe_b64decode(value[len("obf1:"):].encode("ascii"))
|
|
89
|
+
return bytes(b ^ key[i % len(key)] for i, b in enumerate(raw)).decode("utf-8")
|
|
90
|
+
except Exception:
|
|
91
|
+
return ""
|
|
92
|
+
return value
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _save_sudo_password(password: str) -> None:
|
|
96
|
+
"""把 sudo 密码合并写进 configs/secrets.yaml(保留其他键;已 gitignore)。"""
|
|
97
|
+
import yaml
|
|
98
|
+
|
|
99
|
+
secrets_file = ROOT / "configs" / "secrets.yaml"
|
|
100
|
+
data = {}
|
|
101
|
+
if secrets_file.exists():
|
|
102
|
+
try:
|
|
103
|
+
data = yaml.safe_load(secrets_file.read_text(encoding="utf-8")) or {}
|
|
104
|
+
except Exception:
|
|
105
|
+
data = {}
|
|
106
|
+
data["sudo_password"] = password
|
|
107
|
+
secrets_file.parent.mkdir(parents=True, exist_ok=True)
|
|
108
|
+
secrets_file.write_text(
|
|
109
|
+
yaml.safe_dump(data, allow_unicode=True, sort_keys=False),
|
|
110
|
+
encoding="utf-8",
|
|
111
|
+
)
|
|
112
|
+
print("✓ sudo 密码已保存到 configs/secrets.yaml(已 gitignore),后续无需再输")
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def chsrc_set_uv() -> None:
|
|
116
|
+
"""uv 换最优镜像源:chsrc set uv first(自动测速选最快)。
|
|
117
|
+
|
|
118
|
+
- 未安装 chsrc 时自动安装(curl https://chsrc.run/posix | sudo bash):
|
|
119
|
+
sudo 密码优先取 configs/secrets.yaml;没有则提示输入一次并自动保存,
|
|
120
|
+
之后所有 sudo 环节免交互;非交互终端会提示先去补 secrets.yaml
|
|
121
|
+
- chsrc 写用户级 uv 配置(~/.config/uv/uv.toml),对本机所有项目生效
|
|
122
|
+
- 失败只告警,不阻塞构建(沿用当前源)
|
|
123
|
+
"""
|
|
124
|
+
chsrc = "chsrc.exe" if sys.platform == "win32" else "chsrc"
|
|
125
|
+
if not shutil.which(chsrc):
|
|
126
|
+
if sys.platform == "win32":
|
|
127
|
+
print("⚠️ 未检测到 chsrc(https://chsrc.run),跳过 uv 换源")
|
|
128
|
+
return
|
|
129
|
+
print("→ 未检测到 chsrc,自动安装(curl https://chsrc.run/posix | sudo bash)...")
|
|
130
|
+
try:
|
|
131
|
+
password = _sudo_password()
|
|
132
|
+
interactive = sys.stdin is not None and sys.stdin.isatty()
|
|
133
|
+
if not password and interactive:
|
|
134
|
+
# 提示补上:输入一次自动保存进 secrets.yaml,后续 sudo 环节全部免交互
|
|
135
|
+
from getpass import getpass
|
|
136
|
+
|
|
137
|
+
password = getpass(
|
|
138
|
+
"secrets.yaml 未配置 sudo_password,请输入本机 sudo 密码(输入后自动保存): "
|
|
139
|
+
).strip()
|
|
140
|
+
if password:
|
|
141
|
+
_save_sudo_password(password)
|
|
142
|
+
if password:
|
|
143
|
+
subprocess.run(
|
|
144
|
+
["sudo", "-S", "-p", "", "-v"],
|
|
145
|
+
input=password + "\n",
|
|
146
|
+
text=True,
|
|
147
|
+
check=True,
|
|
148
|
+
timeout=30,
|
|
149
|
+
)
|
|
150
|
+
elif interactive:
|
|
151
|
+
pass # 用户未保存:交给 sudo 在终端交互询问(仅本次有效)
|
|
152
|
+
else:
|
|
153
|
+
print("⚠️ 无法安装 chsrc:secrets.yaml 未配置 sudo_password,请补上后重试")
|
|
154
|
+
return
|
|
155
|
+
subprocess.run(
|
|
156
|
+
["bash", "-c", "curl https://chsrc.run/posix | sudo bash"],
|
|
157
|
+
check=True,
|
|
158
|
+
timeout=180,
|
|
159
|
+
)
|
|
160
|
+
except Exception as e:
|
|
161
|
+
print(f"⚠️ chsrc 安装失败,跳过 uv 换源(检查 secrets.yaml 的 sudo_password): {e}")
|
|
162
|
+
return
|
|
163
|
+
try:
|
|
164
|
+
print("→ 正在切换 uv 最优镜像源 (chsrc set uv first)...")
|
|
165
|
+
result = subprocess.run(
|
|
166
|
+
[chsrc, "set", "uv", "first"], capture_output=True, text=True, timeout=120
|
|
167
|
+
)
|
|
168
|
+
output = ((result.stdout or "") + (result.stderr or "")).strip()
|
|
169
|
+
if output:
|
|
170
|
+
print(output)
|
|
171
|
+
except Exception as e:
|
|
172
|
+
print(f"⚠️ chsrc 设置 uv 源失败,沿用当前源: {e}")
|
|
173
|
+
|
|
174
|
+
|
|
71
175
|
def nrm_speedtest() -> None:
|
|
72
176
|
"""用 nrm 一键测速所有内置 npm 源并自动切换到最快的源。
|
|
73
177
|
|
|
@@ -404,6 +508,7 @@ if "-f" in TARGETS or "-a" in TARGETS:
|
|
|
404
508
|
if "-b" in TARGETS or "-a" in TARGETS:
|
|
405
509
|
# 后端:使用当前平台虚拟环境调用 PyInstaller。
|
|
406
510
|
clean(ROOT / "dist")
|
|
511
|
+
chsrc_set_uv()
|
|
407
512
|
run(["uv", "sync", "--extra", "dev"])
|
|
408
513
|
run([str(PYTHON), "backend/backend_build.py"])
|
|
409
514
|
require(ROOT / "dist" / ("server.exe" if sys.platform == "win32" else "server"), "后端")
|
|
@@ -22,6 +22,110 @@ for _stream in (sys.stdout, sys.stderr):
|
|
|
22
22
|
pass
|
|
23
23
|
|
|
24
24
|
|
|
25
|
+
def _sudo_password() -> str:
|
|
26
|
+
"""从 configs/secrets.yaml 读 sudo 密码;支持 obf1: 混淆形态(与后端同算法)。"""
|
|
27
|
+
import base64
|
|
28
|
+
|
|
29
|
+
import yaml
|
|
30
|
+
|
|
31
|
+
secrets_file = ROOT / "configs" / "secrets.yaml"
|
|
32
|
+
if not secrets_file.exists():
|
|
33
|
+
return ""
|
|
34
|
+
try:
|
|
35
|
+
data = yaml.safe_load(secrets_file.read_text(encoding="utf-8")) or {}
|
|
36
|
+
value = str(data.get("sudo_password") or "")
|
|
37
|
+
except Exception:
|
|
38
|
+
return ""
|
|
39
|
+
if value.startswith("obf1:"):
|
|
40
|
+
key = b"[[ package_name ]]$SecretObfuscation#2026"
|
|
41
|
+
try:
|
|
42
|
+
raw = base64.urlsafe_b64decode(value[len("obf1:"):].encode("ascii"))
|
|
43
|
+
return bytes(b ^ key[i % len(key)] for i, b in enumerate(raw)).decode("utf-8")
|
|
44
|
+
except Exception:
|
|
45
|
+
return ""
|
|
46
|
+
return value
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _save_sudo_password(password: str) -> None:
|
|
50
|
+
"""把 sudo 密码合并写进 configs/secrets.yaml(保留其他键;已 gitignore)。"""
|
|
51
|
+
import yaml
|
|
52
|
+
|
|
53
|
+
secrets_file = ROOT / "configs" / "secrets.yaml"
|
|
54
|
+
data = {}
|
|
55
|
+
if secrets_file.exists():
|
|
56
|
+
try:
|
|
57
|
+
data = yaml.safe_load(secrets_file.read_text(encoding="utf-8")) or {}
|
|
58
|
+
except Exception:
|
|
59
|
+
data = {}
|
|
60
|
+
data["sudo_password"] = password
|
|
61
|
+
secrets_file.parent.mkdir(parents=True, exist_ok=True)
|
|
62
|
+
secrets_file.write_text(
|
|
63
|
+
yaml.safe_dump(data, allow_unicode=True, sort_keys=False),
|
|
64
|
+
encoding="utf-8",
|
|
65
|
+
)
|
|
66
|
+
print("✓ sudo 密码已保存到 configs/secrets.yaml(已 gitignore),后续无需再输")
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def chsrc_set_uv() -> None:
|
|
70
|
+
"""uv 换最优镜像源:chsrc set uv first(自动测速选最快)。
|
|
71
|
+
|
|
72
|
+
- 未安装 chsrc 时自动安装(curl https://chsrc.run/posix | sudo bash):
|
|
73
|
+
sudo 密码优先取 configs/secrets.yaml;没有则提示输入一次并自动保存,
|
|
74
|
+
之后所有 sudo 环节免交互;非交互终端会提示先去补 secrets.yaml
|
|
75
|
+
- chsrc 写用户级 uv 配置(~/.config/uv/uv.toml),对本机所有项目生效
|
|
76
|
+
- 失败只告警,不阻塞启动(沿用当前源)
|
|
77
|
+
"""
|
|
78
|
+
chsrc = "chsrc.exe" if sys.platform == "win32" else "chsrc"
|
|
79
|
+
if not shutil.which(chsrc):
|
|
80
|
+
if sys.platform == "win32":
|
|
81
|
+
print("⚠️ 未检测到 chsrc(https://chsrc.run),跳过 uv 换源")
|
|
82
|
+
return
|
|
83
|
+
print("→ 未检测到 chsrc,自动安装(curl https://chsrc.run/posix | sudo bash)...")
|
|
84
|
+
try:
|
|
85
|
+
password = _sudo_password()
|
|
86
|
+
interactive = sys.stdin is not None and sys.stdin.isatty()
|
|
87
|
+
if not password and interactive:
|
|
88
|
+
# 提示补上:输入一次自动保存进 secrets.yaml,后续 sudo 环节全部免交互
|
|
89
|
+
from getpass import getpass
|
|
90
|
+
|
|
91
|
+
password = getpass(
|
|
92
|
+
"secrets.yaml 未配置 sudo_password,请输入本机 sudo 密码(输入后自动保存): "
|
|
93
|
+
).strip()
|
|
94
|
+
if password:
|
|
95
|
+
_save_sudo_password(password)
|
|
96
|
+
if password:
|
|
97
|
+
subprocess.run(
|
|
98
|
+
["sudo", "-S", "-p", "", "-v"],
|
|
99
|
+
input=password + "\n",
|
|
100
|
+
text=True,
|
|
101
|
+
check=True,
|
|
102
|
+
timeout=30,
|
|
103
|
+
)
|
|
104
|
+
elif interactive:
|
|
105
|
+
pass # 用户未保存:交给 sudo 在终端交互询问(仅本次有效)
|
|
106
|
+
else:
|
|
107
|
+
print("⚠️ 无法安装 chsrc:secrets.yaml 未配置 sudo_password,请补上后重试")
|
|
108
|
+
return
|
|
109
|
+
subprocess.run(
|
|
110
|
+
["bash", "-c", "curl https://chsrc.run/posix | sudo bash"],
|
|
111
|
+
check=True,
|
|
112
|
+
timeout=180,
|
|
113
|
+
)
|
|
114
|
+
except Exception as e:
|
|
115
|
+
print(f"⚠️ chsrc 安装失败,跳过 uv 换源(检查 secrets.yaml 的 sudo_password): {e}")
|
|
116
|
+
return
|
|
117
|
+
try:
|
|
118
|
+
print("→ 正在切换 uv 最优镜像源 (chsrc set uv first)...")
|
|
119
|
+
result = subprocess.run(
|
|
120
|
+
[chsrc, "set", "uv", "first"], capture_output=True, text=True, timeout=120
|
|
121
|
+
)
|
|
122
|
+
output = ((result.stdout or "") + (result.stderr or "")).strip()
|
|
123
|
+
if output:
|
|
124
|
+
print(output)
|
|
125
|
+
except Exception as e:
|
|
126
|
+
print(f"⚠️ chsrc 设置 uv 源失败,沿用当前源: {e}")
|
|
127
|
+
|
|
128
|
+
|
|
25
129
|
def stop_service(name: str) -> None:
|
|
26
130
|
"""停止指定服务并删除 PID 文件。Windows 递归结束子进程。"""
|
|
27
131
|
pid_file = PID_DIR / f"{name}.pid"
|
|
@@ -212,6 +316,8 @@ if action in {"start", "restart"}:
|
|
|
212
316
|
print_port_owner(backend_port)
|
|
213
317
|
raise SystemExit(f"后端端口 {backend_port} 已被占用")
|
|
214
318
|
if not python.exists():
|
|
319
|
+
# 首次同步依赖前先切到最快的 uv 镜像源,避免默认源拖慢/拖挂
|
|
320
|
+
chsrc_set_uv()
|
|
215
321
|
print("→ 正在同步 Python 依赖,首次启动可能需要几分钟...")
|
|
216
322
|
try:
|
|
217
323
|
subprocess.run(
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/frontend/src/components/version/UpdatePanel.vue.j2
RENAMED
|
File without changes
|
{xb_init-2.2.2 → xb_init-2.2.3}/xb/templates/frontend/src/composables/useTerminalSessions.js.j2
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|