codebee 0.1.56 → 0.1.57
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 +7 -0
- package/README.md +4 -3
- package/app/.playwright-cli/console-2026-09-23T08-26-03-635Z.log +88 -0
- package/app/.playwright-cli/page-2026-09-23T08-26-03-845Z.yml +126 -0
- package/app/.playwright-cli/page-2026-09-23T08-29-44-203Z.png +0 -0
- package/app/.playwright-cli/page-2026-09-23T08-35-42-046Z.yml +210 -0
- package/app/.playwright-cli/page-2026-09-23T08-36-52-858Z.png +0 -0
- package/app/.playwright-cli/page-2026-09-23T08-37-33-938Z.png +0 -0
- package/app/.playwright-cli/run-detail-after.png +0 -0
- package/app/core/beekeeper.py +183 -0
- package/app/core/branching.py +31 -6
- package/app/core/jobs.py +3 -3
- package/app/core/pipeline.py +4143 -4112
- package/app/core/publish/browser.py +4 -0
- package/app/core/remote.py +2 -0
- package/app/core/runner.py +486 -474
- package/app/core/selfupdate.py +19 -18
- package/app/core/skill_scan.py +5 -0
- package/app/core/store.py +95 -64
- package/app/core/zentao.py +80 -0
- package/app/main.py +2805 -2768
- package/app/ui/app.js +13954 -13639
- package/app/ui/board.css +732 -650
- package/app/ui/i18n.js +10 -2
- package/app/ui/index.html +1 -2
- package/app/ui/style.css +6106 -6107
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,7 @@ README 元数据带回,供老版本在「发现新版本」时展示新版更
|
|
|
8
8
|
|
|
9
9
|
### ✨ 新功能
|
|
10
10
|
|
|
11
|
+
- **工作汇报能直接取禅道数了**:新建「工作汇报」任务时,若已配置禅道集成,起草阶段自动把「分配给我的活跃任务 + 指派给我的活跃 Bug」聚合成本周工作素材注入起草提示(如实取材、缺失数字留待补、勿虚构业绩)——不再只靠你贴流水账。禅道未配置或临时不可达时静默跳过,起草照常。
|
|
11
12
|
- **直连对话把「思考过程」打印出来了**:内置智能体改走流式(SSE),模型的思维链(DeepSeek/vLLM 系 `reasoning_content`、Anthropic `thinking` 块)边生成边实时打印进对话时间线,工具调用与正文增量同步显示——此前整轮回答只有三个点的打字动画,几十秒黑箱干等。运行中思考块常开实时增长;回答收尾后收成「思考过程」折叠摘要(带字数,点开回看),思维链同时进步骤日志。网关不支持流式时自动回落非流式(思考字段仍从响应体兜底抽取),取消/多 KEY 换链语义不变。
|
|
12
13
|
- **日志抽屉认识 claude 事件流了**:claude 步骤日志此前整段原样 JSON,模型长思考时 `thinking_tokens` 心跳每个流式分片刷一条(真实案:3.2MB 步骤日志 15828 条),把正文顶出尾部窗口。现在抽屉视图按邻近组折叠成一行「— 思考中(心跳 ×N 已折叠,估算 ~M tokens)—」,会话启动/API 重试/思考摘要/正文/收尾统计各自翻译成可读行(API 重试逐条保留——429 与断连诊断金矿);只影响显示,原始日志与结果解析不动。
|
|
13
14
|
- 新增**网页成品实时预览**:代码任务跑完,详情页多出「预览」页签——「运行视图」把工作目录里的入口 HTML 真跑起来(iframe 里 style.css / script.js 这些相对引用照常生效,改完点「刷新」即看新版),旁边一排文件页签直接读源码(行号 + 高亮,与成果预览同款),右上角「打开新窗口」给真全屏。借鉴对话式编程产品"边聊边看效果"的体验:终态代码任务跑出了可打开的网页成品时,打开详情直接落在预览;直连对话任务的对话胶囊里也有「预览」入口。没有网页成品的任务(小说、普通脚本)完全不出现这个页签。安全边界:预览是只读静态挂载,只认静态扩展名白名单、拒绝路径穿越与隐藏目录;访问令牌走路径段(iframe 子资源继承不了查询串),鉴权与 /api/* 同一把尺子。
|
|
@@ -23,6 +24,12 @@ README 元数据带回,供老版本在「发现新版本」时展示新版更
|
|
|
23
24
|
|
|
24
25
|
- **首选 KEY 超限自动切备用了**:同厂商多密钥此前只认欠费类文案——首选 KEY 撞上 429 限流(智谱「并发数超过限制」「每分钟Token数已超过上限」、claude 的 rate_limit_error、codex 的 "429 Too Many Requests" 等)只记一笔错误、不进冷却,每个新步骤仍从超限的首选 KEY 重新烧起。现在限流文案与欠费同口径:进冷却 30 分钟、密钥镜像自动切下一把、链展开跳过冷却中的 KEY(到期或「恢复」按钮一键回首选)。顺带补一处漏账:无显式链时「换模型回退」的链条目不带 KEY 标记,这类重试失败此前完全不记 KEY 账。
|
|
25
26
|
|
|
27
|
+
## v0.1.57(2026-09-23)
|
|
28
|
+
|
|
29
|
+
- 任务详情历史运行分页 + 加载提速(详情打开更快,支持「加载更早运行」)
|
|
30
|
+
- 修复:repeat-guard 判死后外层重试继续空转(stop=True 不生效,同输入最多多烧 5 次)——判死现在终态生效
|
|
31
|
+
- 直连对话时长统计修正;任务时限兜底行为补测试
|
|
32
|
+
|
|
26
33
|
## v0.1.56(2026-09-23)
|
|
27
34
|
|
|
28
35
|
- 鉴权错误不再触发换将:密钥失效类错误换哪个 CLI 都一样,直接报错省时间
|
package/README.md
CHANGED
|
@@ -21,10 +21,11 @@ Kimi Code、MiMo Code、Grok Build、Pi、DeepSeek Harness……),提供
|
|
|
21
21
|
不会把你的任务内容交给任何第三方。
|
|
22
22
|
|
|
23
23
|
<!-- relnotes:start -->
|
|
24
|
-
### 最新版更新内容(v0.1.
|
|
24
|
+
### 最新版更新内容(v0.1.57)
|
|
25
25
|
|
|
26
|
-
-
|
|
27
|
-
-
|
|
26
|
+
- 任务详情历史运行分页 + 打开提速
|
|
27
|
+
- 修复重复调用守卫判死后外层重试继续空转的问题(Bigmodel Key 挂死实案)
|
|
28
|
+
- 直连对话时长统计修正
|
|
28
29
|
<!-- relnotes:end -->
|
|
29
30
|
|
|
30
31
|
---
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
[ 154ms] [VERBOSE] [DOM] Password field is not contained in a form: (More info: https://goo.gl/9p2vKq) %o @ http://127.0.0.1:8766/board.html:0
|
|
2
|
+
[ 4086ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
3
|
+
[ 8084ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
4
|
+
[ 12084ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
5
|
+
[ 16071ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
6
|
+
[ 20083ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
7
|
+
[ 24080ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
8
|
+
[ 28074ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
9
|
+
[ 32078ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
10
|
+
[ 36084ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
11
|
+
[ 40087ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
12
|
+
[ 44075ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
13
|
+
[ 48074ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
14
|
+
[ 52070ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
15
|
+
[ 56083ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
16
|
+
[ 60070ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
17
|
+
[ 64074ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
18
|
+
[ 68084ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
19
|
+
[ 72076ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
20
|
+
[ 76083ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
21
|
+
[ 80075ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
22
|
+
[ 84072ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
23
|
+
[ 88077ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
24
|
+
[ 92073ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
25
|
+
[ 96084ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
26
|
+
[ 100086ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
27
|
+
[ 104085ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
28
|
+
[ 108083ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
29
|
+
[ 112083ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
30
|
+
[ 116076ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
31
|
+
[ 120074ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
32
|
+
[ 124084ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
33
|
+
[ 128080ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
34
|
+
[ 132074ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
35
|
+
[ 136074ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
36
|
+
[ 140070ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
37
|
+
[ 144080ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
38
|
+
[ 148075ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
39
|
+
[ 152077ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
40
|
+
[ 156075ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
41
|
+
[ 160072ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
42
|
+
[ 164074ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
43
|
+
[ 168083ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
44
|
+
[ 172076ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
45
|
+
[ 176073ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
46
|
+
[ 180085ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
47
|
+
[ 184071ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
48
|
+
[ 188079ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
49
|
+
[ 192075ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
50
|
+
[ 196085ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
51
|
+
[ 200073ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
52
|
+
[ 204080ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
53
|
+
[ 208077ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
54
|
+
[ 212074ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
55
|
+
[ 216084ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
56
|
+
[ 220077ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
57
|
+
[ 224077ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
58
|
+
[ 228079ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
59
|
+
[ 232072ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
60
|
+
[ 236083ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
61
|
+
[ 240069ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
62
|
+
[ 244077ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
63
|
+
[ 248085ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
64
|
+
[ 252072ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
65
|
+
[ 256073ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
66
|
+
[ 260078ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
67
|
+
[ 264072ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
68
|
+
[ 268074ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
69
|
+
[ 272082ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
70
|
+
[ 276076ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
71
|
+
[ 280075ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
72
|
+
[ 284079ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
73
|
+
[ 288083ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
74
|
+
[ 292069ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
75
|
+
[ 296083ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
76
|
+
[ 300075ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
77
|
+
[ 304077ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
78
|
+
[ 308074ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
79
|
+
[ 312079ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
80
|
+
[ 316074ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
81
|
+
[ 320076ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
82
|
+
[ 324084ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
83
|
+
[ 328076ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
84
|
+
[ 332080ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
85
|
+
[ 336077ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
86
|
+
[ 340085ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8766/api/board:0
|
|
87
|
+
[ 438049ms] [VERBOSE] [DOM] Password field is not contained in a form: (More info: https://goo.gl/9p2vKq) %o @ http://127.0.0.1:8766/board.html:0
|
|
88
|
+
[ 578323ms] [VERBOSE] [DOM] Password field is not contained in a form: (More info: https://goo.gl/9p2vKq) %o @ http://127.0.0.1:8766/board.html:0
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
- generic [active] [ref=e1]:
|
|
2
|
+
- banner [ref=e2]:
|
|
3
|
+
- generic [ref=e8]:
|
|
4
|
+
- generic [ref=e9]: CODEBEE / OPERATIONS
|
|
5
|
+
- generic [ref=e10]: 任务驾驶舱
|
|
6
|
+
- generic [ref=e11]:
|
|
7
|
+
- generic [ref=e13]: 实时监控
|
|
8
|
+
- generic [ref=e14]: /
|
|
9
|
+
- generic [ref=e15]: 已同步 · 16:26:03
|
|
10
|
+
- generic [ref=e16]:
|
|
11
|
+
- generic "执行池占用" [ref=e17]: 蜂巢 0/12 · 对话 0/4
|
|
12
|
+
- generic [ref=e18]: "--:--:--"
|
|
13
|
+
- main [ref=e19]:
|
|
14
|
+
- generic [ref=e20]:
|
|
15
|
+
- text: OPERATIONS / STATUS
|
|
16
|
+
- generic [ref=e21]:
|
|
17
|
+
- generic [ref=e22]: 蜂群状态
|
|
18
|
+
- generic [ref=e25]:
|
|
19
|
+
- generic [ref=e26]:
|
|
20
|
+
- heading "蜂群待命" [level=1] [ref=e27]
|
|
21
|
+
- paragraph [ref=e28]: 没有正在运行的任务,新任务在主界面创建后会实时出现在这里
|
|
22
|
+
- generic [ref=e29]:
|
|
23
|
+
- strong [ref=e30]: "0"
|
|
24
|
+
- generic [ref=e31]: 个活动单元
|
|
25
|
+
- generic [ref=e32]:
|
|
26
|
+
- generic [ref=e33]: 系统状态良好
|
|
27
|
+
- generic [ref=e36]: 实时聚合 · 每 4 秒刷新
|
|
28
|
+
- generic [ref=e44]:
|
|
29
|
+
- strong [ref=e45]: "0"
|
|
30
|
+
- generic [ref=e46]: ACTIVE
|
|
31
|
+
- generic [ref=e47]:
|
|
32
|
+
- generic [ref=e48]: 执行池
|
|
33
|
+
- generic [ref=e50]:
|
|
34
|
+
- strong [ref=e51]: "0"
|
|
35
|
+
- generic [ref=e52]: /
|
|
36
|
+
- generic [ref=e53]: "12"
|
|
37
|
+
- emphasis [ref=e54]: 在线槽位
|
|
38
|
+
- generic [ref=e56]:
|
|
39
|
+
- generic [ref=e57]: 队列等待
|
|
40
|
+
- generic [ref=e58]: "0"
|
|
41
|
+
- generic [ref=e59]:
|
|
42
|
+
- generic [ref=e60]: 今日成功率
|
|
43
|
+
- generic [ref=e61]: —
|
|
44
|
+
- region "核心指标" [ref=e62]:
|
|
45
|
+
- generic [ref=e63]:
|
|
46
|
+
- generic [ref=e64]: 运行中
|
|
47
|
+
- generic [ref=e67]: "0"
|
|
48
|
+
- generic [ref=e68]:
|
|
49
|
+
- generic [ref=e69]: 当前活动
|
|
50
|
+
- generic [ref=e70]: LIVE
|
|
51
|
+
- generic [ref=e71]:
|
|
52
|
+
- generic [ref=e72]: 排队中
|
|
53
|
+
- generic [ref=e75]: "0"
|
|
54
|
+
- generic [ref=e76]:
|
|
55
|
+
- generic [ref=e77]: 等待调度
|
|
56
|
+
- generic [ref=e78]: QUEUE
|
|
57
|
+
- generic [ref=e79]:
|
|
58
|
+
- generic [ref=e80]: 今日完成
|
|
59
|
+
- generic [ref=e83]: "0"
|
|
60
|
+
- generic [ref=e84]:
|
|
61
|
+
- generic [ref=e85]: 完成运行
|
|
62
|
+
- generic [ref=e86]: DONE
|
|
63
|
+
- generic [ref=e87]:
|
|
64
|
+
- generic [ref=e88]: 今日失败
|
|
65
|
+
- generic [ref=e91]: "0"
|
|
66
|
+
- generic [ref=e92]:
|
|
67
|
+
- generic [ref=e93]: 需要关注
|
|
68
|
+
- generic [ref=e94]: ALERT
|
|
69
|
+
- generic [ref=e95]:
|
|
70
|
+
- generic [ref=e96]: 今日 tokens
|
|
71
|
+
- generic [ref=e99]: "0"
|
|
72
|
+
- generic [ref=e100]:
|
|
73
|
+
- generic [ref=e101]: 模型消耗
|
|
74
|
+
- generic [ref=e102]: USAGE
|
|
75
|
+
- generic [ref=e103]:
|
|
76
|
+
- generic [ref=e104]: 今日成本
|
|
77
|
+
- generic [ref=e107]: $0.000
|
|
78
|
+
- generic [ref=e108]:
|
|
79
|
+
- generic [ref=e109]: 运行成本
|
|
80
|
+
- generic [ref=e110]: COST
|
|
81
|
+
- generic [ref=e111]:
|
|
82
|
+
- generic [ref=e112]:
|
|
83
|
+
- generic [ref=e113]:
|
|
84
|
+
- generic [ref=e114]:
|
|
85
|
+
- generic [ref=e115]: 实时任务流
|
|
86
|
+
- heading "运行中任务" [level=2] [ref=e118]
|
|
87
|
+
- generic [ref=e119]:
|
|
88
|
+
- generic [ref=e120]: 0 ACTIVE
|
|
89
|
+
- generic [ref=e121]: 监控中
|
|
90
|
+
- generic [ref=e122]:
|
|
91
|
+
- text: NO ACTIVE RUNS
|
|
92
|
+
- generic [ref=e127]: "0"
|
|
93
|
+
- generic [ref=e128]: 队列已清空
|
|
94
|
+
- generic [ref=e129]: 等待新的任务接入蜂巢
|
|
95
|
+
- generic [ref=e130]:
|
|
96
|
+
- generic [ref=e131]: 工作池就绪
|
|
97
|
+
- generic [ref=e134]: 监控在线
|
|
98
|
+
- complementary [ref=e137]:
|
|
99
|
+
- generic [ref=e138]:
|
|
100
|
+
- generic [ref=e139]:
|
|
101
|
+
- generic [ref=e140]:
|
|
102
|
+
- generic [ref=e141]: 资源脉冲
|
|
103
|
+
- heading "近 7 日 tokens" [level=3] [ref=e144]
|
|
104
|
+
- generic [ref=e145]: 7 DAYS
|
|
105
|
+
- generic [ref=e146]:
|
|
106
|
+
- generic "2026-09-17 · 0" [ref=e147]: 09-17
|
|
107
|
+
- generic "2026-09-18 · 0" [ref=e150]: 09-18
|
|
108
|
+
- generic "2026-09-19 · 0" [ref=e153]: 09-19
|
|
109
|
+
- generic "2026-09-20 · 0" [ref=e156]: 09-20
|
|
110
|
+
- generic "2026-09-21 · 0" [ref=e159]: 09-21
|
|
111
|
+
- generic "2026-09-22 · 0" [ref=e162]: 09-22
|
|
112
|
+
- generic "2026-09-23 · 0" [ref=e165]: 09-23
|
|
113
|
+
- generic [ref=e168]:
|
|
114
|
+
- generic [ref=e169]:
|
|
115
|
+
- generic [ref=e170]:
|
|
116
|
+
- generic [ref=e171]: 模型分布
|
|
117
|
+
- heading "近 7 日模型 TOP5" [level=3] [ref=e174]
|
|
118
|
+
- generic [ref=e175]: TOP 5
|
|
119
|
+
- generic [ref=e176]: 暂无调用记录
|
|
120
|
+
- generic [ref=e178]:
|
|
121
|
+
- generic [ref=e179]:
|
|
122
|
+
- generic [ref=e180]:
|
|
123
|
+
- generic [ref=e181]: 事件日志
|
|
124
|
+
- heading "最近动态" [level=3] [ref=e184]
|
|
125
|
+
- generic [ref=e185]: 0 条事件
|
|
126
|
+
- generic [ref=e186]: 还没有已完成的运行
|
|
Binary file
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
- generic [active] [ref=f3e1]:
|
|
2
|
+
- banner [ref=f3e2]:
|
|
3
|
+
- generic [ref=f3e8]:
|
|
4
|
+
- generic [ref=f3e9]: CODEBEE / OPERATIONS
|
|
5
|
+
- generic [ref=f3e10]: 任务驾驶舱
|
|
6
|
+
- generic [ref=f3e11]:
|
|
7
|
+
- generic [ref=f3e13]: 实时监控
|
|
8
|
+
- generic [ref=f3e14]: /
|
|
9
|
+
- generic [ref=f3e15]: 已同步 · 16:30:00
|
|
10
|
+
- generic [ref=f3e16]:
|
|
11
|
+
- generic "执行池占用" [ref=f3e17]: 蜂巢 3/5 · 对话 0/4
|
|
12
|
+
- generic [ref=f3e18]: "--:--:--"
|
|
13
|
+
- main [ref=f3e19]:
|
|
14
|
+
- generic [ref=f3e20]:
|
|
15
|
+
- text: OPERATIONS / STATUS
|
|
16
|
+
- generic [ref=f3e21]:
|
|
17
|
+
- generic [ref=f3e22]: 蜂群状态
|
|
18
|
+
- generic [ref=f3e25]:
|
|
19
|
+
- generic [ref=f3e26]:
|
|
20
|
+
- heading "蜂群运行中" [level=1] [ref=f3e27]
|
|
21
|
+
- paragraph [ref=f3e28]: 当前有 3 个任务正在并行执行
|
|
22
|
+
- generic [ref=f3e29]:
|
|
23
|
+
- strong [ref=f3e30]: "3"
|
|
24
|
+
- generic [ref=f3e31]: 个活动单元
|
|
25
|
+
- generic [ref=f3e32]:
|
|
26
|
+
- generic [ref=f3e33]: 系统状态良好
|
|
27
|
+
- generic [ref=f3e36]: 实时聚合 · 每 4 秒刷新
|
|
28
|
+
- generic [ref=f3e44]:
|
|
29
|
+
- strong [ref=f3e45]: "3"
|
|
30
|
+
- generic [ref=f3e46]: ACTIVE
|
|
31
|
+
- generic [ref=f3e47]:
|
|
32
|
+
- generic [ref=f3e48]: 执行池
|
|
33
|
+
- generic [ref=f3e50]:
|
|
34
|
+
- strong [ref=f3e51]: "3"
|
|
35
|
+
- generic [ref=f3e52]: /
|
|
36
|
+
- generic [ref=f3e53]: "5"
|
|
37
|
+
- emphasis [ref=f3e54]: 在线槽位
|
|
38
|
+
- generic [ref=f3e56]:
|
|
39
|
+
- generic [ref=f3e57]: 队列等待
|
|
40
|
+
- generic [ref=f3e58]: "0"
|
|
41
|
+
- generic [ref=f3e59]:
|
|
42
|
+
- generic [ref=f3e60]: 今日成功率
|
|
43
|
+
- generic [ref=f3e61]: 42%
|
|
44
|
+
- region "核心指标" [ref=f3e62]:
|
|
45
|
+
- generic [ref=f3e63]:
|
|
46
|
+
- generic [ref=f3e64]: 运行中
|
|
47
|
+
- generic [ref=f3e67]: "3"
|
|
48
|
+
- generic [ref=f3e68]:
|
|
49
|
+
- generic [ref=f3e69]: 当前活动
|
|
50
|
+
- generic [ref=f3e70]: LIVE
|
|
51
|
+
- generic [ref=f3e71]:
|
|
52
|
+
- generic [ref=f3e72]: 排队中
|
|
53
|
+
- generic [ref=f3e75]: "0"
|
|
54
|
+
- generic [ref=f3e76]:
|
|
55
|
+
- generic [ref=f3e77]: 等待调度
|
|
56
|
+
- generic [ref=f3e78]: QUEUE
|
|
57
|
+
- generic [ref=f3e79]:
|
|
58
|
+
- generic [ref=f3e80]: 今日完成
|
|
59
|
+
- generic [ref=f3e83]: "11"
|
|
60
|
+
- generic [ref=f3e84]:
|
|
61
|
+
- generic [ref=f3e85]: 完成运行
|
|
62
|
+
- generic [ref=f3e86]: DONE
|
|
63
|
+
- generic [ref=f3e87]:
|
|
64
|
+
- generic [ref=f3e88]: 今日失败
|
|
65
|
+
- generic [ref=f3e91]: "15"
|
|
66
|
+
- generic [ref=f3e92]:
|
|
67
|
+
- generic [ref=f3e93]: 需要关注
|
|
68
|
+
- generic [ref=f3e94]: ALERT
|
|
69
|
+
- generic [ref=f3e95]:
|
|
70
|
+
- generic [ref=f3e96]: 今日 tokens
|
|
71
|
+
- generic [ref=f3e99]: 1.78亿
|
|
72
|
+
- generic [ref=f3e100]:
|
|
73
|
+
- generic [ref=f3e101]: 模型消耗
|
|
74
|
+
- generic [ref=f3e102]: USAGE
|
|
75
|
+
- generic [ref=f3e103]:
|
|
76
|
+
- generic [ref=f3e104]: 今日成本
|
|
77
|
+
- generic [ref=f3e107]: $39.95
|
|
78
|
+
- generic [ref=f3e108]:
|
|
79
|
+
- generic [ref=f3e109]: 运行成本
|
|
80
|
+
- generic [ref=f3e110]: COST
|
|
81
|
+
- generic [ref=f3e111]:
|
|
82
|
+
- generic [ref=f3e112]:
|
|
83
|
+
- generic [ref=f3e113]:
|
|
84
|
+
- generic [ref=f3e114]:
|
|
85
|
+
- generic [ref=f3e115]: 实时任务流
|
|
86
|
+
- heading "运行中任务" [level=2] [ref=f3e118]
|
|
87
|
+
- generic [ref=f3e119]:
|
|
88
|
+
- generic [ref=f3e120]: 3 ACTIVE
|
|
89
|
+
- generic [ref=f3e121]: 监控中
|
|
90
|
+
- generic [ref=f3e122]:
|
|
91
|
+
- generic [ref=f3e123]:
|
|
92
|
+
- generic [ref=f3e124]:
|
|
93
|
+
- generic [ref=f3e125]: Code
|
|
94
|
+
- generic [ref=f3e126]: ZenTao backend coupon management attribute refactor
|
|
95
|
+
- generic [ref=f3e127]: 06:51
|
|
96
|
+
- generic [ref=f3e128]:
|
|
97
|
+
- generic [ref=f3e129]: glm-5.3-flash
|
|
98
|
+
- generic [ref=f3e130]: Bigmodel - API Key
|
|
99
|
+
- generic [ref=f3e131]: Claude Code
|
|
100
|
+
- generic [ref=f3e134]:
|
|
101
|
+
- generic [ref=f3e135]: "#1"
|
|
102
|
+
- generic [ref=f3e136]: Claude Code
|
|
103
|
+
- generic [ref=f3e137]: Running
|
|
104
|
+
- generic [ref=f3e138]: 预估 17:20 · 进度≈40%
|
|
105
|
+
- text: LIVE
|
|
106
|
+
- generic [ref=f3e139]:
|
|
107
|
+
- generic [ref=f3e140]:
|
|
108
|
+
- generic [ref=f3e141]: Docs
|
|
109
|
+
- generic [ref=f3e142]: Knowledge base weekly cleanup 09-23 00:30
|
|
110
|
+
- generic [ref=f3e143]: 08:11
|
|
111
|
+
- generic [ref=f3e144]:
|
|
112
|
+
- generic [ref=f3e145]: glm-5.3-flash
|
|
113
|
+
- generic [ref=f3e146]: Bigmodel - API Key
|
|
114
|
+
- generic [ref=f3e147]: Claude Code
|
|
115
|
+
- generic [ref=f3e150]:
|
|
116
|
+
- generic [ref=f3e151]: "#1"
|
|
117
|
+
- generic [ref=f3e152]: Claude Code
|
|
118
|
+
- generic [ref=f3e153]: Running
|
|
119
|
+
- generic [ref=f3e154]: 预估 15:20 · 进度≈53%
|
|
120
|
+
- text: LIVE
|
|
121
|
+
- generic [ref=f3e155]:
|
|
122
|
+
- generic [ref=f3e156]:
|
|
123
|
+
- generic [ref=f3e157]: Novel
|
|
124
|
+
- generic [ref=f3e158]: Choose a popular novel direction and generate an outline
|
|
125
|
+
- generic [ref=f3e159]: 09:11
|
|
126
|
+
- generic [ref=f3e160]:
|
|
127
|
+
- generic [ref=f3e161]: glm-5.3-flash
|
|
128
|
+
- generic [ref=f3e162]: Bigmodel - API Key
|
|
129
|
+
- generic [ref=f3e163]: Claude Code
|
|
130
|
+
- generic [ref=f3e173]:
|
|
131
|
+
- generic [ref=f3e174]: "#8"
|
|
132
|
+
- generic [ref=f3e175]: Claude Code
|
|
133
|
+
- generic [ref=f3e176]: Running
|
|
134
|
+
- generic [ref=f3e177]: 预估 17:20 · 进度≈53%
|
|
135
|
+
- text: LIVE
|
|
136
|
+
- text: NO ACTIVE RUNS
|
|
137
|
+
- complementary [ref=f3e178]:
|
|
138
|
+
- generic [ref=f3e179]:
|
|
139
|
+
- generic [ref=f3e180]:
|
|
140
|
+
- generic [ref=f3e181]:
|
|
141
|
+
- generic [ref=f3e182]: 资源脉冲
|
|
142
|
+
- heading "近 7 日 tokens" [level=3] [ref=f3e185]
|
|
143
|
+
- generic [ref=f3e186]: 7 DAYS
|
|
144
|
+
- generic [ref=f3e187]:
|
|
145
|
+
- generic "2026-09-17 · 0" [ref=f3e188]: 09-17
|
|
146
|
+
- generic "2026-09-18 · 0" [ref=f3e191]: 09-18
|
|
147
|
+
- generic "2026-09-19 · 2500.0万" [ref=f3e194]: 09-19
|
|
148
|
+
- generic "2026-09-20 · 0" [ref=f3e197]: 09-20
|
|
149
|
+
- generic "2026-09-21 · 5600.0万" [ref=f3e200]: 09-21
|
|
150
|
+
- generic "2026-09-22 · 9600.0万" [ref=f3e203]: 09-22
|
|
151
|
+
- generic "2026-09-23 · 9700.0万" [ref=f3e206]: 09-23
|
|
152
|
+
- generic [ref=f3e209]:
|
|
153
|
+
- generic [ref=f3e210]:
|
|
154
|
+
- generic [ref=f3e211]:
|
|
155
|
+
- generic [ref=f3e212]: 模型分布
|
|
156
|
+
- heading "近 7 日模型 TOP5" [level=3] [ref=f3e215]
|
|
157
|
+
- generic [ref=f3e216]: TOP 5
|
|
158
|
+
- generic [ref=f3e217]:
|
|
159
|
+
- generic [ref=f3e218]:
|
|
160
|
+
- generic "glm-5.3-flash" [ref=f3e219]
|
|
161
|
+
- generic [ref=f3e222]: 1962.5万
|
|
162
|
+
- generic [ref=f3e223]:
|
|
163
|
+
- generic "(default)" [ref=f3e224]
|
|
164
|
+
- generic [ref=f3e227]: 1134.0万
|
|
165
|
+
- generic [ref=f3e228]:
|
|
166
|
+
- generic "deepseek-v4.1-flash" [ref=f3e229]
|
|
167
|
+
- generic [ref=f3e232]: 652.0万
|
|
168
|
+
- generic [ref=f3e233]:
|
|
169
|
+
- generic "[opencode]deepseek-v4" [ref=f3e234]
|
|
170
|
+
- generic [ref=f3e237]: 467.0万
|
|
171
|
+
- generic [ref=f3e238]:
|
|
172
|
+
- generic "gemini-3.8-flash" [ref=f3e239]
|
|
173
|
+
- generic [ref=f3e242]: 278.0万
|
|
174
|
+
- generic [ref=f3e243]:
|
|
175
|
+
- generic [ref=f3e244]:
|
|
176
|
+
- generic [ref=f3e245]:
|
|
177
|
+
- generic [ref=f3e246]: 事件日志
|
|
178
|
+
- heading "最近动态" [level=3] [ref=f3e249]
|
|
179
|
+
- generic [ref=f3e250]: 10 条事件
|
|
180
|
+
- generic [ref=f3e251]:
|
|
181
|
+
- generic [ref=f3e252]:
|
|
182
|
+
- generic "ZenTao backend coupon management" [ref=f3e254]
|
|
183
|
+
- generic [ref=f3e255]: 01:18 · 15:30
|
|
184
|
+
- generic [ref=f3e256]:
|
|
185
|
+
- generic "Knowledge base weekly cleanup" [ref=f3e258]
|
|
186
|
+
- generic [ref=f3e259]: 02:00 · 15:30
|
|
187
|
+
- generic [ref=f3e260]:
|
|
188
|
+
- generic "Novel outline generation" [ref=f3e262]
|
|
189
|
+
- generic [ref=f3e263]: 02:42 · 15:30
|
|
190
|
+
- generic [ref=f3e264]:
|
|
191
|
+
- generic "ZenTao backend coupon management" [ref=f3e266]
|
|
192
|
+
- generic [ref=f3e267]: 03:24 · 15:30
|
|
193
|
+
- generic [ref=f3e268]:
|
|
194
|
+
- generic "Knowledge base weekly cleanup" [ref=f3e270]
|
|
195
|
+
- generic [ref=f3e271]: 04:06 · 15:30
|
|
196
|
+
- generic [ref=f3e272]:
|
|
197
|
+
- generic "Novel outline generation" [ref=f3e274]
|
|
198
|
+
- generic [ref=f3e275]: 04:48 · 15:30
|
|
199
|
+
- generic [ref=f3e276]:
|
|
200
|
+
- generic "ZenTao backend coupon management" [ref=f3e278]
|
|
201
|
+
- generic [ref=f3e279]: 05:30 · 15:30
|
|
202
|
+
- generic [ref=f3e280]:
|
|
203
|
+
- generic "Knowledge base weekly cleanup" [ref=f3e282]
|
|
204
|
+
- generic [ref=f3e283]: 06:12 · 15:30
|
|
205
|
+
- generic [ref=f3e284]:
|
|
206
|
+
- generic "Novel outline generation" [ref=f3e286]
|
|
207
|
+
- generic [ref=f3e287]: 06:54 · 15:30
|
|
208
|
+
- generic [ref=f3e288]:
|
|
209
|
+
- generic "ZenTao backend coupon management" [ref=f3e290]
|
|
210
|
+
- generic [ref=f3e291]: 07:36 · 15:30
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""蜂巢保全:服务无论以何种方式退出,本服务拉起的蜜蜂 CLI 一起带走。
|
|
3
|
+
|
|
4
|
+
背景(2026-09-23 用户定案):CodeBee 关闭后——无论正常退出、Ctrl+C、崩溃
|
|
5
|
+
还是被 taskkill 硬杀——在跑的 CLI/蜜蜂(codex/claude/kimi 等)必须一起杀
|
|
6
|
+
掉,否则孤儿进程把内存吃满。当天 16:50 一次服务重启就留过一只孤儿
|
|
7
|
+
claude.exe(直到管道断裂才饿死)。
|
|
8
|
+
|
|
9
|
+
Windows:Job Object(JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE)。蜜蜂 Popen 一出生
|
|
10
|
+
就 AssignProcessToJobObject 挂进蜂巢,整棵子进程树自动继承巢内身份;服务进
|
|
11
|
+
程死亡(哪怕 os._exit 跳过 atexit、被 TerminateProcess 断头)时内核关闭巢柄,
|
|
12
|
+
负责把巢内进程全部收走——这是唯一能覆盖「任意死法」的机制。
|
|
13
|
+
- 升级重启的新实例(selfupdate.relaunch)不经 run_process、不挂巢,得以
|
|
14
|
+
存活——否则就地重启等于自杀。桌面蜜蜂、explorer、cmd /k 交互终端同理豁免。
|
|
15
|
+
POSIX(含 Mac):没有 Job Object 也没有 Linux 的 prctl PDEATHSIG,靠登记 +
|
|
16
|
+
atexit 清扫兜底:run_process 的子进程本就 start_new_session(自成进程组,
|
|
17
|
+
pgid==pid),sweep 用 killpg 连树杀。正常退出 / Ctrl+C / SIGTERM/SIGHUP
|
|
18
|
+
(main.py 已把它们转成 SystemExit,atexit 照跑)全覆盖;仅 kill -9 无解
|
|
19
|
+
(任何机制都救不了,属已知边界)。
|
|
20
|
+
|
|
21
|
+
本模块绝不抛异常:挂巢失败只降级为旧行为(取消/超时收尸仍在),绝不影响
|
|
22
|
+
蜜蜂正常起跑。不依赖 pywin32,ctypes 直调 kernel32。
|
|
23
|
+
"""
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
|
|
26
|
+
import atexit
|
|
27
|
+
import collections
|
|
28
|
+
import os
|
|
29
|
+
import signal
|
|
30
|
+
import weakref
|
|
31
|
+
|
|
32
|
+
# 近期蜜蜂登记:只保最近若干条防无限增长。Windows 上 Job 是主机制、登记只是
|
|
33
|
+
# atexit 兜底的补充;POSIX 上登记是主机制(sweep 全靠它)。
|
|
34
|
+
_RECENT = collections.deque(maxlen=256)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
# ---------------------------------------------------------------- Windows 巢
|
|
38
|
+
if os.name == "nt":
|
|
39
|
+
import ctypes
|
|
40
|
+
from ctypes import wintypes
|
|
41
|
+
|
|
42
|
+
_LIMIT_KILL_ON_JOB_CLOSE = 0x00002000
|
|
43
|
+
_INFO_JOB_OBJECT_EXTENDED_LIMIT = 9
|
|
44
|
+
_STILL_ACTIVE = 259
|
|
45
|
+
|
|
46
|
+
class _IO_COUNTERS(ctypes.Structure):
|
|
47
|
+
_fields_ = [(n, ctypes.c_ulonglong) for n in (
|
|
48
|
+
"ReadOperationCount", "WriteOperationCount", "OtherOperationCount",
|
|
49
|
+
"ReadTransferCount", "WriteTransferCount", "OtherTransferCount")]
|
|
50
|
+
|
|
51
|
+
class _JOBOBJECT_BASIC_LIMIT_INFORMATION(ctypes.Structure):
|
|
52
|
+
_fields_ = [
|
|
53
|
+
("PerProcessUserTimeLimit", ctypes.c_longlong),
|
|
54
|
+
("PerJobUserTimeLimit", ctypes.c_longlong),
|
|
55
|
+
("LimitFlags", wintypes.DWORD),
|
|
56
|
+
("MinimumWorkingSetSize", ctypes.c_size_t),
|
|
57
|
+
("MaximumWorkingSetSize", ctypes.c_size_t),
|
|
58
|
+
("ActiveProcessLimit", wintypes.DWORD),
|
|
59
|
+
("Affinity", ctypes.c_size_t), # ULONG_PTR
|
|
60
|
+
("PriorityClass", wintypes.DWORD),
|
|
61
|
+
("SchedulingClass", wintypes.DWORD),
|
|
62
|
+
]
|
|
63
|
+
|
|
64
|
+
class _JOBOBJECT_EXTENDED_LIMIT_INFORMATION(ctypes.Structure):
|
|
65
|
+
_fields_ = [
|
|
66
|
+
("BasicLimitInformation", _JOBOBJECT_BASIC_LIMIT_INFORMATION),
|
|
67
|
+
("IoInfo", _IO_COUNTERS),
|
|
68
|
+
("ProcessMemoryLimit", ctypes.c_size_t),
|
|
69
|
+
("JobMemoryLimit", ctypes.c_size_t),
|
|
70
|
+
("PeakProcessMemoryUsed", ctypes.c_size_t),
|
|
71
|
+
("PeakJobMemoryUsed", ctypes.c_size_t),
|
|
72
|
+
]
|
|
73
|
+
|
|
74
|
+
_kernel32 = ctypes.windll.kernel32
|
|
75
|
+
|
|
76
|
+
class BeeNest:
|
|
77
|
+
"""一个 KILL_ON_JOB_CLOSE 巢。生产用模块单例 NEST;测试自建私有巢。"""
|
|
78
|
+
|
|
79
|
+
def __init__(self):
|
|
80
|
+
self._handle = None
|
|
81
|
+
self.assigned = 0
|
|
82
|
+
|
|
83
|
+
def _ensure_job(self):
|
|
84
|
+
if self._handle:
|
|
85
|
+
return self._handle
|
|
86
|
+
h = _kernel32.CreateJobObjectW(None, None)
|
|
87
|
+
if not h:
|
|
88
|
+
return None
|
|
89
|
+
info = _JOBOBJECT_EXTENDED_LIMIT_INFORMATION()
|
|
90
|
+
info.BasicLimitInformation.LimitFlags = _LIMIT_KILL_ON_JOB_CLOSE
|
|
91
|
+
if not _kernel32.SetInformationJobObject(
|
|
92
|
+
h, _INFO_JOB_OBJECT_EXTENDED_LIMIT,
|
|
93
|
+
ctypes.byref(info), ctypes.sizeof(info)):
|
|
94
|
+
_kernel32.CloseHandle(h)
|
|
95
|
+
return None
|
|
96
|
+
self._handle = h
|
|
97
|
+
return h
|
|
98
|
+
|
|
99
|
+
def adopt(self, proc):
|
|
100
|
+
h = self._ensure_job()
|
|
101
|
+
if not h:
|
|
102
|
+
return
|
|
103
|
+
handle = getattr(proc, "_handle", None)
|
|
104
|
+
if not handle:
|
|
105
|
+
return
|
|
106
|
+
# 子进程树(cmd /c 垫片 → claude.exe → 其孙)自动继承巢内身份,
|
|
107
|
+
# 只需挂直系子进程。Win8+ 支持嵌套 Job,外层有别的 Job 也不碍事。
|
|
108
|
+
if _kernel32.AssignProcessToJobObject(h, int(handle)):
|
|
109
|
+
self.assigned += 1
|
|
110
|
+
|
|
111
|
+
def close(self):
|
|
112
|
+
"""主动关巢:巢内进程全部被内核收走(等价于服务进程死亡)。"""
|
|
113
|
+
if self._handle:
|
|
114
|
+
try:
|
|
115
|
+
_kernel32.CloseHandle(self._handle)
|
|
116
|
+
except Exception:
|
|
117
|
+
pass
|
|
118
|
+
self._handle = None
|
|
119
|
+
|
|
120
|
+
else:
|
|
121
|
+
class BeeNest:
|
|
122
|
+
"""POSIX 占位巢:杀全靠 sweep()(登记 + killpg),close 无事可做。"""
|
|
123
|
+
|
|
124
|
+
def __init__(self):
|
|
125
|
+
self.assigned = 0
|
|
126
|
+
|
|
127
|
+
def adopt(self, proc):
|
|
128
|
+
self.assigned += 1
|
|
129
|
+
|
|
130
|
+
def close(self):
|
|
131
|
+
pass
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
NEST = BeeNest()
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def adopt(proc):
|
|
138
|
+
"""把蜜蜂进程挂巢:服务死则蜜蜂亡。绝不抛异常、绝不拖慢起跑。"""
|
|
139
|
+
if proc is None:
|
|
140
|
+
return
|
|
141
|
+
try:
|
|
142
|
+
_RECENT.append((proc.pid, weakref.ref(proc)))
|
|
143
|
+
NEST.adopt(proc)
|
|
144
|
+
except Exception:
|
|
145
|
+
pass
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def sweep():
|
|
149
|
+
"""退出清扫:登记在册且仍存活的蜜蜂连树杀。
|
|
150
|
+
|
|
151
|
+
POSIX 主机制(atexit 在正常退出/Ctrl+C/SIGTERM→SystemExit 时都会跑);
|
|
152
|
+
Windows 只是 Job 的兜底(Job 建不出来或句柄异常时仍能杀到登记的直系
|
|
153
|
+
进程,孙进程交给既有 taskkill /T 收尸路径)。Windows 端拿不到 Popen
|
|
154
|
+
存活证据的条目不盲杀——防 PID 复用误伤无辜进程(反正有 Job 兜底)。
|
|
155
|
+
"""
|
|
156
|
+
while _RECENT:
|
|
157
|
+
pid, ref = _RECENT.popleft()
|
|
158
|
+
proc = ref() if ref else None
|
|
159
|
+
if proc is not None:
|
|
160
|
+
try:
|
|
161
|
+
if proc.poll() is not None:
|
|
162
|
+
continue # 已退出,跳过
|
|
163
|
+
except Exception:
|
|
164
|
+
pass
|
|
165
|
+
if os.name == "nt":
|
|
166
|
+
if proc is None:
|
|
167
|
+
continue
|
|
168
|
+
try:
|
|
169
|
+
os.kill(pid, signal.SIGTERM) # Windows 语义 = TerminateProcess
|
|
170
|
+
except Exception:
|
|
171
|
+
pass
|
|
172
|
+
else:
|
|
173
|
+
# run_process 子进程 start_new_session:pgid==pid,killpg 连树杀
|
|
174
|
+
try:
|
|
175
|
+
os.killpg(pid, signal.SIGKILL)
|
|
176
|
+
except Exception:
|
|
177
|
+
try:
|
|
178
|
+
os.kill(pid, signal.SIGKILL)
|
|
179
|
+
except Exception:
|
|
180
|
+
pass
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
atexit.register(sweep)
|