codebee 0.1.62 → 0.1.64

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 (101) hide show
  1. package/CHANGELOG.md +507 -490
  2. package/LICENSE +21 -21
  3. package/README.md +487 -486
  4. package/app/.playwright-cli/console-2026-09-23T08-26-03-635Z.log +88 -0
  5. package/app/.playwright-cli/page-2026-09-23T08-26-03-845Z.yml +126 -0
  6. package/app/.playwright-cli/page-2026-09-23T08-29-44-203Z.png +0 -0
  7. package/app/.playwright-cli/page-2026-09-23T08-35-42-046Z.yml +210 -0
  8. package/app/.playwright-cli/page-2026-09-23T08-36-52-858Z.png +0 -0
  9. package/app/.playwright-cli/page-2026-09-23T08-37-33-938Z.png +0 -0
  10. package/app/.playwright-cli/run-detail-after.png +0 -0
  11. package/app/core/aiflavor.py +197 -197
  12. package/app/core/artifacts.py +148 -0
  13. package/app/core/attachments.py +532 -532
  14. package/app/core/automation.py +758 -758
  15. package/app/core/backup.py +470 -470
  16. package/app/core/beekeeper.py +183 -183
  17. package/app/core/board.py +209 -209
  18. package/app/core/bookmeta.py +215 -19
  19. package/app/core/bookmeta_catalog.py +180 -180
  20. package/app/core/branching.py +137 -137
  21. package/app/core/builtin_agent.py +1191 -1191
  22. package/app/core/capability.py +144 -144
  23. package/app/core/catalog.py +19 -14
  24. package/app/core/chaptersafe.py +32 -32
  25. package/app/core/cleanup.py +303 -303
  26. package/app/core/compaction.py +186 -186
  27. package/app/core/covergen.py +356 -356
  28. package/app/core/diagnostics.py +114 -114
  29. package/app/core/dispatch.py +173 -173
  30. package/app/core/dispatch_log.py +113 -113
  31. package/app/core/env_scrub.py +85 -85
  32. package/app/core/error_codes.py +64 -64
  33. package/app/core/errorlog.py +137 -137
  34. package/app/core/flows.py +355 -355
  35. package/app/core/goal_service.py +167 -167
  36. package/app/core/health.py +341 -341
  37. package/app/core/history.py +38 -38
  38. package/app/core/hooks.py +156 -156
  39. package/app/core/jobs.py +1022 -1022
  40. package/app/core/manager.py +1996 -1996
  41. package/app/core/market.py +362 -362
  42. package/app/core/market_remote.py +66 -66
  43. package/app/core/mocks.py +64 -64
  44. package/app/core/modelhub.py +3332 -3266
  45. package/app/core/notify.py +106 -106
  46. package/app/core/paihang.py +109 -109
  47. package/app/core/paths.py +2 -2
  48. package/app/core/pipeline.py +4483 -4426
  49. package/app/core/planner.py +27 -27
  50. package/app/core/portguard.py +111 -111
  51. package/app/core/preview.py +293 -293
  52. package/app/core/publish/__init__.py +7 -7
  53. package/app/core/publish/auto.py +367 -367
  54. package/app/core/publish/browser.py +533 -533
  55. package/app/core/publish/fanqie.py +128 -128
  56. package/app/core/publish/flow.py +406 -406
  57. package/app/core/publish/ledger.py +198 -198
  58. package/app/core/publish/manager.py +590 -590
  59. package/app/core/publish/qimao.py +141 -141
  60. package/app/core/publish/ws.py +139 -139
  61. package/app/core/redact.py +38 -38
  62. package/app/core/repeat_guard.py +124 -124
  63. package/app/core/router.py +20 -3
  64. package/app/core/runner.py +2019 -1991
  65. package/app/core/selfupdate.py +384 -384
  66. package/app/core/session_log.py +161 -161
  67. package/app/core/sessions.py +312 -312
  68. package/app/core/settings.py +149 -149
  69. package/app/core/settings_schema.py +262 -262
  70. package/app/core/share_page.py +114 -114
  71. package/app/core/skill_scan.py +106 -106
  72. package/app/core/skillpacks/fanqie-novel.md +80 -80
  73. package/app/core/skillpacks/market/character-bible.md +66 -66
  74. package/app/core/skillpacks/market/code-risk-checklist.md +58 -58
  75. package/app/core/skillpacks/market/git-workflow.md +57 -57
  76. package/app/core/skillpacks/market/release-notes.md +72 -72
  77. package/app/core/skillpacks/market/weekly-report.md +71 -71
  78. package/app/core/skillpacks/market/worldview-consistency.md +70 -70
  79. package/app/core/step_runner.py +132 -132
  80. package/app/core/store.py +13 -70
  81. package/app/core/task_compile.py +199 -199
  82. package/app/core/telemetry.py +292 -292
  83. package/app/core/tlsctx.py +64 -64
  84. package/app/core/token_meter.py +147 -147
  85. package/app/core/volumes.py +355 -355
  86. package/app/core/wxdigest.py +858 -858
  87. package/app/core/zentao.py +2447 -2090
  88. package/app/main.py +2832 -2826
  89. package/app/pick_dialog.py +110 -110
  90. package/app/ui/app.js +13977 -13977
  91. package/app/ui/board.html +162 -162
  92. package/app/ui/board.js +305 -305
  93. package/app/ui/i18n.js +2711 -2711
  94. package/app/ui/icons/bee.svg +79 -79
  95. package/app/ui/index.html +1 -1
  96. package/app/ui/manifest.json +16 -16
  97. package/app/ui/qrcode.js +2297 -2297
  98. package/app/ui/style.css +6125 -6125
  99. package/bin/tutti.js +147 -147
  100. package/package.json +41 -41
  101. package/tools/wx_reader.py +261 -261
@@ -1,128 +1,128 @@
1
- # -*- coding: utf-8 -*-
2
- """番茄作家后台的发布流程定义(默认表:选择器为合理推测,待实测校准)。
3
-
4
- 校准方式(不改代码):把真实步骤写进 data/publish/flows-fanqie.json:
5
- {"create_book": [ {"do":"navigate","url":"..."}, {"do":"fill","sel":"...","key":"title"} ... ],
6
- "upload_chapter": [ ... ]}
7
- 存在即整体覆盖本文件的 FLOWS;用「探测表单」按钮(probe 流程)dump 出
8
- 页面真实元素清单后照着写即可。每次失败的截图也会指出卡在哪一步。
9
-
10
- URL 依据:tools/fanqie_bookmeta.json 的 source 记录了 2026-09-17 实抓
11
- fanqienovel.com/main/writer/create 建书弹层;入口走作家后台首页点
12
- 「创建作品」,不硬编码深链(深链随改版漂移,入口按钮最稳)。
13
- """
14
- from __future__ import annotations
15
-
16
- CONFIG = {
17
- "id": "fanqie",
18
- "label": "番茄",
19
- "home": "https://fanqienovel.com/main/writer/", # 实测 writer. 子域不存在(DNS 000);快照实抓为主站路径
20
- # 导航后 URL 含任一标记 → 未登录(跳到了登录/通行证页)
21
- "login_url_marks": ["login", "passport", "sso", "account/signin"],
22
- }
23
-
24
- # 建书:入口 → 弹层/页面 → 文本字段直填;分类/签约模式/标签走文本点击。
25
- # 文本输入类的选择器优先用 placeholder 模糊匹配(改版后 id/class 易变,
26
- # 「书名」「简介」这类 placeholder 语料最稳定)。
27
- CREATE_BOOK = [
28
- {"do": "navigate", "url": "{home}"},
29
- {"do": "url_any", "any": ["fanqienovel.com"]},
30
- {"do": "click_text", "text": "创建作品", "contains": True, "scope": "button,a,[role=button],span"},
31
- {"do": "probe", "note": "建书表单"},
32
- {"do": "wait", "sel": "input[placeholder*='书名'],input[placeholder*='作品名'],input[maxlength]", "timeout": 10},
33
- {"do": "fill", "sel": "input[placeholder*='书名'],input[placeholder*='作品名']", "key": "title"},
34
- {"do": "fill", "sel": "textarea[placeholder*='简介'],textarea", "key": "summary"},
35
- {"do": "fill", "sel": "input[placeholder*='主角']", "key": "protagonist"},
36
- {"do": "click_text", "text": "{signing_mode}", "contains": False,
37
- "scope": "[class*=mode] label,label,span,div"},
38
- {"do": "click_text", "text": "{category}", "contains": False,
39
- "scope": "[class*=categor] li,span,div"},
40
- {"do": "shot", "name": "create-book-filled"},
41
- {"do": "submit", "sel": "button[class*=submit],button[class*=primary]"},
42
- ]
43
-
44
- # 发章:后台首页 → 按书名点进作品 → 新建章节 → 填标题与正文。
45
- # book_name 由 manager 从作品登记(books.json)带入 values,click_text 复用。
46
- UPLOAD_CHAPTER = [
47
- {"do": "navigate", "url": "{home}"},
48
- {"do": "url_any", "any": ["fanqienovel.com"]},
49
- {"do": "click_text", "text": "{book_name}", "contains": True,
50
- "scope": "a,span,div[class*=title],div[class*=book]"},
51
- {"do": "click_text", "text": "新建章节", "contains": True, "scope": "button,a,[role=button],span"},
52
- {"do": "probe", "note": "章节编辑器"},
53
- {"do": "fill", "sel": "input[placeholder*='章节'],input[placeholder*='标题']", "key": "chapter_title"},
54
- {"do": "wait", "sel": "[contenteditable=true],textarea[class*=content],div[class*=editor]", "timeout": 10},
55
- {"do": "fill", "sel": "[contenteditable=true],textarea[class*=content]", "key": "chapter_body"},
56
- {"do": "shot", "name": "chapter-filled"},
57
- {"do": "submit", "sel": "button[class*=publish],button[class*=submit]"},
58
- ]
59
-
60
- # 登录态探测:打开后台首页,URL 被踢到登录页 → 未登录
61
- CHECK_LOGIN = [
62
- {"do": "navigate", "url": "{home}"},
63
- {"do": "url_any", "any": ["fanqienovel.com"]},
64
- ]
65
-
66
- # 表单探测(校准辅助):开建书入口后 dump 全部可交互元素
67
- PROBE_FORM = [
68
- {"do": "navigate", "url": "{home}"},
69
- {"do": "url_any", "any": ["fanqienovel.com"]},
70
- {"do": "click_text", "text": "创建作品", "contains": True, "scope": "button,a,[role=button],span"},
71
- {"do": "probe", "note": "建书表单"},
72
- ]
73
-
74
- FLOWS = {"create_book": CREATE_BOOK, "upload_chapter": UPLOAD_CHAPTER,
75
- "check_login": CHECK_LOGIN, "probe_form": PROBE_FORM}
76
-
77
-
78
- def _first(meta, key):
79
- v = meta.get(key)
80
- return str(v[0]).strip() if isinstance(v, list) and v else str(v or "").strip()
81
-
82
-
83
- def values_create_book(meta):
84
- """bookmeta 字段 → 建书表单值。标签弹层的分区点选用单值字段
85
- (每组选 1 个最稳:番茄主题/角色/情节各≤2、内容组各有上限),
86
- 数组全量点选由 tag_groups 路径兼容。"""
87
- return {
88
- "title": (meta.get("book_name") or "").strip(),
89
- "summary": (meta.get("summary") or "").strip(),
90
- "protagonist": (meta.get("protagonist_1") or "").strip(),
91
- "protagonist2": (meta.get("protagonist_2") or "").strip(),
92
- "signing_mode": (meta.get("signing_mode") or "连载模式").strip(),
93
- "category": (meta.get("category") or "").strip(),
94
- "target_reader": (meta.get("target_reader") or "男频").strip(),
95
- "tag_theme": _first(meta, "tags_theme"),
96
- "tag_role": _first(meta, "tags_role"),
97
- "tag_plot": _first(meta, "tags_plot"),
98
- "tag_content_emotion": _first(meta, "content_emotion"),
99
- "tag_content_character": _first(meta, "content_character"),
100
- "tag_content_world": _first(meta, "content_world"),
101
- }
102
-
103
-
104
- def tag_groups(meta):
105
- """标签字段名 → 值列表(manager 用来生成逐个 click_text 步骤)。"""
106
- out = []
107
- for key in ("tags_theme", "tags_role", "tags_plot",
108
- "content_plot", "content_emotion", "content_character", "content_world"):
109
- v = meta.get(key)
110
- if isinstance(v, list) and v:
111
- out.append((key, [str(x) for x in v]))
112
- return out
113
-
114
-
115
- def editor_url(book):
116
- """章节编辑器直达(真机实测):/main/writer/<book_id>/publish/。"""
117
- bid = str((book or {}).get("book_id") or "")
118
- if bid:
119
- return "https://fanqienovel.com/main/writer/%s/publish/" % bid
120
- return CONFIG["home"]
121
-
122
-
123
- def chapter_manage_url(book):
124
- """章节管理页(上线验证用)。"""
125
- bid = str((book or {}).get("book_id") or "")
126
- if bid:
127
- return "https://fanqienovel.com/main/writer/chapter-manage/" + bid
128
- return CONFIG["home"] + "book-manage"
1
+ # -*- coding: utf-8 -*-
2
+ """番茄作家后台的发布流程定义(默认表:选择器为合理推测,待实测校准)。
3
+
4
+ 校准方式(不改代码):把真实步骤写进 data/publish/flows-fanqie.json:
5
+ {"create_book": [ {"do":"navigate","url":"..."}, {"do":"fill","sel":"...","key":"title"} ... ],
6
+ "upload_chapter": [ ... ]}
7
+ 存在即整体覆盖本文件的 FLOWS;用「探测表单」按钮(probe 流程)dump 出
8
+ 页面真实元素清单后照着写即可。每次失败的截图也会指出卡在哪一步。
9
+
10
+ URL 依据:tools/fanqie_bookmeta.json 的 source 记录了 2026-09-17 实抓
11
+ fanqienovel.com/main/writer/create 建书弹层;入口走作家后台首页点
12
+ 「创建作品」,不硬编码深链(深链随改版漂移,入口按钮最稳)。
13
+ """
14
+ from __future__ import annotations
15
+
16
+ CONFIG = {
17
+ "id": "fanqie",
18
+ "label": "番茄",
19
+ "home": "https://fanqienovel.com/main/writer/", # 实测 writer. 子域不存在(DNS 000);快照实抓为主站路径
20
+ # 导航后 URL 含任一标记 → 未登录(跳到了登录/通行证页)
21
+ "login_url_marks": ["login", "passport", "sso", "account/signin"],
22
+ }
23
+
24
+ # 建书:入口 → 弹层/页面 → 文本字段直填;分类/签约模式/标签走文本点击。
25
+ # 文本输入类的选择器优先用 placeholder 模糊匹配(改版后 id/class 易变,
26
+ # 「书名」「简介」这类 placeholder 语料最稳定)。
27
+ CREATE_BOOK = [
28
+ {"do": "navigate", "url": "{home}"},
29
+ {"do": "url_any", "any": ["fanqienovel.com"]},
30
+ {"do": "click_text", "text": "创建作品", "contains": True, "scope": "button,a,[role=button],span"},
31
+ {"do": "probe", "note": "建书表单"},
32
+ {"do": "wait", "sel": "input[placeholder*='书名'],input[placeholder*='作品名'],input[maxlength]", "timeout": 10},
33
+ {"do": "fill", "sel": "input[placeholder*='书名'],input[placeholder*='作品名']", "key": "title"},
34
+ {"do": "fill", "sel": "textarea[placeholder*='简介'],textarea", "key": "summary"},
35
+ {"do": "fill", "sel": "input[placeholder*='主角']", "key": "protagonist"},
36
+ {"do": "click_text", "text": "{signing_mode}", "contains": False,
37
+ "scope": "[class*=mode] label,label,span,div"},
38
+ {"do": "click_text", "text": "{category}", "contains": False,
39
+ "scope": "[class*=categor] li,span,div"},
40
+ {"do": "shot", "name": "create-book-filled"},
41
+ {"do": "submit", "sel": "button[class*=submit],button[class*=primary]"},
42
+ ]
43
+
44
+ # 发章:后台首页 → 按书名点进作品 → 新建章节 → 填标题与正文。
45
+ # book_name 由 manager 从作品登记(books.json)带入 values,click_text 复用。
46
+ UPLOAD_CHAPTER = [
47
+ {"do": "navigate", "url": "{home}"},
48
+ {"do": "url_any", "any": ["fanqienovel.com"]},
49
+ {"do": "click_text", "text": "{book_name}", "contains": True,
50
+ "scope": "a,span,div[class*=title],div[class*=book]"},
51
+ {"do": "click_text", "text": "新建章节", "contains": True, "scope": "button,a,[role=button],span"},
52
+ {"do": "probe", "note": "章节编辑器"},
53
+ {"do": "fill", "sel": "input[placeholder*='章节'],input[placeholder*='标题']", "key": "chapter_title"},
54
+ {"do": "wait", "sel": "[contenteditable=true],textarea[class*=content],div[class*=editor]", "timeout": 10},
55
+ {"do": "fill", "sel": "[contenteditable=true],textarea[class*=content]", "key": "chapter_body"},
56
+ {"do": "shot", "name": "chapter-filled"},
57
+ {"do": "submit", "sel": "button[class*=publish],button[class*=submit]"},
58
+ ]
59
+
60
+ # 登录态探测:打开后台首页,URL 被踢到登录页 → 未登录
61
+ CHECK_LOGIN = [
62
+ {"do": "navigate", "url": "{home}"},
63
+ {"do": "url_any", "any": ["fanqienovel.com"]},
64
+ ]
65
+
66
+ # 表单探测(校准辅助):开建书入口后 dump 全部可交互元素
67
+ PROBE_FORM = [
68
+ {"do": "navigate", "url": "{home}"},
69
+ {"do": "url_any", "any": ["fanqienovel.com"]},
70
+ {"do": "click_text", "text": "创建作品", "contains": True, "scope": "button,a,[role=button],span"},
71
+ {"do": "probe", "note": "建书表单"},
72
+ ]
73
+
74
+ FLOWS = {"create_book": CREATE_BOOK, "upload_chapter": UPLOAD_CHAPTER,
75
+ "check_login": CHECK_LOGIN, "probe_form": PROBE_FORM}
76
+
77
+
78
+ def _first(meta, key):
79
+ v = meta.get(key)
80
+ return str(v[0]).strip() if isinstance(v, list) and v else str(v or "").strip()
81
+
82
+
83
+ def values_create_book(meta):
84
+ """bookmeta 字段 → 建书表单值。标签弹层的分区点选用单值字段
85
+ (每组选 1 个最稳:番茄主题/角色/情节各≤2、内容组各有上限),
86
+ 数组全量点选由 tag_groups 路径兼容。"""
87
+ return {
88
+ "title": (meta.get("book_name") or "").strip(),
89
+ "summary": (meta.get("summary") or "").strip(),
90
+ "protagonist": (meta.get("protagonist_1") or "").strip(),
91
+ "protagonist2": (meta.get("protagonist_2") or "").strip(),
92
+ "signing_mode": (meta.get("signing_mode") or "连载模式").strip(),
93
+ "category": (meta.get("category") or "").strip(),
94
+ "target_reader": (meta.get("target_reader") or "男频").strip(),
95
+ "tag_theme": _first(meta, "tags_theme"),
96
+ "tag_role": _first(meta, "tags_role"),
97
+ "tag_plot": _first(meta, "tags_plot"),
98
+ "tag_content_emotion": _first(meta, "content_emotion"),
99
+ "tag_content_character": _first(meta, "content_character"),
100
+ "tag_content_world": _first(meta, "content_world"),
101
+ }
102
+
103
+
104
+ def tag_groups(meta):
105
+ """标签字段名 → 值列表(manager 用来生成逐个 click_text 步骤)。"""
106
+ out = []
107
+ for key in ("tags_theme", "tags_role", "tags_plot",
108
+ "content_plot", "content_emotion", "content_character", "content_world"):
109
+ v = meta.get(key)
110
+ if isinstance(v, list) and v:
111
+ out.append((key, [str(x) for x in v]))
112
+ return out
113
+
114
+
115
+ def editor_url(book):
116
+ """章节编辑器直达(真机实测):/main/writer/<book_id>/publish/。"""
117
+ bid = str((book or {}).get("book_id") or "")
118
+ if bid:
119
+ return "https://fanqienovel.com/main/writer/%s/publish/" % bid
120
+ return CONFIG["home"]
121
+
122
+
123
+ def chapter_manage_url(book):
124
+ """章节管理页(上线验证用)。"""
125
+ bid = str((book or {}).get("book_id") or "")
126
+ if bid:
127
+ return "https://fanqienovel.com/main/writer/chapter-manage/" + bid
128
+ return CONFIG["home"] + "book-manage"