@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.
- package/.auto-evolve-calls +1 -0
- package/.last-auto-evolve-baseline +1 -0
- package/.playwright-mcp/page-2026-06-16T07-51-45-706Z.yml +130 -0
- package/.playwright-mcp/page-2026-06-16T07-56-44-116Z.yml +131 -0
- package/Bolloon.md +144 -0
- package/Dive-into/CITATION.cff +17 -0
- package/Dive-into/LICENSE +25 -0
- package/Dive-into/README.md +598 -0
- package/Dive-into/README_zh.md +599 -0
- package/Dive-into/assets/context.png +0 -0
- package/Dive-into/assets/extensibility.png +0 -0
- package/Dive-into/assets/iteration.png +0 -0
- package/Dive-into/assets/layered_architecture.png +0 -0
- package/Dive-into/assets/main_structure.png +0 -0
- package/Dive-into/assets/permission.png +0 -0
- package/Dive-into/assets/session_compact.png +0 -0
- package/Dive-into/assets/subagent.png +0 -0
- package/Dive-into/paper/Dive_into_Claude_Code.pdf +0 -0
- package/README.md +1 -1
- package/dist/agents/p2p-chat-tools.js +6 -6
- package/dist/agents/permission-mode.js +115 -0
- package/dist/agents/pi-sdk.js +687 -25
- package/dist/agents/pre-tool-validator.js +194 -0
- package/dist/agents/workflow-pivot-loop.js +113 -12
- package/dist/bollharness/src/scripts/checks/check_doc_freshness.js +1 -1
- package/dist/bollharness/src/scripts/checks/check_doc_links.js +1 -1
- package/dist/bollharness/src/scripts/context_router.js +1 -1
- package/dist/bollharness/src/scripts/deploy-guard.js +1 -1
- package/dist/bollharness/src/scripts/guard_router.js +1 -1
- package/dist/bollharness/src/scripts/hooks/_hook_output.js +1 -1
- package/dist/bollharness/src/scripts/hooks/risk-tracker.js +1 -1
- package/dist/bollharness-integration/context-router.js +2 -2
- package/dist/bollharness-integration/guard-checker.js +1 -1
- package/dist/bootstrap/bootstrap.js +117 -0
- package/dist/bootstrap/context-collector.js +312 -0
- package/dist/bootstrap/context-hierarchy.js +218 -0
- package/dist/bootstrap/lifecycle-hooks.js +171 -0
- package/dist/bootstrap/project-context.js +158 -0
- package/dist/context-compaction/auto-compact.js +144 -0
- package/dist/context-compaction/budget-gate.js +28 -0
- package/dist/context-compaction/budget-reduce.js +35 -0
- package/dist/context-compaction/context-collapse.js +66 -0
- package/dist/context-compaction/index.js +21 -0
- package/dist/context-compaction/microcompact.js +51 -0
- package/dist/context-compaction/pipeline.js +123 -0
- package/dist/context-compaction/snip.js +45 -0
- package/dist/context-compaction/token-estimator.js +35 -0
- package/dist/context-compaction/types.js +19 -0
- package/dist/heartbeat/HealthMonitor.js +3 -2
- package/dist/index.js +49 -2
- package/dist/llm/llm-judgment-client.js +32 -30
- package/dist/llm/pi-ai.js +125 -28
- package/dist/llm/system-prompt/health.js +129 -0
- package/dist/llm/system-prompt/registry.js +246 -0
- package/dist/llm/system-prompt/strip-hibsml.js +51 -0
- package/dist/llm/tool-manifest/ask_user_input.js +35 -0
- package/dist/llm/tool-manifest/bash.js +23 -0
- package/dist/llm/tool-manifest/create_file.js +24 -0
- package/dist/llm/tool-manifest/fetch_sports_data.js +26 -0
- package/dist/llm/tool-manifest/image_search.js +24 -0
- package/dist/llm/tool-manifest/index.js +69 -0
- package/dist/llm/tool-manifest/mcp.js +43 -0
- package/dist/llm/tool-manifest/message_compose.js +31 -0
- package/dist/llm/tool-manifest/places.js +83 -0
- package/dist/llm/tool-manifest/present_files.js +21 -0
- package/dist/llm/tool-manifest/recipe.js +40 -0
- package/dist/llm/tool-manifest/recommend_apps.js +23 -0
- package/dist/llm/tool-manifest/str_replace.js +27 -0
- package/dist/llm/tool-manifest/types.js +7 -0
- package/dist/llm/tool-manifest/view.js +24 -0
- package/dist/llm/tool-manifest/weather.js +27 -0
- package/dist/llm/tool-manifest/web.js +51 -0
- package/dist/network/p2p-direct.js +23 -0
- package/dist/network/source-intent-broadcaster.js +203 -0
- package/dist/network/source-intent.js +100 -0
- package/dist/pi-ecosystem-judgment/adaptive-scan.js +279 -0
- package/dist/pi-ecosystem-judgment/causal-judge.js +449 -0
- package/dist/pi-ecosystem-judgment/detect-hook.js +168 -0
- package/dist/pi-ecosystem-judgment/distill-prompt.js +226 -0
- package/dist/pi-ecosystem-judgment/evolve-judgment.js +170 -0
- package/dist/pi-ecosystem-judgment/human-value-pipeline.js +21 -0
- package/dist/pi-ecosystem-judgment/human-value-store.js +283 -22
- package/dist/pi-ecosystem-judgment/injection-gate.js +208 -0
- package/dist/pi-ecosystem-judgment/monitor-gate.js +188 -0
- package/dist/pi-ecosystem-judgment/value-injection.js +8 -2
- package/dist/security/builtin-guards.js +124 -0
- package/dist/security/context-router-tool.js +106 -0
- package/dist/security/input-scanner.js +223 -0
- package/dist/security/react-harness.js +143 -0
- package/dist/security/tool-gate.js +235 -0
- package/dist/utils/auto-evolve-policy.js +117 -0
- package/dist/utils/clamp.js +7 -0
- package/dist/utils/double.js +6 -0
- package/dist/web/client.js +3810 -3830
- package/dist/web/components/p2p/P2PModal.js +188 -0
- package/dist/web/components/p2p/index.js +264 -226
- package/dist/web/components/p2p/p2p-modal.js +657 -0
- package/dist/web/components/p2p/p2p-tools.js +248 -0
- package/dist/web/index.html +60 -49
- package/dist/web/server.js +827 -124
- package/dist/web/style.css +531 -249
- package/dist/web/ui/message-renderer.js +463 -0
- package/dist/web/ui/step-timeline.js +375 -0
- package/lefthook.yml +33 -0
- package/package.json +3 -2
- package/scripts/auto-evolve-loop.ts +481 -0
- package/scripts/auto-evolve-oneshot.sh +155 -0
- package/scripts/auto-evolve-snapshot.sh +136 -0
- package/scripts/build-web.ts +35 -1
- package/scripts/detect-schema-changes.sh +48 -0
- package/scripts/diff-reviewer.ts +159 -0
- package/scripts/validate-system-prompt.ts +142 -0
- package/scripts/weekly-report.ts +364 -0
- package/src/agents/p2p-chat-tools.ts +6 -6
- package/src/agents/permission-mode.ts +127 -0
- package/src/agents/pi-sdk.ts +741 -30
- package/src/agents/pre-tool-validator.ts +213 -0
- package/src/agents/workflow-pivot-loop.ts +110 -19
- package/src/bollharness/CLAUDE.md +1 -1
- package/src/bollharness/README.md +2 -2
- package/src/bollharness/README.zh-CN.md +2 -2
- package/src/bollharness/reference/boll-reference/scripts/hooks/find-boll-root.sh +2 -2
- package/src/bollharness/scripts/context-fragments/truth-source-hierarchy.md +2 -2
- package/src/bollharness/scripts/context-fragments/version-sources.md +1 -1
- package/src/bollharness/scripts/hooks/find-project-root.sh +4 -4
- package/src/bollharness/src/scripts/checks/check_doc_freshness.ts +1 -1
- package/src/bollharness/src/scripts/checks/check_doc_links.ts +1 -1
- package/src/bollharness/src/scripts/context_router.ts +1 -1
- package/src/bollharness/src/scripts/deploy-guard.ts +1 -1
- package/src/bollharness/src/scripts/guard_router.ts +1 -1
- package/src/bollharness/src/scripts/hooks/_hook_output.ts +1 -1
- package/src/bollharness/src/scripts/hooks/risk-tracker.ts +1 -1
- package/src/bollharness/templates/scaffold/.gitignore.append +1 -1
- package/src/bollharness/templates/scaffold/CLAUDE.md +2 -2
- package/src/bollharness-integration/context-router.ts +2 -2
- package/src/bollharness-integration/guard-checker.ts +1 -1
- package/src/bootstrap/bootstrap.ts +135 -0
- package/src/bootstrap/context-collector.ts +371 -0
- package/src/bootstrap/context-hierarchy.ts +283 -0
- package/src/bootstrap/lifecycle-hooks.ts +289 -0
- package/src/bootstrap/project-context.ts +171 -0
- package/src/context-compaction/auto-compact.ts +153 -0
- package/src/context-compaction/budget-gate.ts +32 -0
- package/src/context-compaction/budget-reduce.ts +37 -0
- package/src/context-compaction/context-collapse.ts +72 -0
- package/src/context-compaction/index.ts +24 -0
- package/src/context-compaction/microcompact.ts +54 -0
- package/src/context-compaction/pipeline.ts +133 -0
- package/src/context-compaction/snip.ts +51 -0
- package/src/context-compaction/token-estimator.ts +36 -0
- package/src/context-compaction/types.ts +99 -0
- package/src/heartbeat/HealthMonitor.ts +3 -2
- package/src/index.ts +47 -2
- package/src/llm/llm-judgment-client.ts +36 -35
- package/src/llm/pi-ai.ts +135 -29
- package/src/llm/system-prompt/health.ts +159 -0
- package/src/llm/system-prompt/layers/channel/local.md +14 -0
- package/src/llm/system-prompt/layers/channel/p2p-agent.md +18 -0
- package/src/llm/system-prompt/layers/channel/p2p-visitor.md +19 -0
- package/src/llm/system-prompt/layers/core/artifacts_storage.md +89 -0
- package/src/llm/system-prompt/layers/core/evenhandedness.md +21 -0
- package/src/llm/system-prompt/layers/core/hibs_reminders.md +15 -0
- package/src/llm/system-prompt/layers/core/identity.md +37 -0
- package/src/llm/system-prompt/layers/core/knowledge.md +17 -0
- package/src/llm/system-prompt/layers/core/memory_system.md +12 -0
- package/src/llm/system-prompt/layers/core/network_filesystem.md +28 -0
- package/src/llm/system-prompt/layers/core/refusal.md +37 -0
- package/src/llm/system-prompt/layers/core/tone.md +31 -0
- package/src/llm/system-prompt/layers/core/tools.thin.md +13 -0
- package/src/llm/system-prompt/layers/core/wellbeing.md +41 -0
- package/src/llm/system-prompt/layers/role/architect.md +20 -0
- package/src/llm/system-prompt/layers/role/expert.md +19 -0
- package/src/llm/system-prompt/layers/role/implementer.md +15 -0
- package/src/llm/system-prompt/layers/role/security.md +15 -0
- package/src/llm/system-prompt/layers/tool/artifacts.md +72 -0
- package/src/llm/system-prompt/layers/tool/bash.md +25 -0
- package/src/llm/system-prompt/layers/tool/hibs_api.md +171 -0
- package/src/llm/system-prompt/layers/tool/image_search.md +70 -0
- package/src/llm/system-prompt/layers/tool/manifest.md +89 -0
- package/src/llm/system-prompt/layers/tool/mcp_apps.md +53 -0
- package/src/llm/system-prompt/layers/tool/web_search.md +83 -0
- package/src/llm/system-prompt/registry.ts +325 -0
- package/src/llm/system-prompt/strip-hibsml.ts +52 -0
- package/src/llm/tool-manifest/ask_user_input.ts +37 -0
- package/src/llm/tool-manifest/bash.ts +25 -0
- package/src/llm/tool-manifest/create_file.ts +26 -0
- package/src/llm/tool-manifest/fetch_sports_data.ts +28 -0
- package/src/llm/tool-manifest/image_search.ts +26 -0
- package/src/llm/tool-manifest/index.ts +88 -0
- package/src/llm/tool-manifest/mcp.ts +46 -0
- package/src/llm/tool-manifest/message_compose.ts +33 -0
- package/src/llm/tool-manifest/places.ts +86 -0
- package/src/llm/tool-manifest/present_files.ts +23 -0
- package/src/llm/tool-manifest/recipe.ts +42 -0
- package/src/llm/tool-manifest/recommend_apps.ts +25 -0
- package/src/llm/tool-manifest/str_replace.ts +29 -0
- package/src/llm/tool-manifest/types.ts +52 -0
- package/src/llm/tool-manifest/view.ts +26 -0
- package/src/llm/tool-manifest/weather.ts +29 -0
- package/src/llm/tool-manifest/web.ts +54 -0
- package/src/network/p2p-direct.ts +22 -0
- package/src/network/source-intent-broadcaster.ts +242 -0
- package/src/network/source-intent.ts +167 -0
- package/src/security/builtin-guards.ts +162 -0
- package/src/security/context-router-tool.ts +122 -0
- package/src/security/input-scanner.ts +287 -0
- package/src/security/react-harness.ts +177 -0
- package/src/security/tool-gate.ts +294 -0
- package/src/utils/auto-evolve-policy.ts +138 -0
- package/src/utils/clamp.ts +5 -0
- package/src/web/client.js +105 -2187
- package/src/web/client.ts +4326 -0
- package/src/web/index.html +60 -49
- package/src/web/server.ts +894 -148
- package/src/web/style.css +531 -249
- package/src/web/ui/message-renderer.ts +540 -0
- package/src/web/ui/step-timeline.ts +394 -0
- package/staging/auto-evolve/clean-001/.review-verdict +9 -0
- package/staging/auto-evolve/clean-001/clean-001.patch +14 -0
- package/staging/auto-evolve/e2e-001/.patch-id +1 -0
- package/staging/auto-evolve/e2e-001/.review-verdict +12 -0
- package/staging/auto-evolve/e2e-001/e2e-001.patch +11 -0
- package/staging/auto-evolve/test-bad/.review-verdict +12 -0
- package/staging/auto-evolve/test-bad/test-bad.patch +11 -0
- package/test-results/.last-run.json +6 -0
- 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
|
package/scripts/build-web.ts
CHANGED
|
@@ -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); });
|