codebee 0.1.7 → 0.1.9
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.
- package/CHANGELOG.md +20 -0
- package/README.md +236 -252
- package/app/core/catalog.py +24 -5
- package/app/core/errorlog.py +179 -0
- package/app/core/flows.py +6 -2
- package/app/core/gitmod.py +45 -1
- package/app/core/health.py +48 -11
- package/app/core/jobs.py +104 -9
- package/app/core/manager.py +21 -0
- package/app/core/modelhub.py +80 -11
- package/app/core/paths.py +1 -0
- package/app/core/pipeline.py +420 -88
- package/app/core/runner.py +122 -10
- package/app/core/settings.py +9 -2
- package/app/core/step_runner.py +28 -4
- package/app/core/store.py +180 -139
- package/app/core/telemetry.py +291 -0
- package/app/core/token_meter.py +18 -0
- package/app/main.py +162 -16
- package/app/pick_dialog.py +78 -0
- package/app/ui/app.js +1012 -604
- package/app/ui/i18n.js +79 -6
- package/app/ui/index.html +161 -80
- package/app/ui/style.css +838 -67
- package/package.json +1 -1
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""原生「选择文件夹」对话框(main.py 的 /api/pick_folder 用)。
|
|
3
|
+
|
|
4
|
+
Tk 必须活在自家进程的主线程里:HTTP 请求线程里建 root 在 macOS 上会崩,
|
|
5
|
+
Windows 上反复建/销毁也不稳,所以隔离成独立进程。ask_directory() 是父端
|
|
6
|
+
入口,把本文件拉起为子进程,请求参数(JSON:initial 起始目录 / title 标题)
|
|
7
|
+
走 stdin,选中目录以 JSON({"path": ...})走 stdout,用户取消回空串;
|
|
8
|
+
对话框部分是文件尾的 main()。任何一步失败都以非零码退出,父端据此回
|
|
9
|
+
fallback=true 让前端回落网页目录弹框。"""
|
|
10
|
+
import json
|
|
11
|
+
import os
|
|
12
|
+
import subprocess
|
|
13
|
+
import sys
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
|
|
16
|
+
# 非 Windows 置 0:POSIX 的 Popen 对非零 creationflags 抛 ValueError(manager 同款守卫)
|
|
17
|
+
CREATE_NO_WINDOW = 0x08000000 if os.name == "nt" else 0
|
|
18
|
+
_SELF = str(Path(__file__).resolve())
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def ask_directory(initial="", title="选择文件夹"):
|
|
22
|
+
"""父端入口:拉起子进程弹原生对话框,返回 (path, error, fallback)。
|
|
23
|
+
|
|
24
|
+
用户取消时 path 为空串;子进程起不来(机器无 tkinter 等)时 error
|
|
25
|
+
非空且 fallback=True,调用方原样转给前端回落网页目录弹框。"""
|
|
26
|
+
if not Path(__file__).exists():
|
|
27
|
+
return "", "pick_dialog.py 缺失", True
|
|
28
|
+
req = json.dumps({"initial": initial, "title": title}).encode("utf-8")
|
|
29
|
+
env = dict(os.environ, PYTHONIOENCODING="utf-8")
|
|
30
|
+
try:
|
|
31
|
+
if os.name == "nt":
|
|
32
|
+
cp = subprocess.run([sys.executable, _SELF], input=req,
|
|
33
|
+
capture_output=True, timeout=600, env=env,
|
|
34
|
+
creationflags=CREATE_NO_WINDOW)
|
|
35
|
+
else:
|
|
36
|
+
cp = subprocess.run([sys.executable, _SELF], input=req,
|
|
37
|
+
capture_output=True, timeout=600, env=env)
|
|
38
|
+
except Exception as e:
|
|
39
|
+
return "", str(e), True
|
|
40
|
+
if cp.returncode != 0:
|
|
41
|
+
err = (cp.stderr or b"").decode("utf-8", "replace").strip().splitlines()
|
|
42
|
+
return "", (err[-1] if err else "native picker unavailable"), True
|
|
43
|
+
try:
|
|
44
|
+
data = json.loads((cp.stdout or b"").decode("utf-8", "replace") or "{}")
|
|
45
|
+
except Exception:
|
|
46
|
+
return "", "对话框输出无法解析", True
|
|
47
|
+
return str(data.get("path") or ""), "", False
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def main():
|
|
51
|
+
req = {}
|
|
52
|
+
try:
|
|
53
|
+
req = json.loads(sys.stdin.read() or "{}")
|
|
54
|
+
except Exception:
|
|
55
|
+
pass
|
|
56
|
+
import tkinter as tk
|
|
57
|
+
from tkinter import filedialog
|
|
58
|
+
|
|
59
|
+
root = tk.Tk()
|
|
60
|
+
root.withdraw()
|
|
61
|
+
try:
|
|
62
|
+
root.attributes("-topmost", True) # 别被全屏浏览器盖住
|
|
63
|
+
except Exception:
|
|
64
|
+
pass
|
|
65
|
+
kw = {"title": req.get("title") or "选择文件夹"}
|
|
66
|
+
init = req.get("initial") or ""
|
|
67
|
+
if init and os.path.isdir(init):
|
|
68
|
+
kw["initialdir"] = init
|
|
69
|
+
try:
|
|
70
|
+
path = filedialog.askdirectory(**kw) or ""
|
|
71
|
+
except Exception:
|
|
72
|
+
sys.exit(1)
|
|
73
|
+
sys.stdout.write(json.dumps({"path": path}))
|
|
74
|
+
root.destroy()
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
if __name__ == "__main__":
|
|
78
|
+
main()
|