codebee 0.1.65 → 0.1.67
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 +532 -513
- package/LICENSE +21 -21
- package/README.md +494 -487
- package/app/core/acceptance.py +100 -0
- package/app/core/aiflavor.py +197 -197
- package/app/core/artifacts.py +148 -148
- package/app/core/assets.py +110 -0
- package/app/core/attachments.py +623 -532
- package/app/core/automation.py +758 -758
- package/app/core/backup.py +470 -470
- package/app/core/beekeeper.py +183 -183
- package/app/core/board.py +209 -209
- package/app/core/bookmeta.py +930 -759
- package/app/core/bookmeta_catalog.py +180 -180
- package/app/core/branching.py +137 -137
- package/app/core/builtin_agent.py +1234 -1191
- package/app/core/capability.py +144 -144
- package/app/core/catalog.py +23 -24
- package/app/core/chaptersafe.py +32 -32
- package/app/core/cleanup.py +303 -303
- package/app/core/compaction.py +201 -186
- package/app/core/covergen.py +356 -356
- package/app/core/defectretro.py +43 -0
- package/app/core/diagnostics.py +114 -114
- package/app/core/dispatch.py +173 -173
- package/app/core/dispatch_log.py +113 -113
- package/app/core/env_scrub.py +85 -85
- package/app/core/error_codes.py +220 -65
- package/app/core/errorlog.py +137 -137
- package/app/core/evaluation.py +174 -0
- package/app/core/failure_notify.py +290 -0
- package/app/core/flows.py +401 -355
- package/app/core/goal_service.py +167 -167
- package/app/core/health.py +374 -342
- package/app/core/history.py +38 -38
- package/app/core/hooks.py +162 -156
- package/app/core/jobs.py +1050 -1022
- package/app/core/knowledge.py +56 -5
- package/app/core/manager.py +2122 -1996
- package/app/core/market.py +362 -362
- package/app/core/market_remote.py +190 -92
- package/app/core/mocks.py +64 -64
- package/app/core/modelhub.py +3546 -3332
- package/app/core/notify.py +106 -106
- package/app/core/operations.py +228 -0
- package/app/core/paihang.py +138 -109
- package/app/core/paths.py +2 -2
- package/app/core/pipeline.py +4808 -4494
- package/app/core/planner.py +37 -32
- package/app/core/portguard.py +111 -111
- package/app/core/preview.py +293 -293
- package/app/core/publish/__init__.py +7 -7
- package/app/core/publish/auto.py +367 -367
- package/app/core/publish/browser.py +539 -533
- package/app/core/publish/fanqie.py +159 -128
- package/app/core/publish/flow.py +440 -406
- package/app/core/publish/flows-fanqie-calibrated.json +17 -9
- package/app/core/publish/flows-qimao-calibrated.json +6 -2
- package/app/core/publish/ledger.py +203 -198
- package/app/core/publish/manager.py +692 -590
- package/app/core/publish/qimao.py +141 -141
- package/app/core/publish/ws.py +139 -139
- package/app/core/redact.py +38 -38
- package/app/core/repeat_guard.py +129 -124
- package/app/core/revisions.py +51 -0
- package/app/core/router.py +119 -81
- package/app/core/runner.py +2065 -2042
- package/app/core/selfupdate.py +384 -384
- package/app/core/session_log.py +161 -161
- package/app/core/sessions.py +312 -312
- package/app/core/settings.py +149 -149
- package/app/core/settings_schema.py +262 -262
- package/app/core/share_page.py +114 -114
- package/app/core/skill_scan.py +114 -106
- package/app/core/skillpacks/fanqie-novel.md +80 -80
- package/app/core/skillpacks/market/character-bible.md +66 -66
- package/app/core/skillpacks/market/code-risk-checklist.md +58 -58
- package/app/core/skillpacks/market/git-workflow.md +57 -57
- package/app/core/skillpacks/market/release-notes.md +72 -72
- package/app/core/skillpacks/market/weekly-report.md +71 -71
- package/app/core/skillpacks/market/worldview-consistency.md +70 -70
- package/app/core/skills.py +315 -73
- package/app/core/step_runner.py +132 -132
- package/app/core/store.py +230 -11
- package/app/core/task_compile.py +199 -199
- package/app/core/telemetry.py +292 -292
- package/app/core/tlsctx.py +64 -64
- package/app/core/token_meter.py +147 -147
- package/app/core/upstream.py +41 -0
- package/app/core/usage.py +114 -3
- package/app/core/volumes.py +389 -355
- package/app/core/wxdigest.py +858 -858
- package/app/core/zentao.py +2465 -2447
- package/app/main.py +2957 -2832
- package/app/pick_dialog.py +110 -110
- package/app/ui/app.js +14384 -13977
- package/app/ui/artdiff.js +74 -0
- package/app/ui/board.css +20 -41
- package/app/ui/board.html +162 -162
- package/app/ui/board.js +305 -305
- package/app/ui/i18n.js +2766 -2711
- package/app/ui/icons/bee.svg +79 -79
- package/app/ui/index.html +7 -1
- package/app/ui/manifest.json +16 -16
- package/app/ui/qrcode.js +2297 -2297
- package/app/ui/style.css +6179 -6125
- package/bin/tutti.js +147 -147
- package/package.json +46 -41
- package/tools/wx_reader.py +261 -261
- package/app/.playwright-cli/console-2026-09-23T08-26-03-635Z.log +0 -88
- package/app/.playwright-cli/page-2026-09-23T08-26-03-845Z.yml +0 -126
- 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 +0 -210
- 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/knowledge.py
CHANGED
|
@@ -29,7 +29,7 @@ import threading
|
|
|
29
29
|
import time
|
|
30
30
|
from pathlib import Path
|
|
31
31
|
|
|
32
|
-
from . import paths, skills
|
|
32
|
+
from . import paths, revisions, skills
|
|
33
33
|
|
|
34
34
|
_LOCK = threading.RLock()
|
|
35
35
|
_FILE = paths.DATA_DIR / "knowledge.json"
|
|
@@ -82,6 +82,29 @@ def list_entries(scope=None, status=None, tag=None, only_enabled=False):
|
|
|
82
82
|
return items
|
|
83
83
|
|
|
84
84
|
|
|
85
|
+
def revision_for_task(task) -> dict:
|
|
86
|
+
"""Return approved knowledge references selected by task scope."""
|
|
87
|
+
scope = str((task or {}).get("type") or "*")
|
|
88
|
+
entries = list_entries(scope=scope, status="approved", only_enabled=True)
|
|
89
|
+
refs = []
|
|
90
|
+
for entry in entries:
|
|
91
|
+
body = entry.get("body") or ""
|
|
92
|
+
digest = revisions.content_sha256(body)
|
|
93
|
+
stored_digest = str(entry.get("content_sha256") or "")
|
|
94
|
+
drift = bool(stored_digest and stored_digest != digest)
|
|
95
|
+
refs.append({"id": entry.get("id") or "",
|
|
96
|
+
"revision_id": (entry.get("revision_id")
|
|
97
|
+
if stored_digest == digest else
|
|
98
|
+
revisions.revision_id("kbrev", digest)) or
|
|
99
|
+
revisions.revision_id("kbrev", digest),
|
|
100
|
+
"content_sha256": digest,
|
|
101
|
+
"revision_drift": drift})
|
|
102
|
+
payload = {"scope": scope, "entries": refs}
|
|
103
|
+
digest = revisions.stable_digest(payload)
|
|
104
|
+
return {"revision_id": revisions.revision_id("knowledge", digest),
|
|
105
|
+
"content_sha256": digest, "scope": scope, "entries": refs}
|
|
106
|
+
|
|
107
|
+
|
|
85
108
|
def _title_sim(a, b):
|
|
86
109
|
"""标题近似度:字符 bigram 的包含度(交集 / 较短者,中文友好零分词)。
|
|
87
110
|
用包含度而非 Jaccard:「X」vs「X 指南」的较短者完全被包含 →1.0,
|
|
@@ -131,13 +154,25 @@ def upsert_entry(scope, title, body, tags=None, source="", source_file="",
|
|
|
131
154
|
if hit is not None:
|
|
132
155
|
it = hit
|
|
133
156
|
it["seen"] = int(it.get("seen") or 1) + 1
|
|
157
|
+
old_body = str(it.get("body") or "")
|
|
158
|
+
old_rev = it.get("revision_id") or ""
|
|
159
|
+
new_rev = revisions.make_revision("kbrev", body, source=source)
|
|
134
160
|
if status == "approved" or it.get("status") != "approved":
|
|
161
|
+
if old_body and old_body != body:
|
|
162
|
+
it.setdefault("revisions", []).append(
|
|
163
|
+
revisions.revision_record(
|
|
164
|
+
"kbrev", old_body, source=it.get("source") or "",
|
|
165
|
+
extra={"body": old_body, "revision_id": old_rev or
|
|
166
|
+
revisions.revision_id("kbrev", revisions.content_sha256(old_body))}))
|
|
167
|
+
it["revisions"] = it["revisions"][-5:]
|
|
135
168
|
it["body"] = body
|
|
169
|
+
it.update({k: new_rev[k] for k in ("revision_id", "content_sha256")})
|
|
136
170
|
if status == "approved":
|
|
137
171
|
it["status"] = "approved"
|
|
138
172
|
else:
|
|
139
173
|
it.setdefault("revisions", []).append(
|
|
140
|
-
|
|
174
|
+
revisions.revision_record("kbrev", body, source=source,
|
|
175
|
+
extra={"body": body}))
|
|
141
176
|
it["revisions"] = it["revisions"][-5:] # 最多留 5 条修订候选
|
|
142
177
|
for tg in tags:
|
|
143
178
|
if tg not in (it.get("tags") or []):
|
|
@@ -154,6 +189,7 @@ def upsert_entry(scope, title, body, tags=None, source="", source_file="",
|
|
|
154
189
|
it["updated_at"] = _now()
|
|
155
190
|
_save(data)
|
|
156
191
|
return it
|
|
192
|
+
rev = revisions.make_revision("kbrev", body, source=source)
|
|
157
193
|
it = {"id": kid, "scope": scope, "title": title, "body": body,
|
|
158
194
|
"tags": tags, "status": status, "enabled": True,
|
|
159
195
|
"source": source, "source_file": source_file,
|
|
@@ -161,6 +197,7 @@ def upsert_entry(scope, title, body, tags=None, source="", source_file="",
|
|
|
161
197
|
"confidence": confidence or "medium",
|
|
162
198
|
"revisions": [], "hits": 0, "seen": 1,
|
|
163
199
|
"created_at": _now(), "updated_at": _now(), "kind": "knowledge"}
|
|
200
|
+
it.update({k: rev[k] for k in ("revision_id", "content_sha256")})
|
|
164
201
|
items.append(it)
|
|
165
202
|
_save(data)
|
|
166
203
|
return it
|
|
@@ -197,7 +234,17 @@ def entry_op(entry_id, op, fields=None):
|
|
|
197
234
|
if str(f.get("title") or "").strip():
|
|
198
235
|
hit["title"] = str(f["title"]).strip()[:80]
|
|
199
236
|
if str(f.get("body") or "").strip():
|
|
200
|
-
|
|
237
|
+
new_body = str(f["body"]).strip()[:1500]
|
|
238
|
+
old_body = str(hit.get("body") or "")
|
|
239
|
+
if old_body != new_body:
|
|
240
|
+
hit.setdefault("revisions", []).append(
|
|
241
|
+
revisions.revision_record(
|
|
242
|
+
"kbrev", old_body, source=hit.get("source") or "",
|
|
243
|
+
extra={"body": old_body}))
|
|
244
|
+
hit["revisions"] = hit["revisions"][-5:]
|
|
245
|
+
hit["body"] = new_body
|
|
246
|
+
hit.update({k: revisions.make_revision("kbrev", new_body)[k]
|
|
247
|
+
for k in ("revision_id", "content_sha256")})
|
|
201
248
|
if "tags" in f:
|
|
202
249
|
hit["tags"] = [str(t).strip()[:20]
|
|
203
250
|
for t in (f.get("tags") or []) if str(t).strip()][:8]
|
|
@@ -238,8 +285,12 @@ def block_for(task):
|
|
|
238
285
|
| skills._text_bigrams(x.get("body"))
|
|
239
286
|
| set(x.get("tags") or []))
|
|
240
287
|
# 过期降权(inkos 检索保留来源/位置的启发):同等相关性下,
|
|
241
|
-
#
|
|
242
|
-
|
|
288
|
+
# 可能过期的事实排在新鲜事实之后——旧知识不该压过新知识。
|
|
289
|
+
# 命中热度平级决胜(教训库 karma 的轻量同构):_bump_hits 记的
|
|
290
|
+
# 注入命中数此前只进不出;相关性同档时高频命中条目优先——
|
|
291
|
+
# 被反复召回的知识已被任务面验证过可用性,压过从未被选中的
|
|
292
|
+
return (-len(probe & grams), -(int(x.get("hits") or 0)),
|
|
293
|
+
1 if _is_stale(x.get("as_of")) else 0,
|
|
243
294
|
x.get("id") or "")
|
|
244
295
|
entries = sorted(entries, key=rank)
|
|
245
296
|
else:
|