codebee 0.1.35 → 0.1.36
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 +15 -0
- package/README.md +15 -0
- package/app/core/market.py +7 -2
- package/app/core/zentao.py +32 -7
- package/app/pet.py +46 -8
- package/app/ui/app.js +43 -5
- package/app/ui/i18n.js +12 -0
- package/app/ui/index.html +25 -21
- package/app/ui/style.css +25 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,21 @@ README 元数据带回,供老版本在「发现新版本」时展示新版更
|
|
|
6
6
|
|
|
7
7
|
## 未发布
|
|
8
8
|
|
|
9
|
+
## v0.1.36(2026-09-21)
|
|
10
|
+
|
|
11
|
+
### 🛠 问题修复
|
|
12
|
+
|
|
13
|
+
- 端口占用诊断的「关闭」现在真能关掉:服务类进程对温和关闭信号本就无反应,此前只发信号不看结果——现在温和无效会自动升级强制结束,并以「端口确实释放」为准,不再假报成功。
|
|
14
|
+
- 群摘要:选好 64 位 Python 后直接点「刷新群列表 / 立即扫描」不再误报「请先填路径」(表单会先静默保存);「立即扫描」按钮文字不再重复;新建的群现在也会出现在监听列表(微信本地库还没同步时从最近会话补齐)。
|
|
15
|
+
- 桌面蜜蜂气泡的「点我细看」现在真的能点:点气泡直达群摘要页;网页已打开时也会跳到目标页,而不是只把旧窗口调到前面。
|
|
16
|
+
- 禅道:「测试并保存连接」不再卡住按钮几十秒(产品/账号清单改后台拉取,拉到后下拉自动就位);操作状态面板显示具体操作名(如「拉取禅道产品」);兼容更多老版禅道的模块树与产品清单返回形状,修「模块清单形状不认识」「产品只显示 ID」。
|
|
17
|
+
- 设置页「代码设置」恢复左标签右控件的横排布局(此前被章节评审卡的样式意外覆盖成整列竖排居中)。
|
|
18
|
+
- 修复页面繁忙时「上次使用的任务类型」偶尔没被恢复的时序问题。
|
|
19
|
+
|
|
20
|
+
### ✨ 界面
|
|
21
|
+
|
|
22
|
+
- 编排模式 / 思考程度 / 对话模型从「更多选项」提到输入框正下方,随开随用,不再折叠。
|
|
23
|
+
|
|
9
24
|
## v0.1.35(2026-09-21)
|
|
10
25
|
|
|
11
26
|
### ✨ 新功能
|
package/README.md
CHANGED
|
@@ -23,11 +23,26 @@ Kimi Code、MiMo Code、Grok Build、Pi、DeepSeek Harness……),提供
|
|
|
23
23
|
<!-- relnotes:start -->
|
|
24
24
|
### ✨ 新功能 · New
|
|
25
25
|
|
|
26
|
+
- 编排模式 / 思考程度 / 对话模型从「更多选项」提到输入框正下方,随开随用。
|
|
27
|
+
- Orchestration mode, reasoning level and chat model now sit right under the input box instead of being folded away.
|
|
28
|
+
|
|
26
29
|
- 经验库越用越准:教训按任务结局自动记胜负,真正帮上忙的经验优先注入、帮倒忙的被挤出——随真实运行自我提纯。
|
|
27
30
|
- The lesson library now tracks outcomes: lessons that helped a task pass gain weight, ones that failed to prevent issues fade — it self-refines with every run.
|
|
28
31
|
|
|
29
32
|
### 🛠 问题修复 · Fixes
|
|
30
33
|
|
|
34
|
+
- 端口诊断的「关闭」真能关掉了:温和信号无效自动升级强杀,以「端口确实释放」为准,不再假报成功。
|
|
35
|
+
- Port diagnostics "Close" now really closes: gentle signal escalates to forced kill when ignored, and success is only reported once the port is actually released.
|
|
36
|
+
|
|
37
|
+
- 群摘要:选好 Python 直接刷新不再误报「请先填路径」;新建的群也会出现在监听列表;蜜蜂气泡「点我细看」真能点了。
|
|
38
|
+
- Digests: refreshing right after picking a Python no longer nags "path required"; brand-new groups show up in the picker; the bee bubble "click to read" actually navigates now.
|
|
39
|
+
|
|
40
|
+
- 禅道:「测试并保存连接」不再卡按钮几十秒;兼容更多老版禅道的模块/产品清单形状;操作状态显示具体操作名。
|
|
41
|
+
- ZenTao: "Test & save" no longer holds the button for tens of seconds; more legacy ZenTao module/product list shapes are supported; the operation panel shows concrete action names.
|
|
42
|
+
|
|
43
|
+
- 设置页「代码设置」恢复横排布局(此前被章节评审卡样式意外覆盖)。
|
|
44
|
+
- Settings → Code display restores its row layout after an accidental style override from the chapter-review card.
|
|
45
|
+
|
|
31
46
|
- 手机端操作被「其他设备正在控制」挡住时,弹出「接管并重试」——一键接管并自动重做刚才的操作。
|
|
32
47
|
- When a mobile action is blocked by another device in control, a "Take over & retry" prompt appears — one tap retakes control and redoes the action.
|
|
33
48
|
|
package/app/core/market.py
CHANGED
|
@@ -170,7 +170,8 @@ def installed_ids():
|
|
|
170
170
|
|
|
171
171
|
def view():
|
|
172
172
|
"""市场目录(给 UI/API):{catalog: [...], categories: [...]}。
|
|
173
|
-
每项带 installed: bool
|
|
173
|
+
每项带 installed: bool + enabled: bool(已装包的启停态,卡片开关直接
|
|
174
|
+
切换,不用再去经验库翻——对齐 ZCode 插件管理形态)。"""
|
|
174
175
|
installed = installed_ids()
|
|
175
176
|
items = []
|
|
176
177
|
for p in skills.BUILTIN_PACKS: # 已内置:已存在,不可安装
|
|
@@ -180,13 +181,17 @@ def view():
|
|
|
180
181
|
"category": meta.get("category") or skills.LESSON_UNCATEGORIZED,
|
|
181
182
|
"scopes": list(p.get("scopes") or ["*"]),
|
|
182
183
|
"builtin": True, "installed": True, "installable": False,
|
|
184
|
+
"enabled": skills._pack_enabled(p["id"]),
|
|
183
185
|
"chars": len(skills.pack_text(p))})
|
|
184
186
|
for p in BUILTIN_PACKS: # 可安装市场包
|
|
185
187
|
files = p.get("files") or {}
|
|
186
188
|
items.append({"id": p["id"], "name": p["name"], "desc": p["desc"],
|
|
187
189
|
"category": p["category"], "scopes": list(p["scopes"]),
|
|
188
190
|
"builtin": False, "installed": p["id"] in installed,
|
|
189
|
-
"installable": True,
|
|
191
|
+
"installable": True,
|
|
192
|
+
"enabled": (p["id"] in installed and
|
|
193
|
+
skills._pack_enabled(p["id"])),
|
|
194
|
+
"files": sorted(files),
|
|
190
195
|
"chars": sum(len(v) for v in files.values())})
|
|
191
196
|
cats = list(skills.LESSON_CATEGORIES) # 闭集全枚举先给全(UI 下拉不缺项)
|
|
192
197
|
for it in items:
|
package/app/core/zentao.py
CHANGED
|
@@ -620,6 +620,33 @@ def _pairs_to_list(pairs, id_key, name_key):
|
|
|
620
620
|
return out
|
|
621
621
|
|
|
622
622
|
|
|
623
|
+
def _module_items(d):
|
|
624
|
+
"""老版模块树形状兼容(2026-09-21 真机反馈「响应形状不认识」):
|
|
625
|
+
sons/modules 数组、{id: {name,...}} 字典、children/sons 嵌套树,统一
|
|
626
|
+
递归展开成 [{id,name}] 平铺清单(id=0 是树根容器,跳过)。"""
|
|
627
|
+
out = []
|
|
628
|
+
|
|
629
|
+
def walk(node):
|
|
630
|
+
if isinstance(node, list):
|
|
631
|
+
for x in node:
|
|
632
|
+
walk(x)
|
|
633
|
+
elif isinstance(node, dict):
|
|
634
|
+
if node.get("id") not in (None, "", 0):
|
|
635
|
+
out.append(node)
|
|
636
|
+
for k in ("children", "sons"):
|
|
637
|
+
if isinstance(node.get(k), (list, dict)):
|
|
638
|
+
walk(node[k])
|
|
639
|
+
else:
|
|
640
|
+
for v in node.values():
|
|
641
|
+
walk(v)
|
|
642
|
+
|
|
643
|
+
if isinstance(d, dict):
|
|
644
|
+
walk(d.get("sons") or d.get("modules") or d.get("tree") or d)
|
|
645
|
+
elif isinstance(d, list):
|
|
646
|
+
walk(d)
|
|
647
|
+
return out
|
|
648
|
+
|
|
649
|
+
|
|
623
650
|
def _old_route(api, method, p, q, body):
|
|
624
651
|
"""路径翻译 + 请求 + 归一。会话死抛 _OldSessionDead。"""
|
|
625
652
|
|
|
@@ -698,16 +725,14 @@ def _old_route(api, method, p, q, body):
|
|
|
698
725
|
m = re.match(r"^/products/(\d+)/modules$", p)
|
|
699
726
|
if m and method == "GET":
|
|
700
727
|
d = go(get("/tree-browse-%s-module.json" % m.group(1)), "(拉模块清单)")
|
|
701
|
-
|
|
702
|
-
if isinstance(d, dict):
|
|
703
|
-
items = d.get("sons") or d.get("modules") or []
|
|
704
|
-
elif isinstance(d, list):
|
|
705
|
-
items = d
|
|
706
|
-
return {"_list": [x for x in items if isinstance(x, dict) and x.get("id")]}
|
|
728
|
+
return {"_list": [x for x in _module_items(d) if isinstance(x, dict) and x.get("id")]}
|
|
707
729
|
|
|
708
730
|
if p == "/products" and method == "GET":
|
|
709
731
|
d = go(get("/api-getmodel-product-getpairs.json"), "(拉产品清单)")
|
|
710
|
-
|
|
732
|
+
prods = d.get("products") if isinstance(d, dict) else None
|
|
733
|
+
if isinstance(prods, list): # 部分老版回数组形状 [{id,name,...}]
|
|
734
|
+
return {"_list": [x for x in prods if isinstance(x, dict) and x.get("id")]}
|
|
735
|
+
pairs = prods if isinstance(prods, dict) else d
|
|
711
736
|
return {"_list": _pairs_to_list(pairs, "id", "name")}
|
|
712
737
|
|
|
713
738
|
if p == "/users" and method == "GET":
|
package/app/pet.py
CHANGED
|
@@ -1090,7 +1090,8 @@ class PetApp:
|
|
|
1090
1090
|
dg = snap.get("digest") or {}
|
|
1091
1091
|
self.seen_digests, notify = digest_alert(self.seen_digests, dg)
|
|
1092
1092
|
if notify:
|
|
1093
|
-
self._show_bubble(digest_bubble_text(dg, self.lang), secs=9.0
|
|
1093
|
+
self._show_bubble(digest_bubble_text(dg, self.lang), secs=9.0,
|
|
1094
|
+
action="digest")
|
|
1094
1095
|
self.last_busy = now
|
|
1095
1096
|
if st == "sleep":
|
|
1096
1097
|
self.mood_kind, self.mood_until = "cheer", now + MOOD_HOLD_S
|
|
@@ -1257,8 +1258,14 @@ class PetApp:
|
|
|
1257
1258
|
self._tip_body = tk.Label(tip, text="", bg="#1B2430",
|
|
1258
1259
|
fg="#ECF2F8",
|
|
1259
1260
|
font=("Microsoft YaHei UI", 9),
|
|
1260
|
-
justify="left", wraplength=280
|
|
1261
|
+
justify="left", wraplength=280,
|
|
1262
|
+
cursor="hand2")
|
|
1261
1263
|
self._tip_body.pack(anchor="w", padx=10, pady=(2, 8))
|
|
1264
|
+
# 点清单即打开网页(含群摘要「点我细看」行——此前清单窗没有任何
|
|
1265
|
+
# 点击绑定,文案写着「点我细看」点了却没反应,用户实测反馈)
|
|
1266
|
+
for w in (self._tip_head, self._tip_body):
|
|
1267
|
+
w.bind("<ButtonPress-1>",
|
|
1268
|
+
lambda e: self._open_ui("#goto=__wxdigest"))
|
|
1262
1269
|
self._tip = tip
|
|
1263
1270
|
self._tip_update()
|
|
1264
1271
|
try:
|
|
@@ -1312,11 +1319,14 @@ class PetApp:
|
|
|
1312
1319
|
text = self._L("alert") % bad.get("title", "?")
|
|
1313
1320
|
self._show_bubble(text)
|
|
1314
1321
|
|
|
1315
|
-
def _show_bubble(self, text, secs=5.0, force=False):
|
|
1322
|
+
def _show_bubble(self, text, secs=5.0, force=False, action=""):
|
|
1323
|
+
"""action:气泡承诺的「点我细看」要兑现(2026-09-21 用户实测点不动——
|
|
1324
|
+
气泡窗口没绑点击,蜜蜂左键也只开首页)。digest=直达群摘要页。"""
|
|
1316
1325
|
if not force and time.time() < self.quiet_until:
|
|
1317
1326
|
return # 「安静一会」期间不碎碎念(系统确认语用 force 放行)
|
|
1318
1327
|
self._destroy_win("_bubble")
|
|
1319
1328
|
self.hop_until = time.time() + 0.7 # 冒泡蹦一下,像在说话
|
|
1329
|
+
self._bubble_action = action
|
|
1320
1330
|
tk = self.tk
|
|
1321
1331
|
bub = tk.Toplevel(self.root)
|
|
1322
1332
|
bub.overrideredirect(True)
|
|
@@ -1324,10 +1334,14 @@ class PetApp:
|
|
|
1324
1334
|
bub.attributes("-topmost", True)
|
|
1325
1335
|
except Exception:
|
|
1326
1336
|
pass
|
|
1327
|
-
tk.Label(bub, text=text, bg="#FFF8E1", fg="#4A3200",
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1337
|
+
lab = tk.Label(bub, text=text, bg="#FFF8E1", fg="#4A3200",
|
|
1338
|
+
bd=1, relief="solid",
|
|
1339
|
+
font=("Microsoft YaHei UI", 9), justify="left",
|
|
1340
|
+
wraplength=230, padx=8, pady=5, cursor="hand2")
|
|
1341
|
+
lab.pack()
|
|
1342
|
+
# 气泡本体可点:点了按承诺跳转(点蜜蜂也走同一逻辑,见 _on_release)
|
|
1343
|
+
for w in (bub, lab):
|
|
1344
|
+
w.bind("<Button-1>", lambda e: self._bubble_click())
|
|
1331
1345
|
x = self.root.winfo_x() + self.win_w - 40
|
|
1332
1346
|
y = max(0, self.root.winfo_y() - 8)
|
|
1333
1347
|
bub.update_idletasks()
|
|
@@ -1338,6 +1352,29 @@ class PetApp:
|
|
|
1338
1352
|
self._bubble_until = time.time() + secs
|
|
1339
1353
|
self.root.after(int(secs * 1000), self._hide_bubble)
|
|
1340
1354
|
|
|
1355
|
+
def _bubble_action_live(self):
|
|
1356
|
+
"""最近一条气泡是否还在展示期且带跳转承诺。"""
|
|
1357
|
+
if time.time() > getattr(self, "_bubble_until", 0):
|
|
1358
|
+
return ""
|
|
1359
|
+
return getattr(self, "_bubble_action", "") or ""
|
|
1360
|
+
|
|
1361
|
+
def _bubble_click(self):
|
|
1362
|
+
# 点了立刻消失并清展示期(_hide_bubble 是到点才收的延迟逻辑,别用);
|
|
1363
|
+
# 先记 action 再清——_open_by_bubble_action 读的就是这个展示期
|
|
1364
|
+
action = self._bubble_action_live()
|
|
1365
|
+
self._destroy_win("_bubble")
|
|
1366
|
+
self._bubble_until = 0
|
|
1367
|
+
if action == "digest":
|
|
1368
|
+
self._open_digest()
|
|
1369
|
+
else:
|
|
1370
|
+
self._open_ui()
|
|
1371
|
+
|
|
1372
|
+
def _open_by_bubble_action(self):
|
|
1373
|
+
if self._bubble_action_live() == "digest":
|
|
1374
|
+
self._open_digest()
|
|
1375
|
+
else:
|
|
1376
|
+
self._open_ui()
|
|
1377
|
+
|
|
1341
1378
|
def _hide_bubble(self):
|
|
1342
1379
|
if time.time() < self._bubble_until:
|
|
1343
1380
|
self.root.after(500, self._hide_bubble)
|
|
@@ -1476,7 +1513,8 @@ class PetApp:
|
|
|
1476
1513
|
self._clamp_pos()
|
|
1477
1514
|
self._save_cfg(x=self.root.winfo_x(), y=self.root.winfo_y())
|
|
1478
1515
|
else:
|
|
1479
|
-
|
|
1516
|
+
# 展示期内气泡承诺过「点我细看」就兑现(digest 直达),否则开首页
|
|
1517
|
+
self._open_by_bubble_action()
|
|
1480
1518
|
|
|
1481
1519
|
def _bye(self, write_setting=False):
|
|
1482
1520
|
"""退出。write_setting=True(右键菜单「关闭桌宠」)先把 pet_enabled=False
|
package/app/ui/app.js
CHANGED
|
@@ -59,7 +59,9 @@ function renderTypeOptions() {
|
|
|
59
59
|
const prev = sel.value; sel.innerHTML = (S.flows || []).map((f) => {
|
|
60
60
|
return '<option value="' + esc(f.id) + '">' + esc(t(f.name)) + t("(") + flowDesc(f) + (f.builtin ? "" : t(" · 自定义")) + t(")") + "</option>";
|
|
61
61
|
}).join("");
|
|
62
|
-
|
|
62
|
+
// 保住用户手动选择(typeTouched);出厂默认 direct 不算选择——prefs 迟到
|
|
63
|
+
// 竞态下要让位给偏好记忆,否则「上次类型」永远恢复不了(高负载下实测)
|
|
64
|
+
if (prev && flowById(prev) && (S.typeTouched || prev !== "direct")) sel.value = prev;
|
|
63
65
|
// 偏好记忆:上次创建用的类型优先于出厂默认「直接执行」(老数据/已删流程回落)
|
|
64
66
|
else if (S.lastPrefs && S.lastPrefs.type && flowById(S.lastPrefs.type)) sel.value = S.lastPrefs.type;
|
|
65
67
|
// 首屏默认落在「直接执行」(快档位:单 CLI 直达,无拆解/评审);
|
|
@@ -153,6 +155,7 @@ function toggleTypeMenu(force) {
|
|
|
153
155
|
}
|
|
154
156
|
|
|
155
157
|
function pickType(id) {
|
|
158
|
+
S.typeTouched = true; // 用户手动选过:flows 重渲染时优先保住,不让位偏好记忆
|
|
156
159
|
const sel = $("f-type");
|
|
157
160
|
if (sel && sel.value !== id) {
|
|
158
161
|
sel.value = id;
|
|
@@ -8969,19 +8972,39 @@ function mkCharsText(n) {
|
|
|
8969
8972
|
return t("约 ") + n + " " + t("字");
|
|
8970
8973
|
}
|
|
8971
8974
|
|
|
8972
|
-
function mkCardHtml(p) {
|
|
8975
|
+
function mkCardHtml(p, section) {
|
|
8973
8976
|
let ops;
|
|
8974
8977
|
if (p.builtin) ops = '<button class="ghost small" disabled>' + t("已内置") + "</button>";
|
|
8975
8978
|
else if (p.installed) ops = '<span class="tag ok">' + t("已安装") + "</span>" +
|
|
8976
8979
|
'<button class="ghost small" onclick="mkRemove(\'' + esc(p.id) + '\')">' + t("卸载") + "</button>";
|
|
8977
8980
|
else ops = '<button class="primary small" onclick="mkInstall(\'' + esc(p.id) + '\')">' + t("安装") + "</button>";
|
|
8981
|
+
// 已装插件卡片直接给启停开关(对齐 ZCode 插件管理形态:启停不用去经验库翻)
|
|
8982
|
+
const toggle = p.installed
|
|
8983
|
+
? '<label class="switch" title="' + (p.enabled ? t("已启用") : t("已停用")) + '">' +
|
|
8984
|
+
'<input type="checkbox"' + (p.enabled ? " checked" : "") +
|
|
8985
|
+
' onchange="mkTogglePack(\'' + esc(p.id) + '\', this.checked)"></label>'
|
|
8986
|
+
: "";
|
|
8987
|
+
const sec = section ? '<span class="tag mk-sec">' + esc(section) + "</span>" : "";
|
|
8978
8988
|
return '<div class="card mk-card"><div class="head">' +
|
|
8979
8989
|
'<span class="name">' + esc(t(p.name)) + "</span>" +
|
|
8980
|
-
'<span class="tag">' + esc(t(p.category || "")) + "</span>" +
|
|
8990
|
+
'<span class="tag">' + esc(t(p.category || "")) + "</span>" + sec +
|
|
8981
8991
|
"</div>" +
|
|
8982
8992
|
'<div class="note">' + esc(t(p.desc || "")) + "</div>" +
|
|
8983
8993
|
'<div class="mk-meta"><span title="' + esc(t("运行该类型任务时自动注入提示词,无需手动调用")) + '">' + t("适用:") + esc(mkScopeText(p.scopes)) + "</span><span>" + esc(mkCharsText(p.chars)) + "</span></div>" +
|
|
8984
|
-
'<div class="ops">' + ops + "</div></div>";
|
|
8994
|
+
'<div class="ops">' + ops + toggle + "</div></div>";
|
|
8995
|
+
}
|
|
8996
|
+
|
|
8997
|
+
/* 已装插件启停:走经验库包启停(同一条链),停用后该插件不再注入任务提示词 */
|
|
8998
|
+
async function mkTogglePack(id, enabled) {
|
|
8999
|
+
try {
|
|
9000
|
+
await api("/api/skills/pack-op", { method: "POST",
|
|
9001
|
+
body: JSON.stringify({ id, op: enabled ? "enable" : "disable" }) });
|
|
9002
|
+
toast(enabled ? t("已启用") : t("已停用(不再注入任务提示词)"));
|
|
9003
|
+
loadMarket();
|
|
9004
|
+
} catch (e) {
|
|
9005
|
+
toast(e.message || t("操作失败"), true);
|
|
9006
|
+
loadMarket();
|
|
9007
|
+
}
|
|
8985
9008
|
}
|
|
8986
9009
|
|
|
8987
9010
|
function renderMarket() {
|
|
@@ -9011,7 +9034,22 @@ function renderMarket() {
|
|
|
9011
9034
|
(p.name || "").toLowerCase().indexOf(q) >= 0 || (p.desc || "").toLowerCase().indexOf(q) >= 0);
|
|
9012
9035
|
const cnt = $("mk-count");
|
|
9013
9036
|
if (cnt && mkActiveView() === "local") cnt.textContent = t("共 ") + items.length + t(" 个");
|
|
9014
|
-
|
|
9037
|
+
// 分区渲染(对齐 ZCode 插件管理形态):内置 / 已安装 / 可安装三组,
|
|
9038
|
+
// 各组小标题+卡片;「全部」以外状态只出命中的那组
|
|
9039
|
+
if (st === "all" && !cat && !q) {
|
|
9040
|
+
const builtin = items.filter((p) => p.builtin);
|
|
9041
|
+
const inst = items.filter((p) => !p.builtin && p.installed);
|
|
9042
|
+
const avail = items.filter((p) => !p.builtin && !p.installed);
|
|
9043
|
+
const sec = (title, list) => list.length
|
|
9044
|
+
? '<h3 class="sec-title">' + title + " " + list.length + "</h3>" +
|
|
9045
|
+
'<div class="mk-grid">' + list.map((p) => mkCardHtml(p, t(title))).join("") + "</div>"
|
|
9046
|
+
: "";
|
|
9047
|
+
grid.innerHTML =
|
|
9048
|
+
sec(t("内置"), builtin) + sec(t("已安装"), inst) + sec(t("可安装"), avail) ||
|
|
9049
|
+
'<div class="empty">' + t("没有符合条件插件") + "</div>";
|
|
9050
|
+
return;
|
|
9051
|
+
}
|
|
9052
|
+
grid.innerHTML = items.map((p) => mkCardHtml(p)).join("") || '<div class="empty">' + t("没有符合条件插件") + "</div>";
|
|
9015
9053
|
}
|
|
9016
9054
|
|
|
9017
9055
|
async function mkInstall(id) {
|
package/app/ui/i18n.js
CHANGED
|
@@ -1281,6 +1281,8 @@
|
|
|
1281
1281
|
"约 ": "about ",
|
|
1282
1282
|
"字": "chars",
|
|
1283
1283
|
"已内置": "Built-in",
|
|
1284
|
+
"已启用": "Enabled",
|
|
1285
|
+
"已停用(不再注入任务提示词)": "Disabled — no longer injected into task prompts",
|
|
1284
1286
|
"没有符合条件插件": "No plugins match the filters",
|
|
1285
1287
|
"该插件已安装过": "Already installed",
|
|
1286
1288
|
"安装成功,运行任务时自动注入提示词;可到「经验库」启停或查看": "Installed — auto-injected into prompts when tasks run; enable/disable or view it in the skill library",
|
|
@@ -1327,6 +1329,16 @@
|
|
|
1327
1329
|
"更新插件": "Update plugin",
|
|
1328
1330
|
"更新模型配置": "Update model settings",
|
|
1329
1331
|
"更新智能体绑定": "Update agent binding",
|
|
1332
|
+
"测试禅道连接": "Test ZenTao connection",
|
|
1333
|
+
"拉取禅道产品": "Fetch ZenTao products",
|
|
1334
|
+
"拉取禅道账号": "Fetch ZenTao accounts",
|
|
1335
|
+
"拉取模块清单": "Fetch module list",
|
|
1336
|
+
"禅道扫描 Bug": "Scan ZenTao bugs",
|
|
1337
|
+
"保存禅道配置": "Save ZenTao settings",
|
|
1338
|
+
"刷新群列表": "Refresh group list",
|
|
1339
|
+
"扫描群摘要": "Scan digests",
|
|
1340
|
+
"保存群摘要设置": "Save digest settings",
|
|
1341
|
+
"关闭端口进程": "Close port process",
|
|
1330
1342
|
"提交操作": "Submit operation",
|
|
1331
1343
|
"{0} 项处理中": "{0} in progress",
|
|
1332
1344
|
"{0} 项失败": "{0} failed",
|
package/app/ui/index.html
CHANGED
|
@@ -305,6 +305,31 @@
|
|
|
305
305
|
<div id="cmp-quick" class="cmp-quick" role="group" aria-label="常用类型" data-i18n-aria="常用类型"></div>
|
|
306
306
|
<!-- 开跑前成本预估(refreshEstimate 填充;无同类样本时保持隐藏) -->
|
|
307
307
|
<p class="hint cmp-estimate hidden" id="cmp-estimate"></p>
|
|
308
|
+
<!-- 编排偏好贴输入框(用户拍板「放上来」:不再折叠进更多选项) -->
|
|
309
|
+
<div class="cmp-prefs" id="cmp-prefs">
|
|
310
|
+
<div class="field">
|
|
311
|
+
<label data-i18n="编排模式">编排模式</label>
|
|
312
|
+
<select id="f-mode">
|
|
313
|
+
<option data-i18n="自动(推荐):按任务类型与风险动态决定步骤" value="auto">自动(推荐):按任务类型与风险动态决定步骤</option>
|
|
314
|
+
<option data-i18n="快速:少步骤优先,先做确定性验收" value="fast">快速:少步骤优先,先做确定性验收</option>
|
|
315
|
+
<option data-i18n="专家:完整规划、多评审、失败修复与换将" value="expert">专家:完整规划、多评审、失败修复与换将</option>
|
|
316
|
+
<option data-i18n="手动:自行指定实现者与评审组" value="manual">手动:自行指定实现者与评审组</option>
|
|
317
|
+
</select>
|
|
318
|
+
</div>
|
|
319
|
+
<div class="field">
|
|
320
|
+
<label data-i18n="思考程度">思考程度</label>
|
|
321
|
+
<select id="f-thinking">
|
|
322
|
+
<option data-i18n="标准:平衡质量与速度" value="standard" selected>标准:平衡质量与速度</option>
|
|
323
|
+
<option data-i18n="自动:随任务难度调整" value="auto">自动:随任务难度调整</option>
|
|
324
|
+
<option data-i18n="快速:少推理、优先响应" value="low">快速:少推理、优先响应</option>
|
|
325
|
+
<option data-i18n="深度:更多推理与检查" value="high">深度:更多推理与检查</option>
|
|
326
|
+
</select>
|
|
327
|
+
</div>
|
|
328
|
+
<div id="f-direct-model" class="field hidden"><label data-i18n="对话模型(可选)">对话模型(可选)</label><div class="grid-2">
|
|
329
|
+
<select id="f-direct-provider" aria-label="对话厂商" data-i18n-aria="对话厂商"><option data-i18n="自动推荐">自动推荐</option></select>
|
|
330
|
+
<select id="f-direct-model-name" aria-label="对话模型" data-i18n-aria="对话模型"><option data-i18n="随厂商推荐">随厂商推荐</option></select>
|
|
331
|
+
</div><p class="hint" data-i18n="只对本次对话生效,不会修改全局绑定;指定渠道不可用时会明确报错。">只对本次对话生效,不会修改全局绑定;指定渠道不可用时会明确报错。</p></div>
|
|
332
|
+
</div>
|
|
308
333
|
<!-- 需求拷问采访卡(renderClarify 渲染;goal 模糊时出现,跳过=直接创建) -->
|
|
309
334
|
<div id="clarify-box" class="clarify-box hidden"></div>
|
|
310
335
|
<div class="field hidden" id="row-resume-session">
|
|
@@ -326,27 +351,6 @@
|
|
|
326
351
|
<div class="field"><label data-i18n="任务标题">任务标题</label><input id="f-title" placeholder="可空,自动取目标首行" data-i18n-ph="可空,自动取目标首行"></div>
|
|
327
352
|
</div>
|
|
328
353
|
<div class="field"><label data-i18n="上下文">上下文</label><textarea id="f-context" rows="2" placeholder="背景信息、约束、相关文件(可空)" data-i18n-ph="背景信息、约束、相关文件(可空)"></textarea></div>
|
|
329
|
-
<div class="field">
|
|
330
|
-
<label data-i18n="编排模式">编排模式</label>
|
|
331
|
-
<select id="f-mode">
|
|
332
|
-
<option data-i18n="自动(推荐):按任务类型与风险动态决定步骤" value="auto">自动(推荐):按任务类型与风险动态决定步骤</option>
|
|
333
|
-
<option data-i18n="快速:少步骤优先,先做确定性验收" value="fast">快速:少步骤优先,先做确定性验收</option>
|
|
334
|
-
<option data-i18n="专家:完整规划、多评审、失败修复与换将" value="expert">专家:完整规划、多评审、失败修复与换将</option>
|
|
335
|
-
<option data-i18n="手动:自行指定实现者与评审组" value="manual">手动:自行指定实现者与评审组</option>
|
|
336
|
-
</select>
|
|
337
|
-
</div>
|
|
338
|
-
<div class="grid-2">
|
|
339
|
-
<div class="field"><label data-i18n="思考程度">思考程度</label><select id="f-thinking">
|
|
340
|
-
<option data-i18n="标准:平衡质量与速度" value="standard" selected>标准:平衡质量与速度</option>
|
|
341
|
-
<option data-i18n="自动:随任务难度调整" value="auto">自动:随任务难度调整</option>
|
|
342
|
-
<option data-i18n="快速:少推理、优先响应" value="low">快速:少推理、优先响应</option>
|
|
343
|
-
<option data-i18n="深度:更多推理与检查" value="high">深度:更多推理与检查</option>
|
|
344
|
-
</select></div>
|
|
345
|
-
<div id="f-direct-model" class="field hidden"><label data-i18n="对话模型(可选)">对话模型(可选)</label><div class="grid-2">
|
|
346
|
-
<select id="f-direct-provider" aria-label="对话厂商" data-i18n-aria="对话厂商"><option data-i18n="自动推荐">自动推荐</option></select>
|
|
347
|
-
<select id="f-direct-model-name" aria-label="对话模型" data-i18n-aria="对话模型"><option data-i18n="随厂商推荐">随厂商推荐</option></select>
|
|
348
|
-
</div><p class="hint" data-i18n="只对本次对话生效,不会修改全局绑定;指定渠道不可用时会明确报错。">只对本次对话生效,不会修改全局绑定;指定渠道不可用时会明确报错。</p></div>
|
|
349
|
-
</div>
|
|
350
354
|
|
|
351
355
|
<div id="f-code-only">
|
|
352
356
|
<div class="field"><label data-i18n="验证命令">验证命令</label><input id="f-verify" placeholder="例:python -m pytest -q(可空=只评审)" data-i18n-ph="例:python -m pytest -q(可空=只评审)"></div>
|
package/app/ui/style.css
CHANGED
|
@@ -5615,3 +5615,28 @@ button.request-busy > * { opacity: .18; }
|
|
|
5615
5615
|
.ch-ev { padding-left: 10px; border-left: 2px solid var(--border); color: var(--muted); }
|
|
5616
5616
|
.ch-ev.ok { border-left-color: var(--ok); color: inherit; }
|
|
5617
5617
|
.ch-ev.bad { border-left-color: var(--bad); color: inherit; }
|
|
5618
|
+
|
|
5619
|
+
/* composer 内编排偏好行:编排模式/思考程度/对话模型贴着输入框(2026-09-21
|
|
5620
|
+
* 用户拍板「放上来」,不再折叠进「更多选项」)。字段横向紧凑排布,窄屏换行。 */
|
|
5621
|
+
.cmp-prefs { display: flex; flex-wrap: wrap; gap: 8px 20px; padding: 6px 2px 2px; }
|
|
5622
|
+
.cmp-prefs > .field { display: flex; align-items: center; gap: 8px; flex: 1 1 260px;
|
|
5623
|
+
min-width: 0; margin: 0; }
|
|
5624
|
+
.cmp-prefs > .field > label { white-space: nowrap; flex: none; margin: 0;
|
|
5625
|
+
font-size: 12.5px; color: var(--muted); }
|
|
5626
|
+
.cmp-prefs > .field > select { flex: 1 1 auto; min-width: 0; width: auto; }
|
|
5627
|
+
/* 对话模型(可选)默认整行:label + 双下拉 + 说明文字 */
|
|
5628
|
+
.cmp-prefs > #f-direct-model { flex: 1 1 100%; align-items: center; }
|
|
5629
|
+
.cmp-prefs > #f-direct-model > .grid-2 { flex: 1 1 auto; min-width: 0; }
|
|
5630
|
+
.cmp-prefs > #f-direct-model > .hint { flex: 1 1 100%; margin: 0; }
|
|
5631
|
+
|
|
5632
|
+
/* 插件市场:内置/已安装/可安装分区标题与已装启停开关(对齐 ZCode 形态) */
|
|
5633
|
+
#mk-grid .sec-title { margin: 14px 0 6px; }
|
|
5634
|
+
.mk-sec { background: color-mix(in srgb, var(--accent) 12%, transparent); }
|
|
5635
|
+
.mk-card .switch { display: inline-flex; align-items: center; cursor: pointer; }
|
|
5636
|
+
.mk-card .switch input { appearance: none; width: 34px; height: 19px;
|
|
5637
|
+
border-radius: 999px; background: var(--border, rgba(128,128,128,.4));
|
|
5638
|
+
position: relative; cursor: pointer; transition: background .15s; margin: 0; }
|
|
5639
|
+
.mk-card .switch input:checked { background: var(--accent); }
|
|
5640
|
+
.mk-card .switch input::after { content: ""; position: absolute; top: 2px; left: 2px;
|
|
5641
|
+
width: 15px; height: 15px; border-radius: 50%; background: #fff; transition: left .15s; }
|
|
5642
|
+
.mk-card .switch input:checked::after { left: 17px; }
|
package/package.json
CHANGED