codebee 0.1.0 → 0.1.2
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/README.md +25 -4
- package/app/core/catalog.py +32 -11
- package/app/core/flows.py +1 -1
- package/app/core/gitmod.py +16 -12
- package/app/core/manager.py +1511 -1415
- package/app/core/modelhub.py +10 -4
- package/app/core/paths.py +12 -6
- package/app/core/selfupdate.py +170 -170
- package/app/ui/app.js +8045 -8021
- package/app/ui/i18n.js +11 -7
- package/app/ui/index.html +1 -0
- package/app/ui/style.css +2736 -2733
- package/bin/tutti.js +147 -121
- package/package.json +39 -39
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
- **跨厂商对抗式评审**:评审者强制来自与作者不同的模型族——同族自评有同款盲区,
|
|
14
14
|
换一双"眼睛"才挑得出陈词滥调(无跨厂商可用时如实备注,绝不伪装)。
|
|
15
|
-
- **产物隔离在任务分支**:指定代码版本的任务,产物提交在 `
|
|
15
|
+
- **产物隔离在任务分支**:指定代码版本的任务,产物提交在 `codebee/<task-id>` 分支上,
|
|
16
16
|
你的工作区始终干净;UI 或 `tools/bee.py` 里过目变更,一键「合并回原分支」或「丢弃」。
|
|
17
17
|
- **多任务并发互不打扰**(1-6 可配)、**六种内置任务类型 + 自定义流程**;
|
|
18
18
|
「编排设置」可指定任意厂商的 API 模型作为**编排者**;CLI 可绑定**跨厂商模型链**。
|
|
@@ -34,13 +34,34 @@ python toolsee.py discard <task> :: 否决——删除任务分支(需输
|
|
|
34
34
|
|
|
35
35
|
## 快速开始
|
|
36
36
|
|
|
37
|
+
**方式一:npm 安装(推荐,普通用户)**
|
|
38
|
+
|
|
39
|
+
需要本机装有 [Node.js](https://nodejs.org) 与 [Python 3.8+](https://www.python.org/downloads/windows/)
|
|
40
|
+
(Windows 装 Python 时勾选 “Add python.exe to PATH”)。然后:
|
|
41
|
+
|
|
42
|
+
```bat
|
|
43
|
+
npm install -g codebee
|
|
44
|
+
codebee
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
`codebee` 命令会启动服务并自动打开浏览器(默认 `http://127.0.0.1:8765`)。
|
|
48
|
+
**启动后那个命令行窗口就是服务本身**——保持开着别关,Ctrl+C 即退出。
|
|
49
|
+
升级:`npm update -g codebee`,或在界面「设置 → 关于与更新」里一键升级。
|
|
50
|
+
|
|
51
|
+
数据存放在用户目录(Windows `%APPDATA%\CodeBee`,macOS/Linux `~/.codebee`),
|
|
52
|
+
升级/重装不影响;老版本 Tutti 目录(`%APPDATA%\Tutti`)会被自动沿用,无需迁移。
|
|
53
|
+
|
|
54
|
+
**方式二:源码运行(开发者)**
|
|
55
|
+
|
|
37
56
|
```bat
|
|
57
|
+
git clone https://github.com/Vercel-By-WXP/CodeBee.git
|
|
58
|
+
cd CodeBee
|
|
38
59
|
start.bat
|
|
39
60
|
:: 或
|
|
40
61
|
python app\main.py --port 8765
|
|
41
62
|
```
|
|
42
63
|
|
|
43
|
-
自动打开 `http://127.0.0.1:8765
|
|
64
|
+
自动打开 `http://127.0.0.1:8765`。源码模式数据落仓库 `data/` 目录。
|
|
44
65
|
|
|
45
66
|
## 手机 / 远程访问
|
|
46
67
|
|
|
@@ -68,8 +89,8 @@ python app\main.py --port 8765
|
|
|
68
89
|
```bat
|
|
69
90
|
:: 一次性配置:cloudflared 登录后创建隧道并绑定子域名
|
|
70
91
|
cloudflared tunnel login
|
|
71
|
-
cloudflared tunnel create
|
|
72
|
-
cloudflared tunnel route dns --overwrite-dns <隧道UUID>
|
|
92
|
+
cloudflared tunnel create codebee
|
|
93
|
+
cloudflared tunnel route dns --overwrite-dns <隧道UUID> codebee.你的域名.com
|
|
73
94
|
|
|
74
95
|
:: 之后日常启动(服务 + 隧道一键起):
|
|
75
96
|
start-public.bat
|
package/app/core/catalog.py
CHANGED
|
@@ -84,31 +84,40 @@ DEFAULT_CATALOG = [
|
|
|
84
84
|
},
|
|
85
85
|
{
|
|
86
86
|
"id": "openclaw", "name": "OpenClaw", "cli_group": "installable",
|
|
87
|
-
"note": "网关型个人 AI 智能体(原 Clawdbot
|
|
87
|
+
"note": "网关型个人 AI 智能体(原 Clawdbot);编排模板装好后需验证;"
|
|
88
|
+
"默认模型在 openclaw.json 的 agents.defaults.model.primary"
|
|
89
|
+
"(顶层 model 键会被 schema 校验拒绝启动,绝不写顶层)",
|
|
88
90
|
"detect": {"cli": "openclaw"},
|
|
89
91
|
"orch": {"kind": "generic", "command": "openclaw", "argv_template": ["{prompt}"]},
|
|
90
|
-
"config": {"path": "~/.openclaw/openclaw.json", "format": "json",
|
|
92
|
+
"config": {"path": "~/.openclaw/openclaw.json", "format": "json-path",
|
|
93
|
+
"model_key": "agents.defaults.model.primary"},
|
|
91
94
|
"install": "npm install -g openclaw",
|
|
92
95
|
"upgrade": "npm install -g openclaw@latest",
|
|
93
96
|
"default_enabled": False,
|
|
94
97
|
},
|
|
95
98
|
{
|
|
96
99
|
"id": "kimi-code", "name": "Kimi Code", "cli_group": "installable",
|
|
97
|
-
"note": "月之暗面 Kimi 编码 CLI(TypeScript 版,需 Node ≥22.19);旧 Python 版
|
|
100
|
+
"note": "月之暗面 Kimi 编码 CLI(TypeScript 版,需 Node ≥22.19);旧 Python 版 "
|
|
101
|
+
"kimi-cli 正在下线;默认模型在 ~/.kimi-code/config.toml 的顶层 "
|
|
102
|
+
"default_model(值须是 [models] 表里定义的别名),首启自动建文件",
|
|
98
103
|
"detect": {"cli": "kimi"},
|
|
99
104
|
"orch": {"kind": "generic", "command": "kimi", "argv_template": ["-p", "{prompt}"]},
|
|
100
|
-
"config": {"path": "~/.kimi/config.
|
|
105
|
+
"config": {"path": "~/.kimi-code/config.toml", "format": "toml-section",
|
|
106
|
+
"model_key": "default_model"},
|
|
101
107
|
"install": "npm install -g @moonshot-ai/kimi-code",
|
|
102
108
|
"upgrade": "npm install -g @moonshot-ai/kimi-code@latest",
|
|
103
109
|
"default_enabled": False,
|
|
104
110
|
},
|
|
105
111
|
{
|
|
106
112
|
"id": "mimo-code", "name": "MiMo Code", "cli_group": "installable",
|
|
107
|
-
"note": "小米 MiMo Code(opencode 衍生);无头调用是子命令 mimo run \"提示词\"
|
|
113
|
+
"note": "小米 MiMo Code(opencode 衍生);无头调用是子命令 mimo run \"提示词\","
|
|
114
|
+
"-p 在该 CLI 是 --password;默认模型在 ~/.config/mimocode/mimocode.jsonc "
|
|
115
|
+
"顶层 model(provider/model 格式),onboarding 自动建文件",
|
|
108
116
|
"detect": {"cli": "mimo"},
|
|
109
117
|
"orch": {"kind": "generic", "command": "mimo", "argv_template": ["run", "{prompt}"],
|
|
110
118
|
"resume_argv_template": ["run", "-s", "{session}"]},
|
|
111
|
-
"config": {"path": "~/.
|
|
119
|
+
"config": {"path": "~/.config/mimocode/mimocode.jsonc", "format": "jsonc",
|
|
120
|
+
"model_key": "model"},
|
|
112
121
|
"install": "npm install -g @mimo-ai/cli",
|
|
113
122
|
"upgrade": "npm install -g @mimo-ai/cli@latest",
|
|
114
123
|
"default_enabled": False,
|
|
@@ -127,10 +136,13 @@ DEFAULT_CATALOG = [
|
|
|
127
136
|
},
|
|
128
137
|
{
|
|
129
138
|
"id": "pi", "name": "Pi", "cli_group": "installable",
|
|
130
|
-
"note": "Earendil Works 的 Pi 编码 CLI(需 Node ≥22.19);包名必须带 @earendil-works/
|
|
139
|
+
"note": "Earendil Works 的 Pi 编码 CLI(需 Node ≥22.19);包名必须带 @earendil-works/ 前缀;"
|
|
140
|
+
"默认模型在 ~/.pi/agent/settings.json 的 defaultModel(须配 defaultProvider 才能解析)",
|
|
131
141
|
"detect": {"cli": "pi"},
|
|
132
142
|
"orch": {"kind": "generic", "command": "pi", "argv_template": ["-p", "{prompt}"]},
|
|
133
|
-
"config": {"path": "~/.pi/
|
|
143
|
+
"config": {"path": "~/.pi/agent/settings.json", "format": "json-path",
|
|
144
|
+
"model_key": "defaultModel",
|
|
145
|
+
"model_extra_keys": {"defaultProvider": ""}},
|
|
134
146
|
"install": "npm install -g --ignore-scripts @earendil-works/pi-coding-agent",
|
|
135
147
|
"upgrade": "npm install -g --ignore-scripts @earendil-works/pi-coding-agent@latest",
|
|
136
148
|
"default_enabled": False,
|
|
@@ -185,13 +197,22 @@ LAUNCH_PATCH = { "codex-cli": {"kind": "console", "command": "codex"},
|
|
|
185
197
|
# config.format 修正({id: config 字段}):load() 幂等覆盖。qwen 的 settings.json
|
|
186
198
|
# 顶层 "model" 是 legacy(被忽略并告警)——老用户的 catalog.json 里 qwencode 还是
|
|
187
199
|
# format=json,不修正的话每次打开都会写无效字段;覆盖无风险(写了也不生效)。
|
|
200
|
+
# grok/kimi/mimo/pi/openclaw 同理:真实落点均经官方文档/源码查证(详见各条目 note
|
|
201
|
+
# 与 tests/test_grok_build.py),早期错标(不存在的文件/错误键名)导致保存默认模型
|
|
202
|
+
# 必然失败或写进无效键,覆盖无风险。
|
|
188
203
|
CONFIG_PATCH = {
|
|
189
204
|
"qwencode": {"path": "~/.qwen/settings.json", "format": None, "model_key": None},
|
|
190
|
-
# grok 实测配置是 TOML(config.toml 的 [models] default);早期版本错标成
|
|
191
|
-
# config.json + format=json,文件永远不存在导致「保存默认模型」必然失败——
|
|
192
|
-
# 必须覆盖修正(写 config.json 无任何效果,覆盖无风险)。
|
|
193
205
|
"grok-build": {"path": "~/.grok/config.toml", "format": "toml-section",
|
|
194
206
|
"model_key": "models.default"},
|
|
207
|
+
"kimi-code": {"path": "~/.kimi-code/config.toml", "format": "toml-section",
|
|
208
|
+
"model_key": "default_model"},
|
|
209
|
+
"mimo-code": {"path": "~/.config/mimocode/mimocode.jsonc", "format": "jsonc",
|
|
210
|
+
"model_key": "model"},
|
|
211
|
+
"pi": {"path": "~/.pi/agent/settings.json", "format": "json-path",
|
|
212
|
+
"model_key": "defaultModel",
|
|
213
|
+
"model_extra_keys": {"defaultProvider": ""}},
|
|
214
|
+
"openclaw": {"path": "~/.openclaw/openclaw.json", "format": "json-path",
|
|
215
|
+
"model_key": "agents.defaults.model.primary"},
|
|
195
216
|
}
|
|
196
217
|
|
|
197
218
|
|
package/app/core/flows.py
CHANGED
|
@@ -31,7 +31,7 @@ ENGINE_DEFAULTS = {
|
|
|
31
31
|
# icon 约定:"i-*" = 前端精灵表单色线性图标(随日/夜主题黑白);其他值(emoji)原样显示,
|
|
32
32
|
# 供自定义流程兜底。预置图标不进 overrides(见 _EDITABLE),保证升级后老数据也拿到新图标。
|
|
33
33
|
BUILTIN_FLOWS = [
|
|
34
|
-
{"id": "direct", "name": "直接执行", "icon": "i-
|
|
34
|
+
{"id": "direct", "name": "直接执行", "icon": "i-chat", "engine": "direct", "builtin": True,
|
|
35
35
|
"goal_hint": "让 AI 直接做什么(一句话,可带附件)",
|
|
36
36
|
"note": "单智能体直达:目标+附件交给一个 CLI 跑完即止,无拆解/评审(快)"},
|
|
37
37
|
{"id": "code", "name": "代码", "icon": "i-code", "engine": "code", "builtin": True,
|
package/app/core/gitmod.py
CHANGED
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
设计约束(对齐质量闸门原则:显式意图不容静默降级):
|
|
5
5
|
- 探测只读:/api/git/info 只跑 rev-parse / status / log,不改仓库任何东西。
|
|
6
6
|
- 检出不破坏用户现场:不直接在所选版本上 detached checkout,而是从它创建
|
|
7
|
-
任务分支
|
|
7
|
+
任务分支 codebee/<task-id> 再检出(老 tutti/<id> 分支仍可合并/丢弃)——原分支指针不动,任务产物落在任务分支上。
|
|
8
8
|
- 工作区不必干净也能检出:未提交改动先 git stash 原样收起(_attachments/
|
|
9
9
|
的附件除外,那是同一任务刚上传的素材),收尾切回后 apply 还原——开发仓库
|
|
10
|
-
永远有并行改动,硬拒绝等于代码版本隔离不可用。stash 条目按
|
|
10
|
+
永远有并行改动,硬拒绝等于代码版本隔离不可用。stash 条目按 codebee-stash-*
|
|
11
11
|
标记,还原失败时保留在 stash 列表里可手工找回,绝不静默丢弃。
|
|
12
12
|
"""
|
|
13
13
|
from __future__ import annotations
|
|
@@ -78,8 +78,12 @@ def repo_info(workdir):
|
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
|
|
81
|
+
BRANCH_PREFIX = "codebee/" # 任务分支前缀;老分支 tutti/<id> 在列表里仍被识别(下方 _TASK_BRANCH_RE)
|
|
82
|
+
_TASK_BRANCH_RES = ("codebee/", "tutti/") # 老版本发布的任务分支前缀,只读兼容
|
|
83
|
+
|
|
84
|
+
|
|
81
85
|
def branch_name(task_id):
|
|
82
|
-
return
|
|
86
|
+
return BRANCH_PREFIX + str(task_id)
|
|
83
87
|
|
|
84
88
|
|
|
85
89
|
def _stash_dirty(workdir, label):
|
|
@@ -88,7 +92,7 @@ def _stash_dirty(workdir, label):
|
|
|
88
92
|
_attachments/ 除外:那是本任务刚上传的附件,必须留在工作目录供注入。
|
|
89
93
|
pathspec 排除走 argv,不经过 shell。失败返回错误——绝不静默带着脏改动切分支。
|
|
90
94
|
"""
|
|
91
|
-
m = "
|
|
95
|
+
m = "codebee-stash-%s" % label
|
|
92
96
|
r = _git(workdir, "stash", "push", "-u", "-m", m,
|
|
93
97
|
"--", ".", ":(exclude)_attachments", timeout=60)
|
|
94
98
|
if not r["ok"]:
|
|
@@ -359,7 +363,7 @@ def finalize_run(workdir, gitinfo, message):
|
|
|
359
363
|
语义(对齐 Baton/Codeband 的隔离模型;本轮只做「保存现场」,任务分支
|
|
360
364
|
的合并/丢弃留给后续的人工裁决):
|
|
361
365
|
- 产物必须可找回:哪怕 run 失败/取消,已写盘的半成品也提交到
|
|
362
|
-
|
|
366
|
+
codebee/<task-id>(WIP 语义),绝不留在用户工作区里污染原分支;
|
|
363
367
|
- _attachments/ 不提交也不丢:用户上传的共享附件保持未跟踪,
|
|
364
368
|
切分支后仍留在工作目录(未跟踪文件随分支切换保留);
|
|
365
369
|
- 任何收尾失败都不抛出:run 终态已定,问题记入 restore_error
|
|
@@ -394,7 +398,7 @@ def finalize_run(workdir, gitinfo, message):
|
|
|
394
398
|
staged = _git(workdir, "diff", "--cached", "--name-only")
|
|
395
399
|
if staged["ok"] and (staged["stdout"] or "").strip():
|
|
396
400
|
# 一次性身份配置:用户仓库可能没配 user.name/email,缺身份不应让提交失败
|
|
397
|
-
c = _git(workdir, "-c", "user.name=
|
|
401
|
+
c = _git(workdir, "-c", "user.name=CodeBee", "-c", "user.email=codebee@orchestra.local",
|
|
398
402
|
"commit", "-m", str(message)[:200], "--quiet")
|
|
399
403
|
if not c["ok"]:
|
|
400
404
|
out["restore_error"] = "提交任务分支失败:%s" % (c["stderr"] or "")[-160:]
|
|
@@ -481,9 +485,9 @@ def merge_task_branch(workdir, task):
|
|
|
481
485
|
out = {"restore_error": ""}
|
|
482
486
|
_restore_stash(wd, stash_sha, out)
|
|
483
487
|
return refuse("任务分支没有领先基线的提交(产物为空),无需合并;可直接丢弃")
|
|
484
|
-
m = _git(wd, "-c", "user.name=
|
|
488
|
+
m = _git(wd, "-c", "user.name=CodeBee", "-c", "user.email=codebee@orchestra.local",
|
|
485
489
|
"merge", "--no-ff", br, "-m",
|
|
486
|
-
"
|
|
490
|
+
"codebee: 合并任务分支 %s(%s)" % (tid, (task or {}).get("title") or "")[:200])
|
|
487
491
|
if not m["ok"]:
|
|
488
492
|
ab = _git(wd, "merge", "--abort")
|
|
489
493
|
tail = (m["stderr"] or m["stdout"] or "")[-200:]
|
|
@@ -775,7 +779,7 @@ def workbench_op(workdir, action, params=None):
|
|
|
775
779
|
|
|
776
780
|
守卫:action 白名单;path 走 _safe_relpath;分支/提交信息限长。
|
|
777
781
|
丢弃(discard)与删除未跟踪文件(delete)不可恢复,必须 confirm=true。
|
|
778
|
-
stash 系列只认 tutti-stash-*
|
|
782
|
+
stash 系列只认 codebee-stash-* 标记条目(老 tutti-stash-* 也认)——用户自己的 stash 不在工作台露出,
|
|
779
783
|
避免误 pop 撞掉检出链收起的现场。
|
|
780
784
|
"""
|
|
781
785
|
params = params or {}
|
|
@@ -915,7 +919,7 @@ def workbench_op(workdir, action, params=None):
|
|
|
915
919
|
|
|
916
920
|
if action == "stash_push":
|
|
917
921
|
msg = str(params.get("message") or "").strip()[:120]
|
|
918
|
-
m = "
|
|
922
|
+
m = "codebee-stash-%s" % (msg or "workbench")
|
|
919
923
|
r = _git(wd, "stash", "push", "-u", "-m", m, "--", ".", ":(exclude)_attachments",
|
|
920
924
|
timeout=90)
|
|
921
925
|
ok, err, data = _res(r)
|
|
@@ -938,8 +942,8 @@ def workbench_op(workdir, action, params=None):
|
|
|
938
942
|
if found is None:
|
|
939
943
|
return False, "stash 条目不存在", {}
|
|
940
944
|
# %s 的形态是 "On master: <message>"/"WIP on ...",认标记用包含判断
|
|
941
|
-
if "
|
|
942
|
-
return False, "工作台只处理编排台自己收起的 stash(
|
|
945
|
+
if "codebee-stash-" not in found:
|
|
946
|
+
return False, "工作台只处理编排台自己收起的 stash(codebee-stash-*),你自己的条目请手工处理", {}
|
|
943
947
|
if action == "stash_pop":
|
|
944
948
|
return _res(_git(wd, "stash", "pop", ref, timeout=90))
|
|
945
949
|
if not params.get("confirm"):
|