codebee 0.1.95 → 0.1.97

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 (144) hide show
  1. package/CHANGELOG.md +733 -720
  2. package/LICENSE +21 -21
  3. package/README.md +516 -509
  4. package/app/core/acceptance.py +100 -100
  5. package/app/core/agent_context.py +118 -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 +246 -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 +2055 -1680
  20. package/app/core/capability.py +144 -144
  21. package/app/core/chaptersafe.py +32 -32
  22. package/app/core/checkpoints.py +648 -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/mcp_client.py +200 -29
  46. package/app/core/mocks.py +64 -64
  47. package/app/core/notify.py +201 -201
  48. package/app/core/novel_quality.py +181 -189
  49. package/app/core/openapi.py +177 -154
  50. package/app/core/operations.py +228 -228
  51. package/app/core/paihang.py +145 -145
  52. package/app/core/pipeline.py +319 -59
  53. package/app/core/planner.py +17 -11
  54. package/app/core/policy.py +84 -0
  55. package/app/core/portguard.py +111 -111
  56. package/app/core/presence.py +77 -77
  57. package/app/core/preview.py +293 -293
  58. package/app/core/project_memory.py +139 -0
  59. package/app/core/prompt_guard.py +78 -78
  60. package/app/core/publish/__init__.py +7 -7
  61. package/app/core/publish/auto.py +106 -22
  62. package/app/core/publish/browser.py +694 -655
  63. package/app/core/publish/chaprows.py +138 -0
  64. package/app/core/publish/fanqie.py +212 -165
  65. package/app/core/publish/flow.py +832 -640
  66. package/app/core/publish/flows-fanqie-calibrated.json +361 -336
  67. package/app/core/publish/ledger.py +51 -2
  68. package/app/core/publish/manager.py +1150 -1118
  69. package/app/core/publish/qimao.py +176 -176
  70. package/app/core/publish/volumes.py +108 -0
  71. package/app/core/publish/ws.py +139 -139
  72. package/app/core/quality_gate.py +194 -194
  73. package/app/core/redact.py +38 -38
  74. package/app/core/repeat_guard.py +129 -129
  75. package/app/core/retrieval.py +137 -137
  76. package/app/core/router.py +398 -398
  77. package/app/core/runner.py +2239 -2238
  78. package/app/core/selfupdate.py +384 -384
  79. package/app/core/session_log.py +161 -161
  80. package/app/core/sessions.py +312 -312
  81. package/app/core/settings.py +33 -5
  82. package/app/core/settings_schema.py +282 -271
  83. package/app/core/share_page.py +114 -114
  84. package/app/core/skill_scan.py +139 -139
  85. package/app/core/skillpacks/fanqie-novel.md +8 -6
  86. package/app/core/skillpacks/market/character-bible.md +66 -66
  87. package/app/core/skillpacks/market/code-risk-checklist.md +58 -58
  88. package/app/core/skillpacks/market/git-workflow.md +57 -57
  89. package/app/core/skillpacks/market/release-notes.md +72 -72
  90. package/app/core/skillpacks/market/weekly-report.md +71 -71
  91. package/app/core/skillpacks/market/worldview-consistency.md +70 -70
  92. package/app/core/skillpacks/qimao-signing.md +14 -11
  93. package/app/core/skills.py +32 -21
  94. package/app/core/step_runner.py +132 -132
  95. package/app/core/store.py +24 -0
  96. package/app/core/story_tracking.py +275 -275
  97. package/app/core/task_compile.py +199 -199
  98. package/app/core/telemetry.py +292 -292
  99. package/app/core/tlsctx.py +64 -64
  100. package/app/core/token_meter.py +147 -147
  101. package/app/core/tool_outputs.py +107 -0
  102. package/app/core/tracing.py +207 -144
  103. package/app/core/upstream.py +41 -41
  104. package/app/core/usage.py +1038 -1038
  105. package/app/core/volumes.py +389 -389
  106. package/app/core/webhooks.py +89 -0
  107. package/app/core/wxdigest.py +865 -858
  108. package/app/core/zentao.py +2692 -2692
  109. package/app/main.py +179 -10
  110. package/app/mcp_server.py +244 -244
  111. package/app/pick_dialog.py +110 -110
  112. package/app/ui/app.js +563 -21
  113. package/app/ui/artdiff.js +74 -74
  114. package/app/ui/assets/community-qr.png +0 -0
  115. package/app/ui/assets/donate-alipay.jpg +0 -0
  116. package/app/ui/assets/donate-qr.jpg +0 -0
  117. package/app/ui/assets/workbench-reference.png +0 -0
  118. package/app/ui/board.css +451 -666
  119. package/app/ui/board.html +165 -162
  120. package/app/ui/board.js +509 -305
  121. package/app/ui/hive3d.js +242 -0
  122. package/app/ui/i18n.js +125 -9
  123. package/app/ui/icons/bee.svg +79 -79
  124. package/app/ui/index.html +60 -3
  125. package/app/ui/manifest.json +16 -16
  126. package/app/ui/qrcode.js +2297 -2297
  127. package/app/ui/style.css +189 -9
  128. package/bin/tutti.js +147 -147
  129. package/package.json +49 -48
  130. package/tools/wx_reader.py +261 -261
  131. package/app/.playwright-cli/console-2026-09-23T08-26-03-635Z.log +0 -88
  132. package/app/.playwright-cli/page-2026-09-23T08-26-03-845Z.yml +0 -126
  133. package/app/.playwright-cli/page-2026-09-23T08-29-44-203Z.png +0 -0
  134. package/app/.playwright-cli/page-2026-09-23T08-35-42-046Z.yml +0 -210
  135. package/app/.playwright-cli/page-2026-09-23T08-36-52-858Z.png +0 -0
  136. package/app/.playwright-cli/page-2026-09-23T08-37-33-938Z.png +0 -0
  137. package/app/.playwright-cli/run-detail-after.png +0 -0
  138. package/app/output/_createbook_body.json +0 -1
  139. package/app/output/_probe_fq_click.py +0 -50
  140. package/app/output/_probe_fq_form.py +0 -42
  141. package/app/output/_probe_fq_modal.py +0 -55
  142. package/app/output/_probe_fq_points.py +0 -71
  143. package/app/output/_probe_fq_submit.py +0 -34
  144. package/app/output/_probe_fq_watch.py +0 -62
@@ -1,114 +1,114 @@
1
- # -*- coding: utf-8 -*-
2
- """可分享报告页(借鉴 agency-orchestrator 的 ao report):把 run 成果渲染成
3
- 自包含单文件 HTML——零 JS、内联样式、离线可看,直接发群/发人。
4
-
5
- 纯函数无网络;数据全部来自调用方(store/paths 已读好的对象)。
6
- """
7
- from __future__ import annotations
8
-
9
- import html as _html
10
- import time
11
-
12
-
13
- def _esc(s):
14
- return _html.escape(str(s if s is not None else ""), quote=True)
15
-
16
-
17
- def _md_ish(text):
18
- """极简 Markdown 呈现:标题/列表/粗体/代码,够报告阅读即可,不做完整解析。"""
19
- out = []
20
- for ln in (text or "").splitlines():
21
- e = _esc(ln)
22
- if ln.startswith("# "):
23
- out.append("<h1>%s</h1>" % e[2:])
24
- elif ln.startswith("## "):
25
- out.append("<h2>%s</h2>" % e[3:])
26
- elif ln.startswith("### "):
27
- out.append("<h3>%s</h3>" % e[4:])
28
- elif ln.startswith("- "):
29
- out.append("<li>%s</li>" % e[2:])
30
- else:
31
- out.append("<p>%s</p>" % e)
32
- return "\n".join(out)
33
-
34
-
35
- _SHARE_TPL = """<!DOCTYPE html>
36
- <html lang="zh"><head><meta charset="utf-8">
37
- <meta name="viewport" content="width=device-width, initial-scale=1">
38
- <title>__TITLE__ · CodeBee 任务报告</title>
39
- <style>
40
- body{margin:0;background:#f5f6f8;color:#1c2330;font:15px/1.65 -apple-system,"PingFang SC","Microsoft YaHei",sans-serif}
41
- .wrap{max-width:760px;margin:0 auto;padding:28px 18px 60px}
42
- .head{border-bottom:3px solid #2b6cb0;padding-bottom:14px;margin-bottom:22px}
43
- h1{margin:0 0 6px;font-size:24px}
44
- .meta{color:#5a6472;font-size:13px}
45
- .badge{display:inline-block;border-radius:999px;padding:2px 12px;font-size:13px;font-weight:600}
46
- .badge.ok{background:#e6f6ec;color:#177245}.badge.bad{background:#fdeaea;color:#b42318}
47
- .badge.off{background:#eef0f3;color:#5a6472}
48
- .card{background:#fff;border:1px solid #e3e6ea;border-radius:12px;padding:18px 20px;margin-bottom:18px}
49
- .card h2{font-size:16px;margin:0 0 12px;color:#2b6cb0}
50
- table{border-collapse:collapse;width:100%}
51
- td{padding:6px 10px;border-bottom:1px solid #eef0f3}
52
- tr.sum td{font-weight:700;border-top:2px solid #e3e6ea}
53
- .step{display:flex;gap:10px;padding:7px 0;border-bottom:1px dashed #eef0f3;font-size:13.5px;align-items:baseline}
54
- .step .n{color:#8a93a0;font-weight:700}.step .role{font-weight:600;min-width:88px}
55
- .step .who{color:#5a6472;min-width:90px}.step .sum{flex:1}.st{font-size:12px}
56
- .st.done{color:#177245}.st.failed{color:#b42318}
57
- h1,h2,h3{margin:14px 0 8px}li{margin:4px 0}.trow{padding:2px 0;border-bottom:1px dotted #eee}
58
- p{margin:8px 0}.mut{color:#8a93a0}code{background:#f0f2f5;padding:1px 6px;border-radius:4px}
59
- pre{background:#f0f2f5;padding:12px;border-radius:8px;overflow-x:auto;white-space:pre-wrap}
60
- </style></head><body><div class="wrap">
61
- <div class="head"><h1>__TITLE__</h1>
62
- <div class="meta">__META__ · __ST__ · CodeBee 生成于 __NOW__</div></div>
63
- <div class="card"><h2>结果</h2><span class="badge __STCLS__">__ST__</span>__OVERALL__</div>
64
- <div class="card"><h2>步骤</h2>__STEPS__</div>
65
- <div class="card"><h2>报告</h2>__REPORT__</div>
66
- <div class="meta">由 <b>CodeBee</b> 多智能体编排台生成</div>
67
- </div></body></html>"""
68
-
69
-
70
- def render_share_html(run, task, report_text):
71
- """渲染自包含分享页。run/task/report_text 缺失时优雅降级。"""
72
- run = run or {}
73
- task = task or {}
74
- status = str(run.get("status") or "")
75
- st_label = {"done": "已完成", "failed": "失败", "cancelled": "已取消",
76
- "running": "进行中"}.get(status, status)
77
- st_cls = {"done": "ok", "failed": "bad", "cancelled": "off"}.get(status, "off")
78
- verdict = run.get("verdict") or {}
79
- means = verdict.get("scores") or {}
80
-
81
- score_rows = ""
82
- for d, v in means.items():
83
- score_rows += "<tr><td>%s</td><td>%.1f</td></tr>" % (_esc(d), float(v))
84
- if verdict:
85
- score_rows += ('<tr class="sum"><td>综合</td>'
86
- '<td>%.1f</td></tr>' % float(verdict.get("overall") or 0))
87
-
88
- steps_rows = ""
89
- for s in run.get("steps") or []:
90
- who = s.get("agent_label") or s.get("agent") or ""
91
- if s.get("model"):
92
- who += " · " + str(s["model"])
93
- steps_rows += (
94
- '<div class="step"><span class="n">%02d</span>'
95
- '<span class="role">%s</span><span class="who">%s</span>'
96
- '<span class="sum">%s</span><span class="st %s">%s</span></div>'
97
- % (s.get("n") or 0, _esc(s.get("role") or ""),
98
- _esc(who),
99
- _esc((s.get("summary") or "")[:220]), _esc(s.get("status") or ""),
100
- _esc(s.get("status") or "")))
101
-
102
- report_html = _md_ish(report_text) if report_text else "<p class='mut'>(暂无报告)</p>"
103
- overall_note = ("综合 %.1f 分" % float(verdict.get("overall"))
104
- if verdict.get("overall") is not None else "")
105
-
106
- return (_SHARE_TPL
107
- .replace("__TITLE__", _esc(task.get("title") or run.get("title") or "任务报告"))
108
- .replace("__META__", _esc(task.get("goal") or ""))
109
- .replace("__ST__", _esc(st_label))
110
- .replace("__STCLS__", st_cls)
111
- .replace("__NOW__", _esc(time.strftime("%Y-%m-%d %H:%M")))
112
- .replace("__OVERALL__", _esc(overall_note))
113
- .replace("__STEPS__", steps_rows or "<p class='mut'>(无步骤)</p>")
114
- .replace("__REPORT__", report_html))
1
+ # -*- coding: utf-8 -*-
2
+ """可分享报告页(借鉴 agency-orchestrator 的 ao report):把 run 成果渲染成
3
+ 自包含单文件 HTML——零 JS、内联样式、离线可看,直接发群/发人。
4
+
5
+ 纯函数无网络;数据全部来自调用方(store/paths 已读好的对象)。
6
+ """
7
+ from __future__ import annotations
8
+
9
+ import html as _html
10
+ import time
11
+
12
+
13
+ def _esc(s):
14
+ return _html.escape(str(s if s is not None else ""), quote=True)
15
+
16
+
17
+ def _md_ish(text):
18
+ """极简 Markdown 呈现:标题/列表/粗体/代码,够报告阅读即可,不做完整解析。"""
19
+ out = []
20
+ for ln in (text or "").splitlines():
21
+ e = _esc(ln)
22
+ if ln.startswith("# "):
23
+ out.append("<h1>%s</h1>" % e[2:])
24
+ elif ln.startswith("## "):
25
+ out.append("<h2>%s</h2>" % e[3:])
26
+ elif ln.startswith("### "):
27
+ out.append("<h3>%s</h3>" % e[4:])
28
+ elif ln.startswith("- "):
29
+ out.append("<li>%s</li>" % e[2:])
30
+ else:
31
+ out.append("<p>%s</p>" % e)
32
+ return "\n".join(out)
33
+
34
+
35
+ _SHARE_TPL = """<!DOCTYPE html>
36
+ <html lang="zh"><head><meta charset="utf-8">
37
+ <meta name="viewport" content="width=device-width, initial-scale=1">
38
+ <title>__TITLE__ · CodeBee 任务报告</title>
39
+ <style>
40
+ body{margin:0;background:#f5f6f8;color:#1c2330;font:15px/1.65 -apple-system,"PingFang SC","Microsoft YaHei",sans-serif}
41
+ .wrap{max-width:760px;margin:0 auto;padding:28px 18px 60px}
42
+ .head{border-bottom:3px solid #2b6cb0;padding-bottom:14px;margin-bottom:22px}
43
+ h1{margin:0 0 6px;font-size:24px}
44
+ .meta{color:#5a6472;font-size:13px}
45
+ .badge{display:inline-block;border-radius:999px;padding:2px 12px;font-size:13px;font-weight:600}
46
+ .badge.ok{background:#e6f6ec;color:#177245}.badge.bad{background:#fdeaea;color:#b42318}
47
+ .badge.off{background:#eef0f3;color:#5a6472}
48
+ .card{background:#fff;border:1px solid #e3e6ea;border-radius:12px;padding:18px 20px;margin-bottom:18px}
49
+ .card h2{font-size:16px;margin:0 0 12px;color:#2b6cb0}
50
+ table{border-collapse:collapse;width:100%}
51
+ td{padding:6px 10px;border-bottom:1px solid #eef0f3}
52
+ tr.sum td{font-weight:700;border-top:2px solid #e3e6ea}
53
+ .step{display:flex;gap:10px;padding:7px 0;border-bottom:1px dashed #eef0f3;font-size:13.5px;align-items:baseline}
54
+ .step .n{color:#8a93a0;font-weight:700}.step .role{font-weight:600;min-width:88px}
55
+ .step .who{color:#5a6472;min-width:90px}.step .sum{flex:1}.st{font-size:12px}
56
+ .st.done{color:#177245}.st.failed{color:#b42318}
57
+ h1,h2,h3{margin:14px 0 8px}li{margin:4px 0}.trow{padding:2px 0;border-bottom:1px dotted #eee}
58
+ p{margin:8px 0}.mut{color:#8a93a0}code{background:#f0f2f5;padding:1px 6px;border-radius:4px}
59
+ pre{background:#f0f2f5;padding:12px;border-radius:8px;overflow-x:auto;white-space:pre-wrap}
60
+ </style></head><body><div class="wrap">
61
+ <div class="head"><h1>__TITLE__</h1>
62
+ <div class="meta">__META__ · __ST__ · CodeBee 生成于 __NOW__</div></div>
63
+ <div class="card"><h2>结果</h2><span class="badge __STCLS__">__ST__</span>__OVERALL__</div>
64
+ <div class="card"><h2>步骤</h2>__STEPS__</div>
65
+ <div class="card"><h2>报告</h2>__REPORT__</div>
66
+ <div class="meta">由 <b>CodeBee</b> 多智能体编排台生成</div>
67
+ </div></body></html>"""
68
+
69
+
70
+ def render_share_html(run, task, report_text):
71
+ """渲染自包含分享页。run/task/report_text 缺失时优雅降级。"""
72
+ run = run or {}
73
+ task = task or {}
74
+ status = str(run.get("status") or "")
75
+ st_label = {"done": "已完成", "failed": "失败", "cancelled": "已取消",
76
+ "running": "进行中"}.get(status, status)
77
+ st_cls = {"done": "ok", "failed": "bad", "cancelled": "off"}.get(status, "off")
78
+ verdict = run.get("verdict") or {}
79
+ means = verdict.get("scores") or {}
80
+
81
+ score_rows = ""
82
+ for d, v in means.items():
83
+ score_rows += "<tr><td>%s</td><td>%.1f</td></tr>" % (_esc(d), float(v))
84
+ if verdict:
85
+ score_rows += ('<tr class="sum"><td>综合</td>'
86
+ '<td>%.1f</td></tr>' % float(verdict.get("overall") or 0))
87
+
88
+ steps_rows = ""
89
+ for s in run.get("steps") or []:
90
+ who = s.get("agent_label") or s.get("agent") or ""
91
+ if s.get("model"):
92
+ who += " · " + str(s["model"])
93
+ steps_rows += (
94
+ '<div class="step"><span class="n">%02d</span>'
95
+ '<span class="role">%s</span><span class="who">%s</span>'
96
+ '<span class="sum">%s</span><span class="st %s">%s</span></div>'
97
+ % (s.get("n") or 0, _esc(s.get("role") or ""),
98
+ _esc(who),
99
+ _esc((s.get("summary") or "")[:220]), _esc(s.get("status") or ""),
100
+ _esc(s.get("status") or "")))
101
+
102
+ report_html = _md_ish(report_text) if report_text else "<p class='mut'>(暂无报告)</p>"
103
+ overall_note = ("综合 %.1f 分" % float(verdict.get("overall"))
104
+ if verdict.get("overall") is not None else "")
105
+
106
+ return (_SHARE_TPL
107
+ .replace("__TITLE__", _esc(task.get("title") or run.get("title") or "任务报告"))
108
+ .replace("__META__", _esc(task.get("goal") or ""))
109
+ .replace("__ST__", _esc(st_label))
110
+ .replace("__STCLS__", st_cls)
111
+ .replace("__NOW__", _esc(time.strftime("%Y-%m-%d %H:%M")))
112
+ .replace("__OVERALL__", _esc(overall_note))
113
+ .replace("__STEPS__", steps_rows or "<p class='mut'>(无步骤)</p>")
114
+ .replace("__REPORT__", report_html))
@@ -1,139 +1,139 @@
1
- # -*- coding: utf-8 -*-
2
- """skill 装前危险模式扫描(借鉴 NVIDIA SkillSpector 的静态扫描思路)。
3
-
4
- 研究数据(SkillSpector 对 31,132 个 skill 的分析):26.1% 含漏洞、5.2% 疑似
5
- 恶意。我们在「白名单闸门 + SSRF 防护 + 剥离式检查」之外补一道**内容静态扫描**:
6
- 装前扫 skill 正文里的危险模式,给风险提示——提示不是拦阻(用户仍可装),
7
- 但危险必须被看见。
8
-
9
- 纯内存函数:输入是文本,输出是发现列表,无网络无落盘。
10
- """
11
- from __future__ import annotations
12
-
13
- import re
14
-
15
- # 危险模式(静态正则;命中即在装前提示行展示)
16
- # —— 每条:(模式, 类别, 中文说明)
17
- _PATTERNS = [
18
- # 代码执行
19
- (r"\beval\s*\(", "代码执行", "动态 eval 执行任意代码"),
20
- (r"\bexec\s*\(", "代码执行", "exec 执行任意代码"),
21
- (r"subprocess|os\.system|Popen", "代码执行", "起子进程执行命令"),
22
- (r"child_process", "代码执行", "Node.js 子进程(可能执行任意命令)"),
23
- (r"(?:curl|wget)[^\n|]*\|\s*(?:ba|z|da)?sh\b", "代码执行",
24
- "下载内容直接管道进 shell 执行(dropper 特征)"),
25
- (r"Invoke-Expression|\biex\s*\(|DownloadString", "代码执行",
26
- "PowerShell 下载执行(dropper 特征)"),
27
- # 数据外发
28
- (r"https?://(?!api\.|docs\.|github\.com|raw\.githubusercontent)[a-z0-9.-]+/(upload|collect|track|ingest|webhook|callback)",
29
- "数据外发", "向非常规端点上传/回调数据"),
30
- (r"requests\.post|urllib\.request|fetch\s*\(", "网络请求", "发起网络请求(确认目标可信)"),
31
- (r"base64.{0,10}(decode|b64decode|atob)", "数据外发",
32
- "base64 解码(可能隐藏混淆载荷)"),
33
- (r"pastebin\.com|webhook\.site|requestbin|pipedream\.net|"
34
- r"ngrok\.(io|app|dev)|trycloudflare\.com", "数据外发",
35
- "常见外传/中转信道(pastebin、ngrok 隧道、webhook.site 等)"),
36
- # 持久化与挖矿(治理巡检 09-24 补:装后驻留与资源盗用的静态特征)
37
- (r"\bcrontab\b|schtasks|LaunchAgents|CurrentVersion\\Run|StartupItems",
38
- "持久化", "注册定时任务/自启动项(持久化驻留特征)"),
39
- (r"stratum\+tcp|xmrig|cryptonight", "可疑意图", "加密货币挖矿特征"),
40
- # 云元数据/内网端点探测(批4 治理 09-25:169.254.169.254 窃取云凭据是
41
- # 真实攻击面,此前零覆盖)。只认高信号形态:链路本地元数据地址/云元数据
42
- # 主机名,或私网地址搭配凭据路径——本地起服务提 127.0.0.1:3000 不误报。
43
- (r"169\.254\.169\.254|169\.254\.\d{1,3}\.\d{1,3}|metadata\.google\.internal",
44
- "可疑意图", "触碰云元数据端点(窃取云凭据特征)"),
45
- (r"(?:192\.168\.\d{1,3}\.\d{1,3}|10\.\d{1,3}\.\d{1,3}\.\d{1,3})[^。\n]{0,40}"
46
- r"(?:meta-data|credentials|secret|token|\.ssh)",
47
- "可疑意图", "私网地址搭配凭据路径(内网探测特征)"),
48
- # 敏感信息读取
49
- (r"os\.environ|process\.env|getenv", "环境读取", "读取环境变量(可能带走密钥)"),
50
- (r"\.ssh/|\.aws/|\.npmrc|\.gitconfig|credentials|\.env\b", "敏感文件", "触碰凭据/密钥文件路径"),
51
- (r"keychain|credential manager|dpapi", "敏感文件", "访问系统凭据库"),
52
- (r"\.claude/|\.zcode/|\.kimi-code/|\.codebee/", "敏感文件",
53
- "触碰 AI 助手配置目录(可能篡改系统提示词或模型绑定)"),
54
- # 提示注入特征
55
- (r"(ignore|disregard|forget).{0,30}(previous|above|prior|all).{0,20}(instruction|prompt|rule)",
56
- "提示注入", "指令覆盖话术(试图无视既有规则)"),
57
- (r"(?:无视|忽略|跳过|忘记)[^。\n]{0,8}(?:之前|以上|前面|上述)[^。\n]{0,6}(?:指令|规则|要求|设定|约束)",
58
- "提示注入", "中文指令覆盖话术(试图无视既有规则)"),
59
- (r"system prompt|开发者指令|隐藏指令|系统提示词", "提示注入", "提及系统提示词/隐藏指令"),
60
- (r"do not (tell|reveal|mention).{0,20}(user|human|player)", "提示注入", "要求对用户隐瞒行为"),
61
- (r"(?:不要|切勿|别)[^。\n]{0,6}(?:告诉|透露|提及|说明|隐瞒)[^。\n]{0,8}(?:用户|主人|玩家)"
62
- r"|(?:不要|切勿|别)[^。\n]{0,6}(?:用户|主人|玩家)[^。\n]{0,6}(?:隐瞒|透露|告诉|说明)"
63
- r"|对(?:用户|主人|玩家)隐瞒",
64
- "提示注入", "中文话术要求对用户隐瞒行为"),
65
- # 反拒答/越权
66
- (r"(you (are|must) (now|act as)|从此你是|你现在必须"
67
- r"|从现在起你(?:是|扮演|成为|要[^。\n]{0,4}服从)|请你扮演)",
68
- "越权人格", "试图重设助手人格"),
69
- # SkillSpector 规则对表补充(0929 第四轮:AR/OH/TR 三族缺口)
70
- (r"(do not|don't|never|不用|无需|不必)[^\n]{0,14}"
71
- r"(refuse|decline|reject|reject)|(?:拒绝|推辞)[^\n]{0,6}(?:是)?(?:禁止|不允许|违规)"
72
- r"|you (?:will|must) (?:always|never fail to) comply",
73
- "提示注入", "反拒答抑制(试图关掉模型的拒绝能力)"),
74
- (r"(omit|skip|remove)[^\n]{0,16}(disclaimer|warning|safety)"
75
- r"|(?:省略|跳过|不要加|去掉)[^\n]{0,10}(?:免责|声明|安全(?:提示|警告|策略))",
76
- "提示注入", "免责/安全声明抑制"),
77
- (r"(?:your|the) (?:output|response|answer)[^\n]{0,30}"
78
- r"(?:will be|is) (?:executed|run|evaluated as (?:code|commands?))"
79
- r"|(?:输出|回答)(?:会|将)[^\n]{0,12}(?:被)?(?:直接)?(?:执行|当作命令|作为代码)",
80
- "数据外发", "输出即执行指示(作答将被当命令跑——OH1 输出注入)"),
81
- (r"(?:keyword|trigger|关键词|触发)[^\n]{0,50}"
82
- r"(?:any|every|all|任何|所有|一切)|"
83
- r"(?:any|every|all|任何|所有|一切)[^\n]{0,30}"
84
- r"(?:keyword|trigger|关键词|触发)",
85
- "可疑意图", "过宽触发条件(任何输入都激活——TR1 触发滥用)"),
86
- (r"exfiltrat|渗透|后门|backdoor|keylog", "可疑意图", "包含可疑渗透/后门词汇"),
87
- ]
88
-
89
- _COMPILED = [(re.compile(p, re.I), cat, desc) for p, cat, desc in _PATTERNS]
90
-
91
-
92
- def scan_text(text, max_findings=12):
93
- """扫描一段 skill 文本。返回 [{category, detail, line}];空列表=干净。
94
-
95
- line 是 1 起的行号(供装前提示定位)。同一类别只报首个命中
96
- (提示行是给人看的,重复刷屏没有信息量)。"""
97
- findings, seen_cats = [], set()
98
- if not text:
99
- return []
100
- lines = text.splitlines()
101
- for rx, cat, desc in _COMPILED:
102
- if cat in seen_cats:
103
- continue
104
- for i, ln in enumerate(lines, 1):
105
- if rx.search(ln):
106
- findings.append({"category": cat, "detail": desc, "line": i})
107
- seen_cats.add(cat)
108
- break
109
- if len(findings) >= max_findings:
110
- break
111
- return findings
112
-
113
-
114
- def risk_label(findings):
115
- """发现列表 → 风险标签(装前提示行用)。
116
-
117
- 三级:高危(代码执行/敏感文件/可疑意图/数据外发/持久化)任一
118
- 命中 = 高风险;中危类(网络请求/环境读取/提示注入/越权人格)≥2 类
119
- 同时命中 = 中风险;有发现 = 注意;空 = 干净。"""
120
- if not findings:
121
- return ""
122
- cats = {f["category"] for f in findings}
123
- if cats & {"代码执行", "敏感文件", "可疑意图", "数据外发", "持久化"}:
124
- return "⚠ 高风险"
125
- medium_cats = cats & {"网络请求", "环境读取", "提示注入", "越权人格"}
126
- if len(medium_cats) >= 2:
127
- return "⚠ 中风险"
128
- return "△ 注意"
129
-
130
-
131
- def scan_summary(text):
132
- """一步到位:扫描+汇总成一行提示文案(空=干净返回空串)。"""
133
- fs = scan_text(text)
134
- if not fs:
135
- return ""
136
- label = risk_label(fs)
137
- top = "、".join("%s(行%d)" % (f["category"], f["line"]) for f in fs[:4])
138
- more = " 等 %d 项" % len(fs) if len(fs) > 4 else ""
139
- return "%s:%s%s" % (label, top, more)
1
+ # -*- coding: utf-8 -*-
2
+ """skill 装前危险模式扫描(借鉴 NVIDIA SkillSpector 的静态扫描思路)。
3
+
4
+ 研究数据(SkillSpector 对 31,132 个 skill 的分析):26.1% 含漏洞、5.2% 疑似
5
+ 恶意。我们在「白名单闸门 + SSRF 防护 + 剥离式检查」之外补一道**内容静态扫描**:
6
+ 装前扫 skill 正文里的危险模式,给风险提示——提示不是拦阻(用户仍可装),
7
+ 但危险必须被看见。
8
+
9
+ 纯内存函数:输入是文本,输出是发现列表,无网络无落盘。
10
+ """
11
+ from __future__ import annotations
12
+
13
+ import re
14
+
15
+ # 危险模式(静态正则;命中即在装前提示行展示)
16
+ # —— 每条:(模式, 类别, 中文说明)
17
+ _PATTERNS = [
18
+ # 代码执行
19
+ (r"\beval\s*\(", "代码执行", "动态 eval 执行任意代码"),
20
+ (r"\bexec\s*\(", "代码执行", "exec 执行任意代码"),
21
+ (r"subprocess|os\.system|Popen", "代码执行", "起子进程执行命令"),
22
+ (r"child_process", "代码执行", "Node.js 子进程(可能执行任意命令)"),
23
+ (r"(?:curl|wget)[^\n|]*\|\s*(?:ba|z|da)?sh\b", "代码执行",
24
+ "下载内容直接管道进 shell 执行(dropper 特征)"),
25
+ (r"Invoke-Expression|\biex\s*\(|DownloadString", "代码执行",
26
+ "PowerShell 下载执行(dropper 特征)"),
27
+ # 数据外发
28
+ (r"https?://(?!api\.|docs\.|github\.com|raw\.githubusercontent)[a-z0-9.-]+/(upload|collect|track|ingest|webhook|callback)",
29
+ "数据外发", "向非常规端点上传/回调数据"),
30
+ (r"requests\.post|urllib\.request|fetch\s*\(", "网络请求", "发起网络请求(确认目标可信)"),
31
+ (r"base64.{0,10}(decode|b64decode|atob)", "数据外发",
32
+ "base64 解码(可能隐藏混淆载荷)"),
33
+ (r"pastebin\.com|webhook\.site|requestbin|pipedream\.net|"
34
+ r"ngrok\.(io|app|dev)|trycloudflare\.com", "数据外发",
35
+ "常见外传/中转信道(pastebin、ngrok 隧道、webhook.site 等)"),
36
+ # 持久化与挖矿(治理巡检 09-24 补:装后驻留与资源盗用的静态特征)
37
+ (r"\bcrontab\b|schtasks|LaunchAgents|CurrentVersion\\Run|StartupItems",
38
+ "持久化", "注册定时任务/自启动项(持久化驻留特征)"),
39
+ (r"stratum\+tcp|xmrig|cryptonight", "可疑意图", "加密货币挖矿特征"),
40
+ # 云元数据/内网端点探测(批4 治理 09-25:169.254.169.254 窃取云凭据是
41
+ # 真实攻击面,此前零覆盖)。只认高信号形态:链路本地元数据地址/云元数据
42
+ # 主机名,或私网地址搭配凭据路径——本地起服务提 127.0.0.1:3000 不误报。
43
+ (r"169\.254\.169\.254|169\.254\.\d{1,3}\.\d{1,3}|metadata\.google\.internal",
44
+ "可疑意图", "触碰云元数据端点(窃取云凭据特征)"),
45
+ (r"(?:192\.168\.\d{1,3}\.\d{1,3}|10\.\d{1,3}\.\d{1,3}\.\d{1,3})[^。\n]{0,40}"
46
+ r"(?:meta-data|credentials|secret|token|\.ssh)",
47
+ "可疑意图", "私网地址搭配凭据路径(内网探测特征)"),
48
+ # 敏感信息读取
49
+ (r"os\.environ|process\.env|getenv", "环境读取", "读取环境变量(可能带走密钥)"),
50
+ (r"\.ssh/|\.aws/|\.npmrc|\.gitconfig|credentials|\.env\b", "敏感文件", "触碰凭据/密钥文件路径"),
51
+ (r"keychain|credential manager|dpapi", "敏感文件", "访问系统凭据库"),
52
+ (r"\.claude/|\.zcode/|\.kimi-code/|\.codebee/", "敏感文件",
53
+ "触碰 AI 助手配置目录(可能篡改系统提示词或模型绑定)"),
54
+ # 提示注入特征
55
+ (r"(ignore|disregard|forget).{0,30}(previous|above|prior|all).{0,20}(instruction|prompt|rule)",
56
+ "提示注入", "指令覆盖话术(试图无视既有规则)"),
57
+ (r"(?:无视|忽略|跳过|忘记)[^。\n]{0,8}(?:之前|以上|前面|上述)[^。\n]{0,6}(?:指令|规则|要求|设定|约束)",
58
+ "提示注入", "中文指令覆盖话术(试图无视既有规则)"),
59
+ (r"system prompt|开发者指令|隐藏指令|系统提示词", "提示注入", "提及系统提示词/隐藏指令"),
60
+ (r"do not (tell|reveal|mention).{0,20}(user|human|player)", "提示注入", "要求对用户隐瞒行为"),
61
+ (r"(?:不要|切勿|别)[^。\n]{0,6}(?:告诉|透露|提及|说明|隐瞒)[^。\n]{0,8}(?:用户|主人|玩家)"
62
+ r"|(?:不要|切勿|别)[^。\n]{0,6}(?:用户|主人|玩家)[^。\n]{0,6}(?:隐瞒|透露|告诉|说明)"
63
+ r"|对(?:用户|主人|玩家)隐瞒",
64
+ "提示注入", "中文话术要求对用户隐瞒行为"),
65
+ # 反拒答/越权
66
+ (r"(you (are|must) (now|act as)|从此你是|你现在必须"
67
+ r"|从现在起你(?:是|扮演|成为|要[^。\n]{0,4}服从)|请你扮演)",
68
+ "越权人格", "试图重设助手人格"),
69
+ # SkillSpector 规则对表补充(0929 第四轮:AR/OH/TR 三族缺口)
70
+ (r"(do not|don't|never|不用|无需|不必)[^\n]{0,14}"
71
+ r"(refuse|decline|reject|reject)|(?:拒绝|推辞)[^\n]{0,6}(?:是)?(?:禁止|不允许|违规)"
72
+ r"|you (?:will|must) (?:always|never fail to) comply",
73
+ "提示注入", "反拒答抑制(试图关掉模型的拒绝能力)"),
74
+ (r"(omit|skip|remove)[^\n]{0,16}(disclaimer|warning|safety)"
75
+ r"|(?:省略|跳过|不要加|去掉)[^\n]{0,10}(?:免责|声明|安全(?:提示|警告|策略))",
76
+ "提示注入", "免责/安全声明抑制"),
77
+ (r"(?:your|the) (?:output|response|answer)[^\n]{0,30}"
78
+ r"(?:will be|is) (?:executed|run|evaluated as (?:code|commands?))"
79
+ r"|(?:输出|回答)(?:会|将)[^\n]{0,12}(?:被)?(?:直接)?(?:执行|当作命令|作为代码)",
80
+ "数据外发", "输出即执行指示(作答将被当命令跑——OH1 输出注入)"),
81
+ (r"(?:keyword|trigger|关键词|触发)[^\n]{0,50}"
82
+ r"(?:any|every|all|任何|所有|一切)|"
83
+ r"(?:any|every|all|任何|所有|一切)[^\n]{0,30}"
84
+ r"(?:keyword|trigger|关键词|触发)",
85
+ "可疑意图", "过宽触发条件(任何输入都激活——TR1 触发滥用)"),
86
+ (r"exfiltrat|渗透|后门|backdoor|keylog", "可疑意图", "包含可疑渗透/后门词汇"),
87
+ ]
88
+
89
+ _COMPILED = [(re.compile(p, re.I), cat, desc) for p, cat, desc in _PATTERNS]
90
+
91
+
92
+ def scan_text(text, max_findings=12):
93
+ """扫描一段 skill 文本。返回 [{category, detail, line}];空列表=干净。
94
+
95
+ line 是 1 起的行号(供装前提示定位)。同一类别只报首个命中
96
+ (提示行是给人看的,重复刷屏没有信息量)。"""
97
+ findings, seen_cats = [], set()
98
+ if not text:
99
+ return []
100
+ lines = text.splitlines()
101
+ for rx, cat, desc in _COMPILED:
102
+ if cat in seen_cats:
103
+ continue
104
+ for i, ln in enumerate(lines, 1):
105
+ if rx.search(ln):
106
+ findings.append({"category": cat, "detail": desc, "line": i})
107
+ seen_cats.add(cat)
108
+ break
109
+ if len(findings) >= max_findings:
110
+ break
111
+ return findings
112
+
113
+
114
+ def risk_label(findings):
115
+ """发现列表 → 风险标签(装前提示行用)。
116
+
117
+ 三级:高危(代码执行/敏感文件/可疑意图/数据外发/持久化)任一
118
+ 命中 = 高风险;中危类(网络请求/环境读取/提示注入/越权人格)≥2 类
119
+ 同时命中 = 中风险;有发现 = 注意;空 = 干净。"""
120
+ if not findings:
121
+ return ""
122
+ cats = {f["category"] for f in findings}
123
+ if cats & {"代码执行", "敏感文件", "可疑意图", "数据外发", "持久化"}:
124
+ return "⚠ 高风险"
125
+ medium_cats = cats & {"网络请求", "环境读取", "提示注入", "越权人格"}
126
+ if len(medium_cats) >= 2:
127
+ return "⚠ 中风险"
128
+ return "△ 注意"
129
+
130
+
131
+ def scan_summary(text):
132
+ """一步到位:扫描+汇总成一行提示文案(空=干净返回空串)。"""
133
+ fs = scan_text(text)
134
+ if not fs:
135
+ return ""
136
+ label = risk_label(fs)
137
+ top = "、".join("%s(行%d)" % (f["category"], f["line"]) for f in fs[:4])
138
+ more = " 等 %d 项" % len(fs) if len(fs) > 4 else ""
139
+ return "%s:%s%s" % (label, top, more)
@@ -12,6 +12,8 @@
12
12
  - **C级:单个案例、固定字数或传闻算法权重**:不作硬门槛,不宣称推荐、签约或收入因果;没有样本就保留为待验证。
13
13
  - 质量报告按“文本质量 → 平台适配 → 当前政策”分层。每个结论都给出证据位置、未知项和可逆改动;完读率、追读率等数字是定位线索,不是文学评分。
14
14
 
15
+ 先确认“不过”指内容/合规审核、建书校验、签约评估、章节发布还是读者数据表现。没有平台明确原文时,报告只能叫内部文本诊断;经验不能证明审核原因或推荐算法。大纲和修改建议不得把固定字数、黄金三章、每章爽点/钩子、危机开局等当硬条件。按具体作品与目标读者评估承诺兑现、人物选择、因果、情绪和叙事节奏,允许有功能的慢热、群像、安静章节和多种情绪回报。
16
+
15
17
  ### 番茄与通用质量底线
16
18
 
17
19
  先检查具体事件是否触发主角主动选择,并产生可见后果、阶段性兑现和新的问题;再检查人物动机、因果连续性、文风一致、移动端可读性与内容安全。算法指标不能替代逐章阅读,也不能把“数据暂时好”写成质量已证实。
@@ -40,7 +42,7 @@
40
42
  - 世界观说明文、慢热日常、多视角群像和倒叙解谜可列为待验证风险;不能直接把某种写法归因成数据崩溃。
41
43
 
42
44
  ## 三、节奏与爽点
43
- - **每章应有可感知的变化、情绪波动或兑现,并留下可追问的下一步**;1800-2500 字可作为一次节奏实验的起点,按题材、章节目标和后台数据调整,**不作硬门槛**。
45
+ - 逐章检查叙事功能与阅读体验;“变化、情绪波动或兑现”是常见观察角度,不要求每章同时满足,也不要求章章以疑问/悬念收尾。1800-2500 字可作为节奏实验起点,按题材和章节目标调整,不作硬门槛。
44
46
  - 建议先用一句话说明主线目标和下一步;多线叙事、慢热铺垫可列为待验证风险,
45
47
  先用章节目标、读者反馈和后台分段数据复核,不预设结果。
46
48
  - 早期长线应安排一次完整的大兑现(打脸/升级/身份跃迁等),具体章节不固定;连续多个章节无兑现时,先回到事件、选择、后果链查找原因,不把数据变化直接归因于某个数字。
@@ -72,8 +74,8 @@
72
74
  文白/网络梗/书面长句不混用。
73
75
  - **流畅**:逐段读出声——长定语、多重倒装、连续同主语开头(她…她…她…)、动作与反应拆碎,
74
76
  卡顿处就地删改;一句一动作,段尾留半句承接。
75
- - **细节刻画力度**:每个爽点/反转标记"特写镜头",五感 + 微动作 + 环境反馈把爆发那几秒写厚,
76
- 铺垫在前、放大在中、余波在后;过渡章才可一笔带过。**"每章一小爽"不配特写等于没写**。
77
+ - **细节刻画力度**:重要情绪/转折是否按其叙事分量呈现。可使用特写、对白、动作、内心直述或留白;
78
+ 不要求所有爽点都扩写,也不为每章制造高潮。检查问题必须由实际文本支持。
77
79
 
78
80
  ## 八、后台数据诊断卡(仅在样本足够时使用)
79
81
 
@@ -88,9 +90,9 @@
88
90
 
89
91
  ## 九、开书/投稿前自检清单
90
92
  - [ ] 书名/标签/简介一致表达题材,分类挂对
91
- - [ ] 第 1 章前 100 字冲突进场;前三章 = 钩子 + 设定兑现 + 完整爽点闭环
92
- - [ ] 每章有可感知的变化/情绪或兑现,章尾留下可追问的问题;字数仅作节奏实验,不作硬门槛
93
- - [ ] 主线一句话讲得清,单线推进,无慢热铺垫章节
93
+ - [ ] 开篇是否尽早兑现作品承诺(具体位置随题材调整);前三章是否让读者理解故事方向并得到相称回报,不强制同一节拍模板
94
+ - [ ] 每章叙事功能清楚,章节收束方式适合当前节奏;字数仅作节奏实验,不作硬门槛
95
+ - [ ] 主线和近期方向可复述;多线/慢热铺垫是否有清楚功能,避免无效延宕
94
96
  - [ ] 早期长线有一次大兑现闭环的规划(章节位置可调整)
95
97
  - [ ] 存稿和日更承诺可持续,并已核对当前合同/后台(不套用固定数字)
96
98
  - [ ] 文笔三词(风格统一/流畅/细节力度)逐章自查过