codebee 0.1.95 → 0.1.96

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.
Files changed (138) hide show
  1. package/CHANGELOG.md +725 -720
  2. package/LICENSE +21 -21
  3. package/README.md +515 -509
  4. package/app/core/acceptance.py +100 -100
  5. package/app/core/agent_context.py +100 -0
  6. package/app/core/aiflavor.py +197 -197
  7. package/app/core/analytics.py +38 -38
  8. package/app/core/artifacts.py +148 -148
  9. package/app/core/assets.py +110 -110
  10. package/app/core/attachments.py +623 -623
  11. package/app/core/audit.py +30 -30
  12. package/app/core/backup.py +470 -470
  13. package/app/core/beekeeper.py +183 -183
  14. package/app/core/benchstore.py +102 -95
  15. package/app/core/board.py +209 -209
  16. package/app/core/bookmeta.py +1036 -1036
  17. package/app/core/bookmeta_catalog.py +180 -180
  18. package/app/core/branching.py +137 -137
  19. package/app/core/builtin_agent.py +1680 -1680
  20. package/app/core/capability.py +144 -144
  21. package/app/core/chaptersafe.py +32 -32
  22. package/app/core/checkpoints.py +143 -0
  23. package/app/core/cleanup.py +303 -303
  24. package/app/core/compaction.py +201 -201
  25. package/app/core/contracts.py +255 -255
  26. package/app/core/covergen.py +356 -356
  27. package/app/core/defectretro.py +43 -43
  28. package/app/core/diagnostics.py +114 -114
  29. package/app/core/dispatch.py +198 -191
  30. package/app/core/dispatch_log.py +128 -128
  31. package/app/core/env_scrub.py +85 -85
  32. package/app/core/errorlog.py +137 -137
  33. package/app/core/eval_matrix.py +82 -0
  34. package/app/core/evalbench.py +184 -91
  35. package/app/core/evaluation.py +174 -174
  36. package/app/core/failure_notify.py +290 -290
  37. package/app/core/flow_graph.py +33 -0
  38. package/app/core/goal_service.py +167 -167
  39. package/app/core/health.py +389 -389
  40. package/app/core/history.py +38 -38
  41. package/app/core/hooks.py +162 -162
  42. package/app/core/jobs.py +25 -4
  43. package/app/core/knowledge_pipeline.py +86 -0
  44. package/app/core/manager.py +2232 -2232
  45. package/app/core/mocks.py +64 -64
  46. package/app/core/notify.py +201 -201
  47. package/app/core/novel_quality.py +181 -189
  48. package/app/core/openapi.py +177 -154
  49. package/app/core/operations.py +228 -228
  50. package/app/core/paihang.py +145 -145
  51. package/app/core/pipeline.py +43 -19
  52. package/app/core/planner.py +17 -11
  53. package/app/core/policy.py +52 -0
  54. package/app/core/portguard.py +111 -111
  55. package/app/core/presence.py +77 -77
  56. package/app/core/preview.py +293 -293
  57. package/app/core/prompt_guard.py +78 -78
  58. package/app/core/publish/__init__.py +7 -7
  59. package/app/core/publish/auto.py +26 -3
  60. package/app/core/publish/browser.py +655 -655
  61. package/app/core/publish/chaprows.py +138 -0
  62. package/app/core/publish/fanqie.py +210 -165
  63. package/app/core/publish/flow.py +753 -640
  64. package/app/core/publish/flows-fanqie-calibrated.json +349 -336
  65. package/app/core/publish/ledger.py +13 -1
  66. package/app/core/publish/manager.py +1150 -1118
  67. package/app/core/publish/qimao.py +176 -176
  68. package/app/core/publish/volumes.py +108 -0
  69. package/app/core/publish/ws.py +139 -139
  70. package/app/core/quality_gate.py +194 -194
  71. package/app/core/redact.py +38 -38
  72. package/app/core/repeat_guard.py +129 -129
  73. package/app/core/retrieval.py +137 -137
  74. package/app/core/router.py +398 -398
  75. package/app/core/runner.py +2238 -2238
  76. package/app/core/selfupdate.py +384 -384
  77. package/app/core/session_log.py +161 -161
  78. package/app/core/sessions.py +312 -312
  79. package/app/core/settings.py +20 -0
  80. package/app/core/settings_schema.py +270 -270
  81. package/app/core/share_page.py +114 -114
  82. package/app/core/skill_scan.py +139 -139
  83. package/app/core/skillpacks/fanqie-novel.md +8 -6
  84. package/app/core/skillpacks/market/character-bible.md +66 -66
  85. package/app/core/skillpacks/market/code-risk-checklist.md +58 -58
  86. package/app/core/skillpacks/market/git-workflow.md +57 -57
  87. package/app/core/skillpacks/market/release-notes.md +72 -72
  88. package/app/core/skillpacks/market/weekly-report.md +71 -71
  89. package/app/core/skillpacks/market/worldview-consistency.md +70 -70
  90. package/app/core/skillpacks/qimao-signing.md +14 -11
  91. package/app/core/skills.py +32 -21
  92. package/app/core/step_runner.py +132 -132
  93. package/app/core/store.py +9 -0
  94. package/app/core/story_tracking.py +275 -275
  95. package/app/core/task_compile.py +199 -199
  96. package/app/core/telemetry.py +292 -292
  97. package/app/core/tlsctx.py +64 -64
  98. package/app/core/token_meter.py +147 -147
  99. package/app/core/tracing.py +207 -144
  100. package/app/core/upstream.py +41 -41
  101. package/app/core/usage.py +1038 -1038
  102. package/app/core/volumes.py +389 -389
  103. package/app/core/webhooks.py +89 -0
  104. package/app/core/wxdigest.py +858 -858
  105. package/app/core/zentao.py +2692 -2692
  106. package/app/main.py +104 -9
  107. package/app/mcp_server.py +244 -244
  108. package/app/pick_dialog.py +110 -110
  109. package/app/ui/app.js +286 -18
  110. package/app/ui/artdiff.js +74 -74
  111. package/app/ui/assets/community-qr.png +0 -0
  112. package/app/ui/assets/donate-alipay.jpg +0 -0
  113. package/app/ui/assets/donate-qr.jpg +0 -0
  114. package/app/ui/board.html +162 -162
  115. package/app/ui/board.js +305 -305
  116. package/app/ui/i18n.js +33 -0
  117. package/app/ui/icons/bee.svg +79 -79
  118. package/app/ui/index.html +32 -3
  119. package/app/ui/manifest.json +16 -16
  120. package/app/ui/qrcode.js +2297 -2297
  121. package/app/ui/style.css +196 -2
  122. package/bin/tutti.js +147 -147
  123. package/package.json +48 -48
  124. package/tools/wx_reader.py +261 -261
  125. package/app/.playwright-cli/console-2026-09-23T08-26-03-635Z.log +0 -88
  126. package/app/.playwright-cli/page-2026-09-23T08-26-03-845Z.yml +0 -126
  127. package/app/.playwright-cli/page-2026-09-23T08-29-44-203Z.png +0 -0
  128. package/app/.playwright-cli/page-2026-09-23T08-35-42-046Z.yml +0 -210
  129. package/app/.playwright-cli/page-2026-09-23T08-36-52-858Z.png +0 -0
  130. package/app/.playwright-cli/page-2026-09-23T08-37-33-938Z.png +0 -0
  131. package/app/.playwright-cli/run-detail-after.png +0 -0
  132. package/app/output/_createbook_body.json +0 -1
  133. package/app/output/_probe_fq_click.py +0 -50
  134. package/app/output/_probe_fq_form.py +0 -42
  135. package/app/output/_probe_fq_modal.py +0 -55
  136. package/app/output/_probe_fq_points.py +0 -71
  137. package/app/output/_probe_fq_submit.py +0 -34
  138. package/app/output/_probe_fq_watch.py +0 -62
@@ -1,139 +1,139 @@
1
- # -*- coding: utf-8 -*-
2
- """最小 WebSocket 客户端(RFC 6455 子集)——CDP 驱动专用。
3
-
4
- 只实现客户端角色:HTTP Upgrade 握手 → 文本帧收发。CDP 的用法非常受限,
5
- 所以刻意不做完整协议:
6
- - 客户端只发文本帧(JSON 命令),服务端回文本帧(响应/事件)+ 偶尔 ping;
7
- - 截图等大响应可能分片(continuation 帧),必须重组;
8
- - 不协商 permessage-deflate 等扩展,服务端帧按规范不带掩码(仍兼容读取)。
9
-
10
- 不引第三方 websocket 库:32 位 Python + npm 分发是零依赖策略,
11
- 标准库 socket 手写两百行即可覆盖上述用法,行为对着真 Edge 验证。
12
- """
13
- from __future__ import annotations
14
-
15
- import base64
16
- import os
17
- import socket
18
- import struct
19
-
20
- OP_CONT, OP_TEXT, OP_BINARY, OP_CLOSE, OP_PING, OP_PONG = 0x0, 0x1, 0x2, 0x8, 0x9, 0xA
21
-
22
-
23
- class WebSocketError(Exception):
24
- """连接层错误(握手失败/对端关闭/帧损坏)。业务超时抛 socket.timeout。"""
25
-
26
-
27
- class MiniWS:
28
- """一次性连接:不做重连(CDP 页面会话由上层 browser.py 决定重开)。"""
29
-
30
- def __init__(self, host, port, path, timeout=30.0):
31
- self._timeout = timeout
32
- self._sock = socket.create_connection((host, int(port)), timeout=timeout)
33
- self._buf = b""
34
- self._handshake(host, int(port), path)
35
-
36
- # ------------------------------------------------------------ 握手
37
- def _handshake(self, host, port, path):
38
- key = base64.b64encode(os.urandom(16)).decode("ascii")
39
- req = ("GET %s HTTP/1.1\r\nHost: %s:%d\r\nUpgrade: websocket\r\n"
40
- "Connection: Upgrade\r\nSec-WebSocket-Key: %s\r\n"
41
- "Sec-WebSocket-Version: 13\r\n\r\n") % (path, host, port, key)
42
- self._sock.sendall(req.encode("ascii"))
43
- while b"\r\n\r\n" not in self._buf:
44
- chunk = self._sock.recv(4096)
45
- if not chunk:
46
- raise WebSocketError("握手失败:连接被关闭")
47
- self._buf += chunk
48
- head, _, self._buf = self._buf.partition(b"\r\n\r\n")
49
- status = head.split(b"\r\n", 1)[0].decode("latin-1", "replace")
50
- if " 101 " not in status and not status.endswith(" 101"):
51
- raise WebSocketError("握手失败:%s" % status[:120])
52
-
53
- # ------------------------------------------------------------ 发送
54
- def _send_frame(self, opcode, payload):
55
- mask = os.urandom(4) # 客户端→服务端必须掩码
56
- n = len(payload)
57
- header = bytearray([0x80 | opcode]) # FIN + opcode
58
- if n < 126:
59
- header.append(0x80 | n)
60
- elif n < 65536:
61
- header.append(0x80 | 126)
62
- header += struct.pack(">H", n)
63
- else:
64
- header.append(0x80 | 127)
65
- header += struct.pack(">Q", n)
66
- header += mask
67
- masked = bytes(b ^ mask[i % 4] for i, b in enumerate(payload))
68
- self._sock.sendall(bytes(header) + masked)
69
-
70
- def send_text(self, text):
71
- self._send_frame(OP_TEXT, text.encode("utf-8"))
72
-
73
- # ------------------------------------------------------------ 接收
74
- def _recv_exact(self, n):
75
- while len(self._buf) < n:
76
- chunk = self._sock.recv(max(4096, n - len(self._buf)))
77
- if not chunk:
78
- raise WebSocketError("连接被关闭")
79
- self._buf += chunk
80
- out, self._buf = self._buf[:n], self._buf[n:]
81
- return out
82
-
83
- def recv_message(self, timeout=None):
84
- """收一条完整消息:自动应答 ping、重组分片。
85
-
86
- 返回 str(文本帧)或 bytes(二进制帧)。超时抛 socket.timeout,
87
- 对端关闭抛 WebSocketError。"""
88
- if timeout is not None:
89
- self._sock.settimeout(timeout)
90
- elif self._timeout:
91
- self._sock.settimeout(self._timeout)
92
- opcode_msg = None
93
- payload = bytearray()
94
- while True:
95
- b1, b2 = self._recv_exact(2)
96
- fin, opcode, masked = b1 & 0x80, b1 & 0x0F, b2 & 0x80
97
- n = b2 & 0x7F
98
- if n == 126:
99
- (n,) = struct.unpack(">H", self._recv_exact(2))
100
- elif n == 127:
101
- (n,) = struct.unpack(">Q", self._recv_exact(8))
102
- data = self._recv_exact(n)
103
- if masked:
104
- mkey = self._recv_exact(4)
105
- data = bytes(b ^ mkey[i % 4] for i, b in enumerate(data))
106
- if opcode == OP_CLOSE:
107
- raise WebSocketError("对端发送关闭帧")
108
- if opcode == OP_PING:
109
- self._send_frame(OP_PONG, data)
110
- continue
111
- if opcode == OP_PONG:
112
- continue
113
- if opcode in (OP_TEXT, OP_BINARY):
114
- opcode_msg, payload = opcode, bytearray(data)
115
- elif opcode == OP_CONT:
116
- if opcode_msg is None:
117
- raise WebSocketError("收到无起始帧的续帧")
118
- payload += data
119
- else:
120
- raise WebSocketError("未知 opcode:%d" % opcode)
121
- if fin:
122
- return bytes(payload) if opcode_msg == OP_BINARY else \
123
- payload.decode("utf-8", "replace")
124
-
125
- def close(self):
126
- try:
127
- self._send_frame(OP_CLOSE, b"")
128
- except Exception:
129
- pass
130
- try:
131
- self._sock.close()
132
- except Exception:
133
- pass
134
-
135
- def __enter__(self):
136
- return self
137
-
138
- def __exit__(self, *exc):
139
- self.close()
1
+ # -*- coding: utf-8 -*-
2
+ """最小 WebSocket 客户端(RFC 6455 子集)——CDP 驱动专用。
3
+
4
+ 只实现客户端角色:HTTP Upgrade 握手 → 文本帧收发。CDP 的用法非常受限,
5
+ 所以刻意不做完整协议:
6
+ - 客户端只发文本帧(JSON 命令),服务端回文本帧(响应/事件)+ 偶尔 ping;
7
+ - 截图等大响应可能分片(continuation 帧),必须重组;
8
+ - 不协商 permessage-deflate 等扩展,服务端帧按规范不带掩码(仍兼容读取)。
9
+
10
+ 不引第三方 websocket 库:32 位 Python + npm 分发是零依赖策略,
11
+ 标准库 socket 手写两百行即可覆盖上述用法,行为对着真 Edge 验证。
12
+ """
13
+ from __future__ import annotations
14
+
15
+ import base64
16
+ import os
17
+ import socket
18
+ import struct
19
+
20
+ OP_CONT, OP_TEXT, OP_BINARY, OP_CLOSE, OP_PING, OP_PONG = 0x0, 0x1, 0x2, 0x8, 0x9, 0xA
21
+
22
+
23
+ class WebSocketError(Exception):
24
+ """连接层错误(握手失败/对端关闭/帧损坏)。业务超时抛 socket.timeout。"""
25
+
26
+
27
+ class MiniWS:
28
+ """一次性连接:不做重连(CDP 页面会话由上层 browser.py 决定重开)。"""
29
+
30
+ def __init__(self, host, port, path, timeout=30.0):
31
+ self._timeout = timeout
32
+ self._sock = socket.create_connection((host, int(port)), timeout=timeout)
33
+ self._buf = b""
34
+ self._handshake(host, int(port), path)
35
+
36
+ # ------------------------------------------------------------ 握手
37
+ def _handshake(self, host, port, path):
38
+ key = base64.b64encode(os.urandom(16)).decode("ascii")
39
+ req = ("GET %s HTTP/1.1\r\nHost: %s:%d\r\nUpgrade: websocket\r\n"
40
+ "Connection: Upgrade\r\nSec-WebSocket-Key: %s\r\n"
41
+ "Sec-WebSocket-Version: 13\r\n\r\n") % (path, host, port, key)
42
+ self._sock.sendall(req.encode("ascii"))
43
+ while b"\r\n\r\n" not in self._buf:
44
+ chunk = self._sock.recv(4096)
45
+ if not chunk:
46
+ raise WebSocketError("握手失败:连接被关闭")
47
+ self._buf += chunk
48
+ head, _, self._buf = self._buf.partition(b"\r\n\r\n")
49
+ status = head.split(b"\r\n", 1)[0].decode("latin-1", "replace")
50
+ if " 101 " not in status and not status.endswith(" 101"):
51
+ raise WebSocketError("握手失败:%s" % status[:120])
52
+
53
+ # ------------------------------------------------------------ 发送
54
+ def _send_frame(self, opcode, payload):
55
+ mask = os.urandom(4) # 客户端→服务端必须掩码
56
+ n = len(payload)
57
+ header = bytearray([0x80 | opcode]) # FIN + opcode
58
+ if n < 126:
59
+ header.append(0x80 | n)
60
+ elif n < 65536:
61
+ header.append(0x80 | 126)
62
+ header += struct.pack(">H", n)
63
+ else:
64
+ header.append(0x80 | 127)
65
+ header += struct.pack(">Q", n)
66
+ header += mask
67
+ masked = bytes(b ^ mask[i % 4] for i, b in enumerate(payload))
68
+ self._sock.sendall(bytes(header) + masked)
69
+
70
+ def send_text(self, text):
71
+ self._send_frame(OP_TEXT, text.encode("utf-8"))
72
+
73
+ # ------------------------------------------------------------ 接收
74
+ def _recv_exact(self, n):
75
+ while len(self._buf) < n:
76
+ chunk = self._sock.recv(max(4096, n - len(self._buf)))
77
+ if not chunk:
78
+ raise WebSocketError("连接被关闭")
79
+ self._buf += chunk
80
+ out, self._buf = self._buf[:n], self._buf[n:]
81
+ return out
82
+
83
+ def recv_message(self, timeout=None):
84
+ """收一条完整消息:自动应答 ping、重组分片。
85
+
86
+ 返回 str(文本帧)或 bytes(二进制帧)。超时抛 socket.timeout,
87
+ 对端关闭抛 WebSocketError。"""
88
+ if timeout is not None:
89
+ self._sock.settimeout(timeout)
90
+ elif self._timeout:
91
+ self._sock.settimeout(self._timeout)
92
+ opcode_msg = None
93
+ payload = bytearray()
94
+ while True:
95
+ b1, b2 = self._recv_exact(2)
96
+ fin, opcode, masked = b1 & 0x80, b1 & 0x0F, b2 & 0x80
97
+ n = b2 & 0x7F
98
+ if n == 126:
99
+ (n,) = struct.unpack(">H", self._recv_exact(2))
100
+ elif n == 127:
101
+ (n,) = struct.unpack(">Q", self._recv_exact(8))
102
+ data = self._recv_exact(n)
103
+ if masked:
104
+ mkey = self._recv_exact(4)
105
+ data = bytes(b ^ mkey[i % 4] for i, b in enumerate(data))
106
+ if opcode == OP_CLOSE:
107
+ raise WebSocketError("对端发送关闭帧")
108
+ if opcode == OP_PING:
109
+ self._send_frame(OP_PONG, data)
110
+ continue
111
+ if opcode == OP_PONG:
112
+ continue
113
+ if opcode in (OP_TEXT, OP_BINARY):
114
+ opcode_msg, payload = opcode, bytearray(data)
115
+ elif opcode == OP_CONT:
116
+ if opcode_msg is None:
117
+ raise WebSocketError("收到无起始帧的续帧")
118
+ payload += data
119
+ else:
120
+ raise WebSocketError("未知 opcode:%d" % opcode)
121
+ if fin:
122
+ return bytes(payload) if opcode_msg == OP_BINARY else \
123
+ payload.decode("utf-8", "replace")
124
+
125
+ def close(self):
126
+ try:
127
+ self._send_frame(OP_CLOSE, b"")
128
+ except Exception:
129
+ pass
130
+ try:
131
+ self._sock.close()
132
+ except Exception:
133
+ pass
134
+
135
+ def __enter__(self):
136
+ return self
137
+
138
+ def __exit__(self, *exc):
139
+ self.close()