@bolloon/bolloon-agent 0.1.34 → 0.1.36

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 (226) hide show
  1. package/.auto-evolve-calls +1 -0
  2. package/.last-auto-evolve-baseline +1 -0
  3. package/.playwright-mcp/page-2026-06-16T07-51-45-706Z.yml +130 -0
  4. package/.playwright-mcp/page-2026-06-16T07-56-44-116Z.yml +131 -0
  5. package/Bolloon.md +144 -0
  6. package/Dive-into/CITATION.cff +17 -0
  7. package/Dive-into/LICENSE +25 -0
  8. package/Dive-into/README.md +598 -0
  9. package/Dive-into/README_zh.md +599 -0
  10. package/Dive-into/assets/context.png +0 -0
  11. package/Dive-into/assets/extensibility.png +0 -0
  12. package/Dive-into/assets/iteration.png +0 -0
  13. package/Dive-into/assets/layered_architecture.png +0 -0
  14. package/Dive-into/assets/main_structure.png +0 -0
  15. package/Dive-into/assets/permission.png +0 -0
  16. package/Dive-into/assets/session_compact.png +0 -0
  17. package/Dive-into/assets/subagent.png +0 -0
  18. package/Dive-into/paper/Dive_into_Claude_Code.pdf +0 -0
  19. package/README.md +1 -1
  20. package/dist/agents/p2p-chat-tools.js +6 -6
  21. package/dist/agents/permission-mode.js +115 -0
  22. package/dist/agents/pi-sdk.js +687 -25
  23. package/dist/agents/pre-tool-validator.js +194 -0
  24. package/dist/agents/workflow-pivot-loop.js +113 -12
  25. package/dist/bollharness/src/scripts/checks/check_doc_freshness.js +1 -1
  26. package/dist/bollharness/src/scripts/checks/check_doc_links.js +1 -1
  27. package/dist/bollharness/src/scripts/context_router.js +1 -1
  28. package/dist/bollharness/src/scripts/deploy-guard.js +1 -1
  29. package/dist/bollharness/src/scripts/guard_router.js +1 -1
  30. package/dist/bollharness/src/scripts/hooks/_hook_output.js +1 -1
  31. package/dist/bollharness/src/scripts/hooks/risk-tracker.js +1 -1
  32. package/dist/bollharness-integration/context-router.js +2 -2
  33. package/dist/bollharness-integration/guard-checker.js +1 -1
  34. package/dist/bootstrap/bootstrap.js +117 -0
  35. package/dist/bootstrap/context-collector.js +312 -0
  36. package/dist/bootstrap/context-hierarchy.js +218 -0
  37. package/dist/bootstrap/lifecycle-hooks.js +171 -0
  38. package/dist/bootstrap/project-context.js +158 -0
  39. package/dist/context-compaction/auto-compact.js +144 -0
  40. package/dist/context-compaction/budget-gate.js +28 -0
  41. package/dist/context-compaction/budget-reduce.js +35 -0
  42. package/dist/context-compaction/context-collapse.js +66 -0
  43. package/dist/context-compaction/index.js +21 -0
  44. package/dist/context-compaction/microcompact.js +51 -0
  45. package/dist/context-compaction/pipeline.js +123 -0
  46. package/dist/context-compaction/snip.js +45 -0
  47. package/dist/context-compaction/token-estimator.js +35 -0
  48. package/dist/context-compaction/types.js +19 -0
  49. package/dist/heartbeat/HealthMonitor.js +3 -2
  50. package/dist/index.js +49 -2
  51. package/dist/llm/llm-judgment-client.js +32 -30
  52. package/dist/llm/pi-ai.js +125 -28
  53. package/dist/llm/system-prompt/health.js +129 -0
  54. package/dist/llm/system-prompt/registry.js +246 -0
  55. package/dist/llm/system-prompt/strip-hibsml.js +51 -0
  56. package/dist/llm/tool-manifest/ask_user_input.js +35 -0
  57. package/dist/llm/tool-manifest/bash.js +23 -0
  58. package/dist/llm/tool-manifest/create_file.js +24 -0
  59. package/dist/llm/tool-manifest/fetch_sports_data.js +26 -0
  60. package/dist/llm/tool-manifest/image_search.js +24 -0
  61. package/dist/llm/tool-manifest/index.js +69 -0
  62. package/dist/llm/tool-manifest/mcp.js +43 -0
  63. package/dist/llm/tool-manifest/message_compose.js +31 -0
  64. package/dist/llm/tool-manifest/places.js +83 -0
  65. package/dist/llm/tool-manifest/present_files.js +21 -0
  66. package/dist/llm/tool-manifest/recipe.js +40 -0
  67. package/dist/llm/tool-manifest/recommend_apps.js +23 -0
  68. package/dist/llm/tool-manifest/str_replace.js +27 -0
  69. package/dist/llm/tool-manifest/types.js +7 -0
  70. package/dist/llm/tool-manifest/view.js +24 -0
  71. package/dist/llm/tool-manifest/weather.js +27 -0
  72. package/dist/llm/tool-manifest/web.js +51 -0
  73. package/dist/network/p2p-direct.js +23 -0
  74. package/dist/network/source-intent-broadcaster.js +203 -0
  75. package/dist/network/source-intent.js +100 -0
  76. package/dist/pi-ecosystem-judgment/adaptive-scan.js +279 -0
  77. package/dist/pi-ecosystem-judgment/causal-judge.js +449 -0
  78. package/dist/pi-ecosystem-judgment/detect-hook.js +168 -0
  79. package/dist/pi-ecosystem-judgment/distill-prompt.js +226 -0
  80. package/dist/pi-ecosystem-judgment/evolve-judgment.js +170 -0
  81. package/dist/pi-ecosystem-judgment/human-value-pipeline.js +21 -0
  82. package/dist/pi-ecosystem-judgment/human-value-store.js +283 -22
  83. package/dist/pi-ecosystem-judgment/injection-gate.js +208 -0
  84. package/dist/pi-ecosystem-judgment/monitor-gate.js +188 -0
  85. package/dist/pi-ecosystem-judgment/value-injection.js +8 -2
  86. package/dist/security/builtin-guards.js +124 -0
  87. package/dist/security/context-router-tool.js +106 -0
  88. package/dist/security/input-scanner.js +223 -0
  89. package/dist/security/react-harness.js +143 -0
  90. package/dist/security/tool-gate.js +235 -0
  91. package/dist/utils/auto-evolve-policy.js +117 -0
  92. package/dist/utils/clamp.js +7 -0
  93. package/dist/utils/double.js +6 -0
  94. package/dist/web/client.js +3810 -3830
  95. package/dist/web/components/p2p/P2PModal.js +188 -0
  96. package/dist/web/components/p2p/index.js +264 -226
  97. package/dist/web/components/p2p/p2p-modal.js +657 -0
  98. package/dist/web/components/p2p/p2p-tools.js +248 -0
  99. package/dist/web/index.html +60 -49
  100. package/dist/web/server.js +827 -124
  101. package/dist/web/style.css +531 -249
  102. package/dist/web/ui/message-renderer.js +463 -0
  103. package/dist/web/ui/step-timeline.js +375 -0
  104. package/lefthook.yml +33 -0
  105. package/package.json +3 -2
  106. package/scripts/auto-evolve-loop.ts +481 -0
  107. package/scripts/auto-evolve-oneshot.sh +155 -0
  108. package/scripts/auto-evolve-snapshot.sh +136 -0
  109. package/scripts/build-web.ts +35 -1
  110. package/scripts/detect-schema-changes.sh +48 -0
  111. package/scripts/diff-reviewer.ts +159 -0
  112. package/scripts/validate-system-prompt.ts +142 -0
  113. package/scripts/weekly-report.ts +364 -0
  114. package/src/agents/p2p-chat-tools.ts +6 -6
  115. package/src/agents/permission-mode.ts +127 -0
  116. package/src/agents/pi-sdk.ts +741 -30
  117. package/src/agents/pre-tool-validator.ts +213 -0
  118. package/src/agents/workflow-pivot-loop.ts +110 -19
  119. package/src/bollharness/CLAUDE.md +1 -1
  120. package/src/bollharness/README.md +2 -2
  121. package/src/bollharness/README.zh-CN.md +2 -2
  122. package/src/bollharness/reference/boll-reference/scripts/hooks/find-boll-root.sh +2 -2
  123. package/src/bollharness/scripts/context-fragments/truth-source-hierarchy.md +2 -2
  124. package/src/bollharness/scripts/context-fragments/version-sources.md +1 -1
  125. package/src/bollharness/scripts/hooks/find-project-root.sh +4 -4
  126. package/src/bollharness/src/scripts/checks/check_doc_freshness.ts +1 -1
  127. package/src/bollharness/src/scripts/checks/check_doc_links.ts +1 -1
  128. package/src/bollharness/src/scripts/context_router.ts +1 -1
  129. package/src/bollharness/src/scripts/deploy-guard.ts +1 -1
  130. package/src/bollharness/src/scripts/guard_router.ts +1 -1
  131. package/src/bollharness/src/scripts/hooks/_hook_output.ts +1 -1
  132. package/src/bollharness/src/scripts/hooks/risk-tracker.ts +1 -1
  133. package/src/bollharness/templates/scaffold/.gitignore.append +1 -1
  134. package/src/bollharness/templates/scaffold/CLAUDE.md +2 -2
  135. package/src/bollharness-integration/context-router.ts +2 -2
  136. package/src/bollharness-integration/guard-checker.ts +1 -1
  137. package/src/bootstrap/bootstrap.ts +135 -0
  138. package/src/bootstrap/context-collector.ts +371 -0
  139. package/src/bootstrap/context-hierarchy.ts +283 -0
  140. package/src/bootstrap/lifecycle-hooks.ts +289 -0
  141. package/src/bootstrap/project-context.ts +171 -0
  142. package/src/context-compaction/auto-compact.ts +153 -0
  143. package/src/context-compaction/budget-gate.ts +32 -0
  144. package/src/context-compaction/budget-reduce.ts +37 -0
  145. package/src/context-compaction/context-collapse.ts +72 -0
  146. package/src/context-compaction/index.ts +24 -0
  147. package/src/context-compaction/microcompact.ts +54 -0
  148. package/src/context-compaction/pipeline.ts +133 -0
  149. package/src/context-compaction/snip.ts +51 -0
  150. package/src/context-compaction/token-estimator.ts +36 -0
  151. package/src/context-compaction/types.ts +99 -0
  152. package/src/heartbeat/HealthMonitor.ts +3 -2
  153. package/src/index.ts +47 -2
  154. package/src/llm/llm-judgment-client.ts +36 -35
  155. package/src/llm/pi-ai.ts +135 -29
  156. package/src/llm/system-prompt/health.ts +159 -0
  157. package/src/llm/system-prompt/layers/channel/local.md +14 -0
  158. package/src/llm/system-prompt/layers/channel/p2p-agent.md +18 -0
  159. package/src/llm/system-prompt/layers/channel/p2p-visitor.md +19 -0
  160. package/src/llm/system-prompt/layers/core/artifacts_storage.md +89 -0
  161. package/src/llm/system-prompt/layers/core/evenhandedness.md +21 -0
  162. package/src/llm/system-prompt/layers/core/hibs_reminders.md +15 -0
  163. package/src/llm/system-prompt/layers/core/identity.md +37 -0
  164. package/src/llm/system-prompt/layers/core/knowledge.md +17 -0
  165. package/src/llm/system-prompt/layers/core/memory_system.md +12 -0
  166. package/src/llm/system-prompt/layers/core/network_filesystem.md +28 -0
  167. package/src/llm/system-prompt/layers/core/refusal.md +37 -0
  168. package/src/llm/system-prompt/layers/core/tone.md +31 -0
  169. package/src/llm/system-prompt/layers/core/tools.thin.md +13 -0
  170. package/src/llm/system-prompt/layers/core/wellbeing.md +41 -0
  171. package/src/llm/system-prompt/layers/role/architect.md +20 -0
  172. package/src/llm/system-prompt/layers/role/expert.md +19 -0
  173. package/src/llm/system-prompt/layers/role/implementer.md +15 -0
  174. package/src/llm/system-prompt/layers/role/security.md +15 -0
  175. package/src/llm/system-prompt/layers/tool/artifacts.md +72 -0
  176. package/src/llm/system-prompt/layers/tool/bash.md +25 -0
  177. package/src/llm/system-prompt/layers/tool/hibs_api.md +171 -0
  178. package/src/llm/system-prompt/layers/tool/image_search.md +70 -0
  179. package/src/llm/system-prompt/layers/tool/manifest.md +89 -0
  180. package/src/llm/system-prompt/layers/tool/mcp_apps.md +53 -0
  181. package/src/llm/system-prompt/layers/tool/web_search.md +83 -0
  182. package/src/llm/system-prompt/registry.ts +325 -0
  183. package/src/llm/system-prompt/strip-hibsml.ts +52 -0
  184. package/src/llm/tool-manifest/ask_user_input.ts +37 -0
  185. package/src/llm/tool-manifest/bash.ts +25 -0
  186. package/src/llm/tool-manifest/create_file.ts +26 -0
  187. package/src/llm/tool-manifest/fetch_sports_data.ts +28 -0
  188. package/src/llm/tool-manifest/image_search.ts +26 -0
  189. package/src/llm/tool-manifest/index.ts +88 -0
  190. package/src/llm/tool-manifest/mcp.ts +46 -0
  191. package/src/llm/tool-manifest/message_compose.ts +33 -0
  192. package/src/llm/tool-manifest/places.ts +86 -0
  193. package/src/llm/tool-manifest/present_files.ts +23 -0
  194. package/src/llm/tool-manifest/recipe.ts +42 -0
  195. package/src/llm/tool-manifest/recommend_apps.ts +25 -0
  196. package/src/llm/tool-manifest/str_replace.ts +29 -0
  197. package/src/llm/tool-manifest/types.ts +52 -0
  198. package/src/llm/tool-manifest/view.ts +26 -0
  199. package/src/llm/tool-manifest/weather.ts +29 -0
  200. package/src/llm/tool-manifest/web.ts +54 -0
  201. package/src/network/p2p-direct.ts +22 -0
  202. package/src/network/source-intent-broadcaster.ts +242 -0
  203. package/src/network/source-intent.ts +167 -0
  204. package/src/security/builtin-guards.ts +162 -0
  205. package/src/security/context-router-tool.ts +122 -0
  206. package/src/security/input-scanner.ts +287 -0
  207. package/src/security/react-harness.ts +177 -0
  208. package/src/security/tool-gate.ts +294 -0
  209. package/src/utils/auto-evolve-policy.ts +138 -0
  210. package/src/utils/clamp.ts +5 -0
  211. package/src/web/client.js +105 -2187
  212. package/src/web/client.ts +4326 -0
  213. package/src/web/index.html +60 -49
  214. package/src/web/server.ts +894 -148
  215. package/src/web/style.css +531 -249
  216. package/src/web/ui/message-renderer.ts +540 -0
  217. package/src/web/ui/step-timeline.ts +394 -0
  218. package/staging/auto-evolve/clean-001/.review-verdict +9 -0
  219. package/staging/auto-evolve/clean-001/clean-001.patch +14 -0
  220. package/staging/auto-evolve/e2e-001/.patch-id +1 -0
  221. package/staging/auto-evolve/e2e-001/.review-verdict +12 -0
  222. package/staging/auto-evolve/e2e-001/e2e-001.patch +11 -0
  223. package/staging/auto-evolve/test-bad/.review-verdict +12 -0
  224. package/staging/auto-evolve/test-bad/test-bad.patch +11 -0
  225. package/test-results/.last-run.json +6 -0
  226. package/test-results/src-test-web-loop-status-b-5734c-atus-bar-/346/230/276/347/244/272-spinner-/344/270/215/346/230/276/347/244/272/345/276/252/347/216/257/350/256/241/346/225/260/error-context.md +285 -0
@@ -0,0 +1,136 @@
1
+ #!/bin/bash
2
+ # auto-evolve-snapshot.sh — 阶段 C 护栏 2 + 3
3
+ #
4
+ # 用法 (LLM 改源码前必调):
5
+ # bash scripts/auto-evolve-snapshot.sh # 打 baseline tag + 记当前 HEAD
6
+ # bash scripts/auto-evolve-snapshot.sh apply <patch-id> # 人类批准后合并 staging → main
7
+ # bash scripts/auto-evolve-snapshot.sh list # 列所有 baseline
8
+ # bash scripts/auto-evolve-snapshot.sh rollback <tag> # 回滚到指定 baseline
9
+ #
10
+ # 流程:
11
+ # 1. LLM 改之前调 snapshot: 当前 HEAD 打 auto-evolve-baseline-<ts> tag
12
+ # 2. LLM 改 staging/auto-evolve/<patch-id>/ (不进 src/)
13
+ # 3. 护栏 1 (lefthook) 跑 vitest + tsc, 坏就 abort
14
+ # 4. 护栏 4 (reviewer hook) 审 diff, 通过才准 apply
15
+ # 5. 人类调 apply: git apply staging/auto-evolve/<patch-id>/*.patch → src/
16
+ # 6. 出问题: 调 rollback → git reset --hard <tag>
17
+
18
+ set -euo pipefail
19
+
20
+ REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
21
+ cd "$REPO_ROOT"
22
+
23
+ STAGING_DIR="staging/auto-evolve"
24
+ TAG_PREFIX="auto-evolve-baseline-"
25
+
26
+ cmd="${1:-snapshot}"
27
+ patch_id="${2:-}"
28
+
29
+ case "$cmd" in
30
+ snapshot)
31
+ # 护栏 2: 打 baseline tag
32
+ if ! git diff --quiet HEAD 2>/dev/null; then
33
+ echo "❌ 有未提交改动. 先 git commit 或 git stash"
34
+ exit 1
35
+ fi
36
+ ts="$(date -u +%Y%m%dT%H%M%SZ)"
37
+ tag="${TAG_PREFIX}${ts}"
38
+ git tag -a "$tag" -m "auto-evolve baseline @ ${ts}" HEAD
39
+ echo "✅ baseline tag: $tag"
40
+ echo "$tag" > .last-auto-evolve-baseline
41
+ echo " 回滚命令: bash $0 rollback $tag"
42
+ ;;
43
+
44
+ prepare)
45
+ # LLM 改之前调: 创建 staging 目录
46
+ if [ -z "$patch_id" ]; then
47
+ echo "用法: $0 prepare <patch-id>"
48
+ exit 1
49
+ fi
50
+ mkdir -p "$STAGING_DIR/$patch_id"
51
+ echo "$patch_id" > "$STAGING_DIR/$patch_id/.patch-id"
52
+ echo "✅ staging 创建: $STAGING_DIR/$patch_id/"
53
+ echo " LLM 改完后把 patch 放这里: $STAGING_DIR/$patch_id/*.patch"
54
+ ;;
55
+
56
+ apply)
57
+ # 人类批准: 把 staging 的 patch 合并到 src/
58
+ if [ -z "$patch_id" ]; then
59
+ echo "用法: $0 apply <patch-id>"
60
+ exit 1
61
+ fi
62
+ patch_dir="$STAGING_DIR/$patch_id"
63
+ if [ ! -d "$patch_dir" ]; then
64
+ echo "❌ staging 不存在: $patch_dir"
65
+ exit 1
66
+ fi
67
+ # 必须先 snapshot
68
+ if [ ! -f .last-auto-evolve-baseline ]; then
69
+ echo "❌ 没有 baseline. 先跑: $0 snapshot"
70
+ exit 1
71
+ fi
72
+ baseline="$(cat .last-auto-evolve-baseline)"
73
+
74
+ # 应用所有 patch
75
+ applied=0
76
+ for p in "$patch_dir"/*.patch; do
77
+ [ -e "$p" ] || continue
78
+ echo " applying: $p"
79
+ if ! git apply --check "$p"; then
80
+ echo "❌ patch 不可用: $p (可能已应用过)"
81
+ exit 1
82
+ fi
83
+ git apply "$p"
84
+ applied=$((applied + 1))
85
+ done
86
+
87
+ if [ $applied -eq 0 ]; then
88
+ echo "❌ staging 里没有 .patch 文件"
89
+ exit 1
90
+ fi
91
+
92
+ echo "✅ 应用 $applied 个 patch"
93
+ echo " 建议现在跑: npm test + git commit -m 'auto-evolve: $patch_id'"
94
+ echo " 出问题回滚: $0 rollback $baseline"
95
+ ;;
96
+
97
+ rollback)
98
+ # 回滚到指定 baseline
99
+ if [ -z "$patch_id" ]; then
100
+ echo "用法: $0 rollback <tag>"
101
+ echo "可用的 baseline:"
102
+ git tag -l "${TAG_PREFIX}*" | sort -r | head -10
103
+ exit 1
104
+ fi
105
+ if ! git tag -l | grep -qx "$patch_id"; then
106
+ echo "❌ tag 不存在: $patch_id"
107
+ exit 1
108
+ fi
109
+ echo "⚠️ 将回滚到 $patch_id (hard reset, 丢弃之后所有改动)"
110
+ read -p "确认? [y/N] " -n 1 -r
111
+ echo
112
+ if [[ $REPLY =~ ^[Yy]$ ]]; then
113
+ git reset --hard "$patch_id"
114
+ echo "✅ 回滚到 $patch_id"
115
+ else
116
+ echo "取消"
117
+ fi
118
+ ;;
119
+
120
+ list)
121
+ echo "auto-evolve baselines (最近 10):"
122
+ git tag -l "${TAG_PREFIX}*" | sort -r | head -10 | while read tag; do
123
+ msg="$(git tag -l --format='%(contents)' "$tag" | head -1)"
124
+ echo " $tag — $msg"
125
+ done
126
+ if [ -f .last-auto-evolve-baseline ]; then
127
+ echo ""
128
+ echo "当前 baseline: $(cat .last-auto-evolve-baseline)"
129
+ fi
130
+ ;;
131
+
132
+ *)
133
+ echo "用法: $0 {snapshot|prepare <id>|apply <id>|rollback <tag>|list}"
134
+ exit 1
135
+ ;;
136
+ esac
@@ -51,12 +51,46 @@ async function main() {
51
51
  minify: false,
52
52
  });
53
53
 
54
+ // 2026-06-15: 编译 message-renderer.ts (对话显示 UI 模块)
55
+ // esbuild 编译 .ts → dist/web/ui/message-renderer.js (ESM, 浏览器侧 <script type="module"> 加载)
56
+ console.log('[build-web] 编译 message-renderer.ts...');
57
+ await fs.mkdir(path.join(DIST_WEB, 'ui'), { recursive: true });
58
+ await esbuild.build({
59
+ entryPoints: [path.join(ROOT, 'src/web/ui/message-renderer.ts')],
60
+ outfile: path.join(DIST_WEB, 'ui/message-renderer.js'),
61
+ format: 'esm',
62
+ target: 'es2022',
63
+ platform: 'browser',
64
+ minify: false,
65
+ });
66
+
67
+ // 2026-06-15: 编译 step-timeline.ts (气泡内 4 状态步骤条)
68
+ console.log('[build-web] 编译 step-timeline.ts...');
69
+ await esbuild.build({
70
+ entryPoints: [path.join(ROOT, 'src/web/ui/step-timeline.ts')],
71
+ outfile: path.join(DIST_WEB, 'ui/step-timeline.js'),
72
+ format: 'esm',
73
+ target: 'es2022',
74
+ platform: 'browser',
75
+ minify: false,
76
+ });
77
+
78
+ // 编译主客户端入口 (classic script, 非 module; 由 index.html 以 /client.js 加载)
79
+ console.log('[build-web] 编译 client.ts...');
80
+ await esbuild.build({
81
+ entryPoints: [path.join(ROOT, 'src/web/client.ts')],
82
+ outfile: path.join(DIST_WEB, 'client.js'),
83
+ format: 'iife',
84
+ target: 'es2022',
85
+ platform: 'browser',
86
+ minify: false,
87
+ });
88
+
54
89
  // 复制静态文件
55
90
  console.log('[build-web] 复制静态文件...');
56
91
  await fs.copyFile(path.join(ROOT, 'src/web/index.html'), path.join(DIST_WEB, 'index.html'));
57
92
  await fs.copyFile(path.join(ROOT, 'src/web/api-config.html'), path.join(DIST_WEB, 'api-config.html'));
58
93
  await fs.copyFile(path.join(ROOT, 'src/web/style.css'), path.join(DIST_WEB, 'style.css'));
59
- await fs.copyFile(path.join(ROOT, 'src/web/client.js'), path.join(DIST_WEB, 'client.js'));
60
94
  // 复制 PWA manifest (index.html 里有 <link rel="manifest">, 否则浏览器会 404)
61
95
  await fs.copyFile(path.join(ROOT, 'src/web/manifest.json'), path.join(DIST_WEB, 'manifest.json'));
62
96
  // 复制 icons 目录 (manifest.json 里引用了 favicon 等)
@@ -0,0 +1,48 @@
1
+ #!/bin/bash
2
+ # detect-schema-changes.sh — 阶段 C 护栏 6
3
+ #
4
+ # 检查 LLM 改的文件里有没有动 schema (interface / type / enum 声明)
5
+ # 有则强制要求 reviewer 双签 (在 .auto-evolve-review-required 文件)
6
+ #
7
+ # 用法 (在 staging 准备好 patch 后, apply 前):
8
+ # bash scripts/detect-schema-changes.sh <patch-id>
9
+
10
+ set -euo pipefail
11
+
12
+ REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
13
+ cd "$REPO_ROOT"
14
+
15
+ patch_id="${1:-}"
16
+ if [ -z "$patch_id" ]; then
17
+ echo "用法: $0 <patch-id>"
18
+ exit 1
19
+ fi
20
+
21
+ staging_dir="staging/auto-evolve/$patch_id"
22
+ if [ ! -d "$staging_dir" ]; then
23
+ echo "❌ staging 不存在: $staging_dir"
24
+ exit 1
25
+ fi
26
+
27
+ flag="$staging_dir/.schema-changed"
28
+ rm -f "$flag"
29
+
30
+ found=0
31
+ for patch in "$staging_dir"/*.patch; do
32
+ [ -e "$patch" ] || continue
33
+ # 检查 patch 里有没有新增/修改 interface、type、enum 声明
34
+ if grep -E '^\+.*(interface |type [A-Z][a-zA-Z0-9_]* =|enum [A-Z][a-zA-Z0-9_]*)' "$patch" > /dev/null 2>&1; then
35
+ found=1
36
+ echo "⚠️ schema 改动检测到: $patch"
37
+ grep -E '^\+.*(interface |type [A-Z][a-zA-Z0-9_]* =|enum [A-Z][a-zA-Z0-9_]*)' "$patch" | head -3
38
+ fi
39
+ done
40
+
41
+ if [ $found -eq 1 ]; then
42
+ touch "$flag"
43
+ echo ""
44
+ echo "🚨 schema 改动标记: $flag"
45
+ echo " 护栏 6 触发: apply 时会强制要求双签 reviewer"
46
+ else
47
+ echo "✅ 无 schema 改动, 走单签"
48
+ fi
@@ -0,0 +1,159 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * diff-reviewer.ts — 阶段 C 护栏 4
4
+ *
5
+ * 2nd LLM call 审第 1 个的 diff:
6
+ * - 默认用 Haiku (便宜, ~$0.001/diff)
7
+ * - schema 改动升级 Sonnet (护栏 6 双签)
8
+ *
9
+ * 输入: patch 文件 (git format-patch 风格)
10
+ * 输出: .review-verdict 写到 staging/<patch-id>/, 含 PASS/FAIL + 原因
11
+ *
12
+ * 用法:
13
+ * tsx scripts/diff-reviewer.ts <patch-id> [--model sonnet]
14
+ */
15
+
16
+ import * as fs from 'fs/promises';
17
+ import * as path from 'path';
18
+ // Anthropic SDK 在 review() 里 lazy import — 无 API key 或没装 SDK 都不应炸
19
+
20
+ const STAGING_DIR = 'staging/auto-evolve';
21
+ const ENV_KEY_MODEL = 'AUTO_EVOLVE_REVIEW_MODEL';
22
+
23
+ const REVIEW_PROMPT = `你是一个严格的代码审查员. 审查以下 git diff (LLM 自动生成的源码改动).
24
+
25
+ 只回答 JSON, 字段:
26
+ {
27
+ "verdict": "PASS" | "FAIL",
28
+ "concerns": ["concern 1", "concern 2", ...],
29
+ "suggestions": ["suggestion 1", ...]
30
+ }
31
+
32
+ PASS 条件 (全部满足才 PASS):
33
+ 1. 改动能解决它声称要解决的问题
34
+ 2. 没引入明显 bug (空指针, 内存泄漏, 死循环, race condition)
35
+ 3. 没引入安全漏洞 (injection, XSS, 越权)
36
+ 4. 边界条件考虑 (空数组, undefined, 极值, 并发)
37
+ 5. 改动局限在它声称的范围, 不夹带私货
38
+ 6. 跟现有代码风格一致
39
+
40
+ FAIL 条件 (任一即 FAIL):
41
+ - 满足上面任一 PASS 条件的反例
42
+ - 引入了新依赖 (必须在 concerns 里说)
43
+ - 删除了测试 / 注释掉失败用例
44
+ - 用了 any / unknown / @ts-ignore 偷懒
45
+
46
+ DIFF:
47
+ {{DIFF}}
48
+ `;
49
+
50
+ function degradedGrepReview(patchContent: string): { verdict: string; concerns: string[]; suggestions: string[]; raw: string } {
51
+ console.warn('[diff-reviewer] ⚠️ 降级 grep 检查 (无 API key 或无 SDK)');
52
+ const concerns: string[] = [];
53
+ if (/\+.*\bany\b/.test(patchContent)) concerns.push('使用了 any');
54
+ if (/\+.*\b@ts-ignore\b/.test(patchContent)) concerns.push('使用了 @ts-ignore');
55
+ if (/\+.*\bconsole\.log\b/.test(patchContent)) concerns.push('留了 console.log');
56
+ if (/\-.*test\(/.test(patchContent)) concerns.push('删除了测试');
57
+ return {
58
+ verdict: concerns.length > 0 ? 'FAIL' : 'PASS',
59
+ concerns,
60
+ suggestions: [],
61
+ raw: '(degraded grep mode)',
62
+ };
63
+ }
64
+
65
+ async function review(patchContent: string, model: string): Promise<{ verdict: string; concerns: string[]; suggestions: string[]; raw: string }> {
66
+ // 无 API key → 直接降级, 不 import SDK (避免 no-ANTHROPIC 环境下也炸)
67
+ if (!process.env.ANTHROPIC_API_KEY) {
68
+ return degradedGrepReview(patchContent);
69
+ }
70
+
71
+ // 有 API key → 尝试 lazy import SDK
72
+ let Anthropic: any;
73
+ try {
74
+ ({ Anthropic } = await import('@anthropic-ai/sdk'));
75
+ } catch (err) {
76
+ console.warn('[diff-reviewer] ⚠️ @anthropic-ai/sdk 未装, 降级 grep');
77
+ return degradedGrepReview(patchContent);
78
+ }
79
+
80
+ const client = new Anthropic();
81
+ const prompt = REVIEW_PROMPT.replace('{{DIFF}}', patchContent.slice(0, 20000)); // 限长
82
+ const resp = await client.messages.create({
83
+ model,
84
+ max_tokens: 1024,
85
+ messages: [{ role: 'user', content: prompt }],
86
+ });
87
+ const text = resp.content[0].type === 'text' ? resp.content[0].text : '';
88
+ // 解析 JSON
89
+ const m = /\{[\s\S]*\}/.exec(text);
90
+ if (!m) {
91
+ return { verdict: 'FAIL', concerns: ['LLM 没返回 JSON'], suggestions: [], raw: text };
92
+ }
93
+ try {
94
+ const parsed = JSON.parse(m[0]);
95
+ return {
96
+ verdict: parsed.verdict === 'PASS' ? 'PASS' : 'FAIL',
97
+ concerns: parsed.concerns || [],
98
+ suggestions: parsed.suggestions || [],
99
+ raw: text,
100
+ };
101
+ } catch {
102
+ return { verdict: 'FAIL', concerns: ['JSON 解析失败'], suggestions: [], raw: text };
103
+ }
104
+ }
105
+
106
+ async function main() {
107
+ const args = process.argv.slice(2);
108
+ const patchId = args[0];
109
+ if (!patchId) {
110
+ console.error('用法: tsx diff-reviewer.ts <patch-id> [--model sonnet]');
111
+ process.exit(1);
112
+ }
113
+ const forceModel = args.includes('--model') ? args[args.indexOf('--model') + 1] : null;
114
+
115
+ const stagingDir = path.join(STAGING_DIR, patchId);
116
+ const schemaFlag = path.join(stagingDir, '.schema-changed');
117
+ const isSchemaChange = await fs.access(schemaFlag).then(() => true).catch(() => false);
118
+
119
+ const defaultModel = isSchemaChange ? 'claude-sonnet-4-6' : 'claude-haiku-4-5';
120
+ const model = forceModel || process.env[ENV_KEY_MODEL] || defaultModel;
121
+
122
+ console.log(`[diff-reviewer] patch=${patchId} schema=${isSchemaChange} model=${model}`);
123
+
124
+ // 合并所有 patch
125
+ const files = await fs.readdir(stagingDir);
126
+ const patches = files.filter((f) => f.endsWith('.patch'));
127
+ if (patches.length === 0) {
128
+ console.error('❌ staging 里没有 .patch 文件');
129
+ process.exit(1);
130
+ }
131
+
132
+ let combined = '';
133
+ for (const p of patches) {
134
+ combined += `\n=== ${p} ===\n` + (await fs.readFile(path.join(stagingDir, p), 'utf-8'));
135
+ }
136
+
137
+ const r = await review(combined, model);
138
+
139
+ const verdict = {
140
+ patchId,
141
+ model,
142
+ schemaChange: isSchemaChange,
143
+ verdict: r.verdict,
144
+ concerns: r.concerns,
145
+ suggestions: r.suggestions,
146
+ reviewedAt: new Date().toISOString(),
147
+ };
148
+ await fs.writeFile(path.join(stagingDir, '.review-verdict'), JSON.stringify(verdict, null, 2));
149
+
150
+ console.log(`[diff-reviewer] verdict=${r.verdict} concerns=${r.concerns.length}`);
151
+ if (r.verdict === 'FAIL') {
152
+ for (const c of r.concerns) console.log(` - ${c}`);
153
+ process.exit(2);
154
+ } else {
155
+ for (const s of r.suggestions) console.log(` 💡 ${s}`);
156
+ }
157
+ }
158
+
159
+ main().catch((e) => { console.error(e); process.exit(1); });
@@ -0,0 +1,142 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * validate-system-prompt.ts — 护栏: system-prompt 改动验证
4
+ *
5
+ * 跑在 pre-commit + reviewer 后:
6
+ * 1. 每个 layer .md 不超 maxChars
7
+ * 2. version 字段 (HTML 注释 <!-- id@version -->) 存在
8
+ * 3. hibsml 标签没漏 (如果出现 → 警告)
9
+ *
10
+ * 用法:
11
+ * tsx scripts/validate-system-prompt.ts
12
+ * tsx scripts/validate-system-prompt.ts --layer core/refusal.md
13
+ */
14
+ import * as fs from 'fs/promises';
15
+ import * as path from 'path';
16
+
17
+ const REPO = process.cwd();
18
+ const LAYERS_DIR = path.join(REPO, 'src/llm/system-prompt/layers');
19
+
20
+ // 跟 registry 保持一致 (手维护同步; 后续可让 registry 暴露)
21
+ // P-Action 4 (2026-06-15): 跟 registry.ts STATIC_LAYERS maxChars 同步, 停用 layer 设 0
22
+ const MAX_CHARS: Record<string, number> = {
23
+ 'core/identity': 800,
24
+ 'core/knowledge': 600,
25
+ 'core/tools.thin': 400,
26
+ 'core/hibs_reminders': 0, // 停用 (was 800)
27
+ 'core/refusal': 800,
28
+ 'core/tone': 500,
29
+ 'core/wellbeing': 600,
30
+ 'core/evenhandedness': 300,
31
+ 'core/memory_system': 200,
32
+ 'core/artifacts_storage': 0, // 停用 (was 2500)
33
+ 'core/network_filesystem': 0, // 停用 (was 900)
34
+ 'role/expert': 500,
35
+ 'role/architect': 0, // 停用 (was 500)
36
+ 'role/implementer': 0, // 停用 (was 500)
37
+ 'role/security': 0, // 停用 (was 500)
38
+ 'channel/local': 500,
39
+ 'channel/p2p-visitor': 700,
40
+ 'channel/p2p-agent': 700,
41
+ 'tool/bash': 600,
42
+ 'tool/web_search': 600,
43
+ 'tool/mcp_apps': 0, // 停用 (was 1800)
44
+ 'tool/hibs_api': 0, // 停用 (was 4500)
45
+ 'tool/image_search': 0, // 停用 (was 2500)
46
+ 'tool/artifacts': 0, // 停用 (was 2500)
47
+ 'tool/manifest': 500,
48
+ };
49
+
50
+ type IssueType = 'oversize' | 'no-version' | 'leftover-hibsml';
51
+ type IssueSeverity = 'error' | 'warning';
52
+
53
+ interface Issue {
54
+ layer: string;
55
+ type: IssueType;
56
+ severity: IssueSeverity;
57
+ detail: string;
58
+ }
59
+
60
+ /**
61
+ * P-Action 4 (2026-06-15): oversize 降级为 warning.
62
+ * 原因: P-Action 4 收紧 registry maxChars 后, 多个历史 layer .md 实际长度超过新上限.
63
+ * 这些 .md 是"原样"对齐 Claude.ai 完整版的, 内容不动 (用户约束: 不改 prompt).
64
+ * runtime 时 assembleSystemPrompt 会按 maxChars 截断, 行为已受控.
65
+ * 因此 validate 阶段不再 fail build, 只 log warning.
66
+ * 保留为 error 的: no-version (可追溯性), leftover-hibsml (安全).
67
+ */
68
+ const SEVERITY: Record<IssueType, IssueSeverity> = {
69
+ oversize: 'warning',
70
+ 'no-version': 'error',
71
+ 'leftover-hibsml': 'error',
72
+ };
73
+
74
+ async function check(file: string): Promise<Issue[]> {
75
+ const issues: Issue[] = [];
76
+ const rel = path.relative(LAYERS_DIR, file);
77
+ const max = MAX_CHARS[rel.replace(/\.md$/, '')];
78
+ const content = await fs.readFile(file, 'utf-8');
79
+ if (max && content.length > max) {
80
+ issues.push({ layer: rel, type: 'oversize', severity: SEVERITY.oversize, detail: `${content.length} > ${max}` });
81
+ }
82
+ if (!/<!--\s*[\w.-]+@[\d.]+\s*-->/.test(content)) {
83
+ issues.push({ layer: rel, type: 'no-version', severity: SEVERITY['no-version'], detail: '缺 <!-- id@version --> 标记' });
84
+ }
85
+ if (/\{hibsml:(?!thinking_mode)[\w_]+\}/.test(content) || /\{\/hibsml:/.test(content)) {
86
+ issues.push({ layer: rel, type: 'leftover-hibsml', severity: SEVERITY['leftover-hibsml'], detail: '检测到未脱除的 hibsml 标签' });
87
+ }
88
+ return issues;
89
+ }
90
+
91
+ async function walk(dir: string): Promise<string[]> {
92
+ const out: string[] = [];
93
+ const entries = await fs.readdir(dir, { withFileTypes: true });
94
+ for (const e of entries) {
95
+ const full = path.join(dir, e.name);
96
+ if (e.isDirectory()) out.push(...await walk(full));
97
+ else if (e.name.endsWith('.md')) out.push(full);
98
+ }
99
+ return out;
100
+ }
101
+
102
+ async function main() {
103
+ const args = process.argv.slice(2);
104
+ let files: string[];
105
+ if (args.includes('--layer')) {
106
+ const idx = args.indexOf('--layer');
107
+ const target = path.join(LAYERS_DIR, args[idx + 1]);
108
+ files = [target];
109
+ } else {
110
+ files = await walk(LAYERS_DIR);
111
+ }
112
+ const allIssues: Issue[] = [];
113
+ for (const f of files) {
114
+ const issues = await check(f);
115
+ allIssues.push(...issues);
116
+ }
117
+ if (allIssues.length === 0) {
118
+ console.log(`✅ ${files.length} 个 layer 全部通过 (字符上限, 版本标记, hibsml 脱除)`);
119
+ return;
120
+ }
121
+ const errors = allIssues.filter((i) => i.severity === 'error');
122
+ const warnings = allIssues.filter((i) => i.severity === 'warning');
123
+
124
+ if (warnings.length > 0) {
125
+ console.warn(`⚠️ ${warnings.length} 个 warning (P-Action 4 后 oversize 不再 fail build):`);
126
+ for (const i of warnings) {
127
+ console.warn(` [${i.type}] ${i.layer}: ${i.detail}`);
128
+ }
129
+ }
130
+
131
+ if (errors.length === 0) {
132
+ console.log(`✅ ${files.length} 个 layer 通过 (${warnings.length} 个 warning, 0 个 error)`);
133
+ return;
134
+ }
135
+ console.error(`❌ ${errors.length} 个 error:`);
136
+ for (const i of errors) {
137
+ console.error(` [${i.type}] ${i.layer}: ${i.detail}`);
138
+ }
139
+ process.exit(1);
140
+ }
141
+
142
+ main().catch((e) => { console.error(e); process.exit(1); });