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,137 +1,137 @@
1
- # -*- coding: utf-8 -*-
2
- """多线剧情推演(inkos 借鉴 2026-09-23):写章前一次调用生成 2-3 条分支
3
- 节拍计划,自带推荐择优,选中分支注入本章 BEATS;全部分支追加审计文件
4
- .codebee/branch-plans.md 供回看。计划级赛马——比 prose 级 Best-of-N 省
5
- 一个数量级的 token。"""
6
- from __future__ import annotations
7
-
8
- import logging
9
- import os
10
-
11
- log = logging.getLogger(__name__)
12
-
13
- BRANCH_PLAN_PROMPT = """你是网文剧情策划。基于全书设定与上一章结尾,为下一章生成 __N__ 条**彼此方向不同**的剧情分支计划。
14
-
15
- 要求:
16
- - 每条分支给出:本章节拍(50-120 字:事件/冲突/推进)+ 章末钩子(一句话)+ 一句取舍理由(为什么选/不选它)
17
- - 分支之间要有真实的方向差异(不同冲突来源/不同人物决定/不同信息揭示),不是同一件事换措辞
18
- - 你是策划也是评委:综合大纲意图、前情、人物动机,推荐其中最有力的一条
19
-
20
- 只输出一个 ```json 代码块:
21
- {"branches": [{"beats": "…", "hook": "…", "why": "…"}, …], "pick": 0}
22
- pick = 推荐分支的下标(0 起)。
23
-
24
- ## 全书目标
25
- __GOAL__
26
-
27
- ## 大纲上下文(本章前后)
28
- __OUTLINE__
29
-
30
- ## 上一章结尾
31
- __PREV__
32
- """
33
-
34
-
35
- def plan_branches(run_id, task, i, goal, outline_txt, prev, n, *, log_path=None):
36
- """生成并择优一条分支计划。返回 (beats, hook) 或 None(失败/未启用走原大纲)。
37
-
38
- 编排者一次调用产 N 条+自荐 pick;失败静默回落原大纲节拍(推演是增强
39
- 不是闸门)。全部分支连同 pick 追加 .codebee/branch-plans.md 审计。"""
40
- if n < 2:
41
- return None
42
- # Token 压力守卫:压力 > 0.7 时跳过推演——每次推演是额外 4000
43
- # max_tokens 编排者调用;长篇后期预算紧张时推演是第一个该省的增强
44
- # (压缩守卫先跑、推演不跑,省下的预算留给正文章稿)。
45
- try:
46
- from . import token_meter
47
- if token_meter.pressure_ratio(run_id) > 0.7:
48
- return None
49
- except Exception:
50
- pass
51
- from . import modelhub, runner
52
- orch = modelhub.resolve_orchestrator()
53
- if not orch:
54
- return None
55
- prov, model = orch
56
- prompt = (BRANCH_PLAN_PROMPT
57
- .replace("__N__", str(n))
58
- .replace("__GOAL__", goal[:600])
59
- .replace("__OUTLINE__", outline_txt[:3000])
60
- .replace("__PREV__", (prev or "(开篇)")[-1200:]))
61
- res = modelhub.chat(prov["id"], model, prompt, max_tokens=4000, timeout=300)
62
- if not res.get("ok"):
63
- return None
64
- data = runner.extract_json(res.get("text") or "")
65
- branches = (data or {}).get("branches") if isinstance(data, dict) else None
66
- if not isinstance(branches, list):
67
- return None
68
- usable = [b for b in branches
69
- if isinstance(b, dict) and str(b.get("beats") or "").strip()]
70
- if len(usable) < 2:
71
- return None
72
- try:
73
- pick = int(data.get("pick") or 0)
74
- except (TypeError, ValueError):
75
- pick = 0
76
- pick = max(0, min(pick, len(usable) - 1))
77
- chosen = usable[pick]
78
- try:
79
- from . import store as _store
80
- wd = _store.run_workdir(run_id) or ""
81
- except Exception:
82
- wd = ""
83
- _append_audit(wd, i, usable, pick)
84
- return (str(chosen["beats"]).strip()[:300],
85
- str(chosen.get("hook") or "").strip()[:80] or None)
86
-
87
-
88
- def _append_audit(workdir, chapter, branches, pick):
89
- """全部分支追加 .codebee/branch-plans.md(失败静默——审计是增强)。"""
90
- if not workdir:
91
- return
92
- try:
93
- p = _audit_path(workdir)
94
- os.makedirs(os.path.dirname(p), exist_ok=True)
95
- with open(p, "a", encoding="utf-8") as f:
96
- if f.tell() == 0:
97
- f.write("# 多线剧情推演(每章分支计划与择优,供回看)\n\n")
98
- f.write("## 第 %d 章\n" % chapter)
99
- for k, b in enumerate(branches):
100
- mark = "✅ " if k == pick else ""
101
- f.write("- %s%s(钩子:%s)——%s\n" % (
102
- mark, str(b.get("beats") or "")[:160],
103
- str(b.get("hook") or "")[:60],
104
- str(b.get("why") or "")[:120]))
105
- f.write("\n")
106
- except Exception:
107
- pass
108
-
109
-
110
- def _audit_path(workdir):
111
- """审计文件路径(越界拒绝:workdir 必须存在的目录)。"""
112
- from pathlib import Path
113
- root = Path(workdir).resolve()
114
- if not root.is_dir():
115
- raise ValueError("workdir 必须是已存在的目录")
116
- return root / ".codebee" / "branch-plans.md"
117
-
118
-
119
- def mark_stale(workdir, chapter):
120
- """正史重写后旧推演标过期(inkos 借鉴:分支计划随正史失效)。
121
-
122
- 修订步骤改写章稿后,本章的分支计划节头追加「(已过期,正史已重写)」——
123
- 防止后续翻看审计时把旧推演当成当前正史的来源。失败静默。"""
124
- if not workdir:
125
- return
126
- try:
127
- p = _audit_path(workdir)
128
- if not p.is_file():
129
- return
130
- txt = p.read_text(encoding="utf-8", errors="replace")
131
- header = "## 第 %d 章\n" % chapter
132
- stale_header = "## 第 %d 章(已过期,正史已重写)\n" % chapter
133
- if header in txt and stale_header not in txt:
134
- p.write_text(txt.replace(header, stale_header, 1),
135
- encoding="utf-8")
136
- except Exception:
137
- pass
1
+ # -*- coding: utf-8 -*-
2
+ """多线剧情推演(inkos 借鉴 2026-09-23):写章前一次调用生成 2-3 条分支
3
+ 节拍计划,自带推荐择优,选中分支注入本章 BEATS;全部分支追加审计文件
4
+ .codebee/branch-plans.md 供回看。计划级赛马——比 prose 级 Best-of-N 省
5
+ 一个数量级的 token。"""
6
+ from __future__ import annotations
7
+
8
+ import logging
9
+ import os
10
+
11
+ log = logging.getLogger(__name__)
12
+
13
+ BRANCH_PLAN_PROMPT = """你是网文剧情策划。基于全书设定与上一章结尾,为下一章生成 __N__ 条**彼此方向不同**的剧情分支计划。
14
+
15
+ 要求:
16
+ - 每条分支给出:本章节拍(50-120 字:事件/冲突/推进)+ 章末钩子(一句话)+ 一句取舍理由(为什么选/不选它)
17
+ - 分支之间要有真实的方向差异(不同冲突来源/不同人物决定/不同信息揭示),不是同一件事换措辞
18
+ - 你是策划也是评委:综合大纲意图、前情、人物动机,推荐其中最有力的一条
19
+
20
+ 只输出一个 ```json 代码块:
21
+ {"branches": [{"beats": "…", "hook": "…", "why": "…"}, …], "pick": 0}
22
+ pick = 推荐分支的下标(0 起)。
23
+
24
+ ## 全书目标
25
+ __GOAL__
26
+
27
+ ## 大纲上下文(本章前后)
28
+ __OUTLINE__
29
+
30
+ ## 上一章结尾
31
+ __PREV__
32
+ """
33
+
34
+
35
+ def plan_branches(run_id, task, i, goal, outline_txt, prev, n, *, log_path=None):
36
+ """生成并择优一条分支计划。返回 (beats, hook) 或 None(失败/未启用走原大纲)。
37
+
38
+ 编排者一次调用产 N 条+自荐 pick;失败静默回落原大纲节拍(推演是增强
39
+ 不是闸门)。全部分支连同 pick 追加 .codebee/branch-plans.md 审计。"""
40
+ if n < 2:
41
+ return None
42
+ # Token 压力守卫:压力 > 0.7 时跳过推演——每次推演是额外 4000
43
+ # max_tokens 编排者调用;长篇后期预算紧张时推演是第一个该省的增强
44
+ # (压缩守卫先跑、推演不跑,省下的预算留给正文章稿)。
45
+ try:
46
+ from . import token_meter
47
+ if token_meter.pressure_ratio(run_id) > 0.7:
48
+ return None
49
+ except Exception:
50
+ pass
51
+ from . import modelhub, runner
52
+ orch = modelhub.resolve_orchestrator()
53
+ if not orch:
54
+ return None
55
+ prov, model = orch
56
+ prompt = (BRANCH_PLAN_PROMPT
57
+ .replace("__N__", str(n))
58
+ .replace("__GOAL__", goal[:600])
59
+ .replace("__OUTLINE__", outline_txt[:3000])
60
+ .replace("__PREV__", (prev or "(开篇)")[-1200:]))
61
+ res = modelhub.chat(prov["id"], model, prompt, max_tokens=4000, timeout=300)
62
+ if not res.get("ok"):
63
+ return None
64
+ data = runner.extract_json(res.get("text") or "")
65
+ branches = (data or {}).get("branches") if isinstance(data, dict) else None
66
+ if not isinstance(branches, list):
67
+ return None
68
+ usable = [b for b in branches
69
+ if isinstance(b, dict) and str(b.get("beats") or "").strip()]
70
+ if len(usable) < 2:
71
+ return None
72
+ try:
73
+ pick = int(data.get("pick") or 0)
74
+ except (TypeError, ValueError):
75
+ pick = 0
76
+ pick = max(0, min(pick, len(usable) - 1))
77
+ chosen = usable[pick]
78
+ try:
79
+ from . import store as _store
80
+ wd = _store.run_workdir(run_id) or ""
81
+ except Exception:
82
+ wd = ""
83
+ _append_audit(wd, i, usable, pick)
84
+ return (str(chosen["beats"]).strip()[:300],
85
+ str(chosen.get("hook") or "").strip()[:80] or None)
86
+
87
+
88
+ def _append_audit(workdir, chapter, branches, pick):
89
+ """全部分支追加 .codebee/branch-plans.md(失败静默——审计是增强)。"""
90
+ if not workdir:
91
+ return
92
+ try:
93
+ p = _audit_path(workdir)
94
+ os.makedirs(os.path.dirname(p), exist_ok=True)
95
+ with open(p, "a", encoding="utf-8") as f:
96
+ if f.tell() == 0:
97
+ f.write("# 多线剧情推演(每章分支计划与择优,供回看)\n\n")
98
+ f.write("## 第 %d 章\n" % chapter)
99
+ for k, b in enumerate(branches):
100
+ mark = "✅ " if k == pick else ""
101
+ f.write("- %s%s(钩子:%s)——%s\n" % (
102
+ mark, str(b.get("beats") or "")[:160],
103
+ str(b.get("hook") or "")[:60],
104
+ str(b.get("why") or "")[:120]))
105
+ f.write("\n")
106
+ except Exception:
107
+ pass
108
+
109
+
110
+ def _audit_path(workdir):
111
+ """审计文件路径(越界拒绝:workdir 必须存在的目录)。"""
112
+ from pathlib import Path
113
+ root = Path(workdir).resolve()
114
+ if not root.is_dir():
115
+ raise ValueError("workdir 必须是已存在的目录")
116
+ return root / ".codebee" / "branch-plans.md"
117
+
118
+
119
+ def mark_stale(workdir, chapter):
120
+ """正史重写后旧推演标过期(inkos 借鉴:分支计划随正史失效)。
121
+
122
+ 修订步骤改写章稿后,本章的分支计划节头追加「(已过期,正史已重写)」——
123
+ 防止后续翻看审计时把旧推演当成当前正史的来源。失败静默。"""
124
+ if not workdir:
125
+ return
126
+ try:
127
+ p = _audit_path(workdir)
128
+ if not p.is_file():
129
+ return
130
+ txt = p.read_text(encoding="utf-8", errors="replace")
131
+ header = "## 第 %d 章\n" % chapter
132
+ stale_header = "## 第 %d 章(已过期,正史已重写)\n" % chapter
133
+ if header in txt and stale_header not in txt:
134
+ p.write_text(txt.replace(header, stale_header, 1),
135
+ encoding="utf-8")
136
+ except Exception:
137
+ pass