@bolloon/bolloon-agent 0.2.12 → 0.2.13

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 (284) hide show
  1. package/README.md +495 -467
  2. package/bin/bolloon-cli.cjs +183 -183
  3. package/bin/bolloon-daemon.sh +207 -0
  4. package/bin/bolloon.cjs +0 -0
  5. package/bin/ipfs +0 -0
  6. package/dist/agents/agent-manifest-protocol.js +52 -0
  7. package/dist/agents/chat-segmenter.js +298 -0
  8. package/dist/agents/constraint-layer.js +19 -19
  9. package/dist/agents/judgment-protocol.js +479 -0
  10. package/dist/agents/parse-tool-call.js +304 -0
  11. package/dist/agents/peer-manifest-loader.js +210 -0
  12. package/dist/agents/pi-sdk-session-factory.js +110 -0
  13. package/dist/agents/pi-sdk-session-manager.js +297 -0
  14. package/dist/agents/pi-sdk-tools.js +1288 -0
  15. package/dist/agents/pi-sdk-types.js +13 -0
  16. package/dist/agents/pi-sdk.js +553 -1306
  17. package/dist/agents/react-loop.js +120 -0
  18. package/dist/agents/session-store.js +171 -0
  19. package/dist/agents/shell-guard.js +2 -2
  20. package/dist/agents/tool-registry.js +136 -0
  21. package/dist/agents/workflow-pivot-loop.js +200 -22
  22. package/dist/bollharness/src/scripts/context_router.js +7 -0
  23. package/dist/bollharness/src/scripts/deploy-guard.js +8 -8
  24. package/dist/bollharness-integration/context-router-judgment.js +4 -4
  25. package/dist/bollharness-integration/context-router.js +292 -292
  26. package/dist/bollharness-integration/gate-state-machine.js +26 -13
  27. package/dist/bollharness-integration/integration.js +71 -0
  28. package/dist/bollharness-integration/llm-judgment-engine.js +134 -134
  29. package/dist/bollharness-integration/skill-adapter.js +57 -127
  30. package/dist/bootstrap/chat-archiver.js +276 -0
  31. package/dist/bootstrap/context-collector.js +6 -3
  32. package/dist/bootstrap/event-log.js +160 -0
  33. package/dist/bootstrap/lifecycle-hooks.js +15 -1
  34. package/dist/bootstrap/memory-compressor.js +170 -0
  35. package/dist/bootstrap/persona-loader.js +94 -0
  36. package/dist/bootstrap/project-state.js +159 -0
  37. package/dist/bootstrap/remote-mirror.js +97 -0
  38. package/dist/bootstrap/session-window.js +121 -0
  39. package/dist/bootstrap/vector-index.js +248 -0
  40. package/dist/cli/loading-tui.js +40 -0
  41. package/dist/cli-entry.js +41 -37
  42. package/dist/context-compaction/auto-compact.js +7 -7
  43. package/dist/electron/config.js +21 -0
  44. package/dist/electron/config.js.map +1 -0
  45. package/dist/electron/dialogs.js +108 -0
  46. package/dist/electron/dialogs.js.map +1 -0
  47. package/dist/electron/first-run.js +170 -0
  48. package/dist/electron/first-run.js.map +1 -0
  49. package/dist/electron/ipc.js +20 -0
  50. package/dist/electron/ipc.js.map +1 -0
  51. package/dist/electron/logger.js +114 -0
  52. package/dist/electron/logger.js.map +1 -0
  53. package/dist/electron/main.js +63 -0
  54. package/dist/electron/main.js.map +1 -0
  55. package/dist/electron/menu.js +145 -0
  56. package/dist/electron/menu.js.map +1 -0
  57. package/dist/electron/paths.js +75 -0
  58. package/dist/electron/paths.js.map +1 -0
  59. package/dist/electron/server.js +119 -0
  60. package/dist/electron/server.js.map +1 -0
  61. package/dist/electron/tray.js +111 -0
  62. package/dist/electron/tray.js.map +1 -0
  63. package/dist/electron/window.js +111 -0
  64. package/dist/electron/window.js.map +1 -0
  65. package/dist/electron-preload.js +26 -6
  66. package/dist/electron-preload.js.map +1 -1
  67. package/dist/electron.js +6 -168
  68. package/dist/electron.js.map +1 -1
  69. package/dist/index.js +323 -266
  70. package/dist/llm/config-store.js +24 -8
  71. package/dist/llm/llm-judgment-client.js +102 -102
  72. package/dist/llm/pi-ai.js +137 -85
  73. package/dist/llm/system-prompt/layers/channel/local.md +14 -14
  74. package/dist/llm/system-prompt/layers/channel/p2p-agent.md +18 -18
  75. package/dist/llm/system-prompt/layers/channel/p2p-visitor.md +19 -19
  76. package/dist/llm/system-prompt/layers/core/artifacts_storage.md +89 -89
  77. package/dist/llm/system-prompt/layers/core/evenhandedness.md +21 -21
  78. package/dist/llm/system-prompt/layers/core/hibs_reminders.md +15 -15
  79. package/dist/llm/system-prompt/layers/core/identity.md +37 -37
  80. package/dist/llm/system-prompt/layers/core/knowledge.md +17 -17
  81. package/dist/llm/system-prompt/layers/core/memory_system.md +12 -12
  82. package/dist/llm/system-prompt/layers/core/network_filesystem.md +28 -28
  83. package/dist/llm/system-prompt/layers/core/refusal.md +37 -37
  84. package/dist/llm/system-prompt/layers/core/tone.md +31 -31
  85. package/dist/llm/system-prompt/layers/core/tools.thin.md +13 -13
  86. package/dist/llm/system-prompt/layers/core/wellbeing.md +41 -41
  87. package/dist/llm/system-prompt/layers/role/architect.md +20 -20
  88. package/dist/llm/system-prompt/layers/role/expert.md +19 -19
  89. package/dist/llm/system-prompt/layers/role/implementer.md +15 -15
  90. package/dist/llm/system-prompt/layers/role/security.md +15 -15
  91. package/dist/llm/system-prompt/layers/tool/artifacts.md +72 -72
  92. package/dist/llm/system-prompt/layers/tool/bash.md +25 -25
  93. package/dist/llm/system-prompt/layers/tool/hibs_api.md +171 -171
  94. package/dist/llm/system-prompt/layers/tool/image_search.md +70 -70
  95. package/dist/llm/system-prompt/layers/tool/manifest.md +89 -89
  96. package/dist/llm/system-prompt/layers/tool/mcp_apps.md +53 -53
  97. package/dist/llm/system-prompt/layers/tool/web_search.md +83 -83
  98. package/dist/llm/tool-manifest/ask_user_input.js +1 -1
  99. package/dist/llm/tool-manifest/bash.js +3 -3
  100. package/dist/llm/tool-manifest/create_file.js +4 -4
  101. package/dist/llm/tool-manifest/fetch_sports_data.js +3 -3
  102. package/dist/llm/tool-manifest/image_search.js +2 -2
  103. package/dist/llm/tool-manifest/mcp.js +2 -2
  104. package/dist/llm/tool-manifest/message_compose.js +3 -3
  105. package/dist/llm/tool-manifest/places.js +2 -2
  106. package/dist/llm/tool-manifest/present_files.js +1 -1
  107. package/dist/llm/tool-manifest/recipe.js +2 -2
  108. package/dist/llm/tool-manifest/str_replace.js +5 -5
  109. package/dist/llm/tool-manifest/view.js +3 -3
  110. package/dist/llm/tool-manifest/weather.js +4 -4
  111. package/dist/llm/tool-manifest/web.js +4 -4
  112. package/dist/network/local-inbox-bus.js +73 -0
  113. package/dist/network/p2p-outbox.js +161 -0
  114. package/dist/network/peer-fs.js +420 -0
  115. package/dist/network/peer-resource-bridge.js +216 -0
  116. package/dist/pi-ecosystem-judgment/causal-judge.js +51 -51
  117. package/dist/pi-ecosystem-judgment/cleanup.js +126 -0
  118. package/dist/pi-ecosystem-judgment/distill-prompt.js +42 -42
  119. package/dist/pi-ecosystem-judgment/distillation.js +14 -14
  120. package/dist/pi-ecosystem-judgment/human-value-store.js +45 -11
  121. package/dist/pi-ecosystem-judgment/monitor-gate.js +28 -28
  122. package/dist/pi-ecosystem-judgment/value-injection.js +102 -102
  123. package/dist/security/context-router-tool.js +15 -15
  124. package/dist/security/tool-gate.js +11 -0
  125. package/dist/web/api-config.html +520 -520
  126. package/dist/web/client-loop-status.js +220 -0
  127. package/dist/web/client.js +22 -5
  128. package/dist/web/client.js.map +7 -0
  129. package/dist/web/components/wallet-viem.mjs +118 -118
  130. package/dist/web/index.html +375 -375
  131. package/dist/web/input-validator.js +103 -0
  132. package/dist/web/manifest.json +20 -20
  133. package/dist/web/routes-judgments.js +738 -0
  134. package/dist/web/routes-llm-config.js +279 -0
  135. package/dist/web/routes-tasks.js +222 -0
  136. package/dist/web/server-sse.js +121 -0
  137. package/dist/web/server-storage.js +154 -0
  138. package/dist/web/server-types.js +15 -0
  139. package/dist/web/server-v3-p2p.js +224 -0
  140. package/dist/web/server.js +1070 -1307
  141. package/dist/web/style.css +4742 -4742
  142. package/dist/web/util/safe-name.js +32 -0
  143. package/package.json +162 -160
  144. package/scripts/build-cli.js +215 -215
  145. package/scripts/build-web.ts +130 -130
  146. package/scripts/postinstall.js +152 -152
  147. package/bin/bolloon.js +0 -157
  148. package/dist/constraint-runtime/src/_archive_helper.js +0 -9
  149. package/dist/constraint-runtime/src/agent/coordinator.js +0 -48
  150. package/dist/constraint-runtime/src/agent/index.js +0 -1
  151. package/dist/constraint-runtime/src/assistant/index.js +0 -12
  152. package/dist/constraint-runtime/src/bootstrap/index.js +0 -12
  153. package/dist/constraint-runtime/src/bootstrap_graph.js +0 -13
  154. package/dist/constraint-runtime/src/bridge/index.js +0 -12
  155. package/dist/constraint-runtime/src/buddy/index.js +0 -12
  156. package/dist/constraint-runtime/src/cli/index.js +0 -12
  157. package/dist/constraint-runtime/src/command_graph.js +0 -10
  158. package/dist/constraint-runtime/src/commands.js +0 -60
  159. package/dist/constraint-runtime/src/components/index.js +0 -12
  160. package/dist/constraint-runtime/src/constants/index.js +0 -12
  161. package/dist/constraint-runtime/src/constraint/budget.js +0 -22
  162. package/dist/constraint-runtime/src/constraint/index.js +0 -2
  163. package/dist/constraint-runtime/src/constraint/permission.js +0 -20
  164. package/dist/constraint-runtime/src/context.js +0 -30
  165. package/dist/constraint-runtime/src/coordinator/index.js +0 -12
  166. package/dist/constraint-runtime/src/cost_hook.js +0 -4
  167. package/dist/constraint-runtime/src/cost_tracker.js +0 -8
  168. package/dist/constraint-runtime/src/deferred_init.js +0 -10
  169. package/dist/constraint-runtime/src/direct_modes.js +0 -6
  170. package/dist/constraint-runtime/src/dynamic-tool-loader.js +0 -85
  171. package/dist/constraint-runtime/src/entrypoints/index.js +0 -12
  172. package/dist/constraint-runtime/src/execution_registry.js +0 -44
  173. package/dist/constraint-runtime/src/history.js +0 -9
  174. package/dist/constraint-runtime/src/hooks/index.js +0 -12
  175. package/dist/constraint-runtime/src/index.js +0 -26
  176. package/dist/constraint-runtime/src/ink.js +0 -4
  177. package/dist/constraint-runtime/src/keybindings/index.js +0 -12
  178. package/dist/constraint-runtime/src/memdir/index.js +0 -12
  179. package/dist/constraint-runtime/src/migrations/index.js +0 -12
  180. package/dist/constraint-runtime/src/models.js +0 -1
  181. package/dist/constraint-runtime/src/moreright/index.js +0 -12
  182. package/dist/constraint-runtime/src/native_ts/index.js +0 -12
  183. package/dist/constraint-runtime/src/output_styles/index.js +0 -12
  184. package/dist/constraint-runtime/src/parity_audit.js +0 -12
  185. package/dist/constraint-runtime/src/plugins/index.js +0 -12
  186. package/dist/constraint-runtime/src/port_manifest.js +0 -11
  187. package/dist/constraint-runtime/src/prefetch.js +0 -9
  188. package/dist/constraint-runtime/src/query.js +0 -1
  189. package/dist/constraint-runtime/src/remote/index.js +0 -12
  190. package/dist/constraint-runtime/src/remote_runtime.js +0 -9
  191. package/dist/constraint-runtime/src/runtime/index.js +0 -1
  192. package/dist/constraint-runtime/src/runtime/session.js +0 -35
  193. package/dist/constraint-runtime/src/schemas/index.js +0 -12
  194. package/dist/constraint-runtime/src/screens/index.js +0 -12
  195. package/dist/constraint-runtime/src/server/index.js +0 -12
  196. package/dist/constraint-runtime/src/services/index.js +0 -12
  197. package/dist/constraint-runtime/src/session_store.js +0 -22
  198. package/dist/constraint-runtime/src/setup.js +0 -30
  199. package/dist/constraint-runtime/src/skills/index.js +0 -1
  200. package/dist/constraint-runtime/src/skills/skill-registry.js +0 -28
  201. package/dist/constraint-runtime/src/state/index.js +0 -12
  202. package/dist/constraint-runtime/src/system_init.js +0 -20
  203. package/dist/constraint-runtime/src/thinking/engine.js +0 -42
  204. package/dist/constraint-runtime/src/thinking/index.js +0 -1
  205. package/dist/constraint-runtime/src/tool_pool.js +0 -8
  206. package/dist/constraint-runtime/src/tools/OpenCLI/execAdapter.js +0 -7
  207. package/dist/constraint-runtime/src/tools/OpenCLI/listAdapters.js +0 -7
  208. package/dist/constraint-runtime/src/tools/OpenCLI/runCommand.js +0 -7
  209. package/dist/constraint-runtime/src/tools/SafeSDK/confirmTransaction.js +0 -6
  210. package/dist/constraint-runtime/src/tools/SafeSDK/createTransaction.js +0 -8
  211. package/dist/constraint-runtime/src/tools/SafeSDK/executeTransaction.js +0 -6
  212. package/dist/constraint-runtime/src/tools/SafeSDK/getBalance.js +0 -6
  213. package/dist/constraint-runtime/src/tools/SafeSDK/getPendingTransactions.js +0 -6
  214. package/dist/constraint-runtime/src/tools/SafeSDK/proposeTransaction.js +0 -6
  215. package/dist/constraint-runtime/src/tools.js +0 -80
  216. package/dist/constraint-runtime/src/transcript.js +0 -19
  217. package/dist/constraint-runtime/src/types/index.js +0 -12
  218. package/dist/constraint-runtime/src/upstream_proxy/index.js +0 -12
  219. package/dist/constraint-runtime/src/utils/index.js +0 -12
  220. package/dist/constraint-runtime/src/vim/index.js +0 -12
  221. package/dist/constraint-runtime/src/voice/index.js +0 -12
  222. package/dist/constraint-runtime/tests/agent.test.js +0 -16
  223. package/dist/constraint-runtime/tests/constraint.test.js +0 -41
  224. package/dist/constraint-runtime/tests/skill.test.js +0 -19
  225. package/dist/constraint-runtime/tests/thinking.test.js +0 -22
  226. package/dist/pi-ecosystem-colony/index.js +0 -365
  227. package/dist/social/ant-colony/AdaptiveHeartbeat.js +0 -101
  228. package/dist/social/ant-colony/PheromoneEngine.js +0 -227
  229. package/dist/social/ant-colony/index.js +0 -6
  230. package/dist/social/ant-colony/types.js +0 -24
  231. package/dist/test/ai-judgment-test.js +0 -80
  232. package/dist/test/bollharness-integration.test.js +0 -318
  233. package/dist/test/channel-agent-multi-dialogue.js +0 -205
  234. package/dist/test/channel-heartbeat-agent-test.js +0 -201
  235. package/dist/test/constraint-layer.test.js +0 -164
  236. package/dist/test/diap-identity-test.js +0 -172
  237. package/dist/test/diap-quick-test.js +0 -62
  238. package/dist/test/global-shared-context.test.js +0 -315
  239. package/dist/test/harness-judgment-injection.test.js +0 -246
  240. package/dist/test/harness-workflow-integrator-test.js +0 -228
  241. package/dist/test/human-value-store.test.js +0 -243
  242. package/dist/test/hybrid-integration-test.js +0 -118
  243. package/dist/test/hybrid-messenger-verify.js +0 -55
  244. package/dist/test/iroh-bistream-debug.js +0 -38
  245. package/dist/test/iroh-communication.test.js +0 -66
  246. package/dist/test/iroh-debug-test.js +0 -57
  247. package/dist/test/iroh-diap-test.js +0 -71
  248. package/dist/test/iroh-direct-connect.js +0 -55
  249. package/dist/test/iroh-e2e-fixed.js +0 -89
  250. package/dist/test/iroh-e2e-same-process.js +0 -63
  251. package/dist/test/iroh-e2e.js +0 -66
  252. package/dist/test/iroh-final-e2e.js +0 -72
  253. package/dist/test/iroh-relay-test.js +0 -37
  254. package/dist/test/iroh-simple-test.js +0 -41
  255. package/dist/test/iroh-transport-verify.js +0 -54
  256. package/dist/test/iroh-transport.test.js +0 -37
  257. package/dist/test/iroh-two-nodes.js +0 -70
  258. package/dist/test/iroh-verify.js +0 -44
  259. package/dist/test/judgment-decision.test.js +0 -219
  260. package/dist/test/llm-judgment-integration.test.js +0 -220
  261. package/dist/test/p2p-agent-complex-dialogue.js +0 -385
  262. package/dist/test/p2p-agent-dialogue.js +0 -341
  263. package/dist/test/p2p-agent-full-bidirectional.js +0 -510
  264. package/dist/test/p2p-agent-harness-flow.js +0 -437
  265. package/dist/test/p2p-agent-harness-single.js +0 -143
  266. package/dist/test/p2p-ai-dialogue-test.js +0 -318
  267. package/dist/test/p2p-cid-connect-test.js +0 -195
  268. package/dist/test/p2p-connect-receiver.js +0 -69
  269. package/dist/test/p2p-doc-transfer.js +0 -110
  270. package/dist/test/p2p-identity-page-test.js +0 -77
  271. package/dist/test/p2p-iroh-test.js +0 -171
  272. package/dist/test/p2p-minimal-test.js +0 -241
  273. package/dist/test/p2p-node-1.js +0 -148
  274. package/dist/test/p2p-node-2.js +0 -148
  275. package/dist/test/p2p-server.js +0 -281
  276. package/dist/test/p2p-two-nodes-test.js +0 -438
  277. package/dist/test/pi-sdk.test.js +0 -44
  278. package/dist/test/set-persona.js +0 -40
  279. package/dist/test/simple.test.js +0 -9
  280. package/dist/test/storage-integration.test.js +0 -150
  281. package/dist/test/subagent-manager.test.js +0 -276
  282. package/dist/test/test-gate-flow.test.js +0 -81
  283. package/dist/test/workflow-engine.test.js +0 -87
  284. package/dist/test/workflow-pivot-loop.test.js +0 -246
@@ -0,0 +1,216 @@
1
+ /**
2
+ * peer-resource-bridge.ts — 4 类资源 (groups/function/exportment/science) 的
3
+ * 本地读 + 远端落盘的统一封装.
4
+ *
5
+ * 设计目的 (2026-07-05):
6
+ * peer-fs.ts 已经有完整路径 helpers (writeGroup/writeFunction/...) + reader (listPeerResources).
7
+ * server.ts 三处要调 (两个 manifest.exchange.reply 落盘 + 一个 manifest.exchange 发送),
8
+ * 每处手写 4 个 await 又啰嗦又容易漏. 这里抽出来.
9
+ *
10
+ * 本地读: ~/.bolloon/local-resources/<category>/<id>.md frontmatter
11
+ * 远端落: peerFs.writeGroup/Function/Exportment/Science (atomic, 人类可读 md)
12
+ *
13
+ * frontmatter 字段就是类型本身的字段 (id/name/description/...),
14
+ * description 从 frontmatter 后面的第一个段落拿.
15
+ */
16
+ import * as fs from 'fs/promises';
17
+ import * as path from 'path';
18
+ import * as os from 'os';
19
+ import * as peerFs from '../network/peer-fs.js';
20
+ const HOME = process.env.BOLLOON_HOME || path.join(os.homedir(), '.bolloon');
21
+ export const LOCAL_RESOURCES_ROOT = path.join(HOME, 'local-resources');
22
+ const EMPTY = { groups: [], functions: [], exportments: [], sciences: [] };
23
+ /**
24
+ * 简单 frontmatter 解析: 只支持 key: value / key: [..] (本文件自产自销, 不引第三方).
25
+ */
26
+ function parseFrontmatter(text) {
27
+ const m = text.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
28
+ if (!m)
29
+ return { fields: {}, body: text };
30
+ const fields = {};
31
+ for (const line of m[1].split('\n')) {
32
+ const kv = line.match(/^([A-Za-z_][A-Za-z0-9_]*):\s*(.*)$/);
33
+ if (!kv)
34
+ continue;
35
+ const key = kv[1];
36
+ let raw = kv[2].trim();
37
+ if (raw.startsWith('[') && raw.endsWith(']')) {
38
+ try {
39
+ fields[key] = JSON.parse(raw);
40
+ continue;
41
+ }
42
+ catch { }
43
+ }
44
+ if ((raw.startsWith('"') && raw.endsWith('"')) || (raw.startsWith("'") && raw.endsWith("'"))) {
45
+ try {
46
+ fields[key] = JSON.parse(raw);
47
+ continue;
48
+ }
49
+ catch { }
50
+ }
51
+ fields[key] = raw;
52
+ }
53
+ return { fields, body: m[2].trim() };
54
+ }
55
+ /**
56
+ * 从 ~/.bolloon/local-resources/<category>/<id>.md 读所有本地资源.
57
+ * 文件不存在 / 目录不存在 → 返回空数组 (不报错, 跟 peer-fs 风格一致).
58
+ */
59
+ async function readCategoryDir(category) {
60
+ try {
61
+ const dir = path.join(LOCAL_RESOURCES_ROOT, category);
62
+ const entries = await fs.readdir(dir);
63
+ return entries.filter((e) => e.endsWith('.md')).map((e) => path.join(dir, e));
64
+ }
65
+ catch {
66
+ return [];
67
+ }
68
+ }
69
+ async function readGroupFile(p) {
70
+ try {
71
+ const raw = await fs.readFile(p, 'utf-8');
72
+ const { fields, body } = parseFrontmatter(raw);
73
+ if (!fields.id)
74
+ return null;
75
+ return {
76
+ id: String(fields.id),
77
+ name: String(fields.name || fields.id),
78
+ description: body || undefined,
79
+ visibility: fields.visibility,
80
+ memberCount: typeof fields.memberCount === 'number' ? fields.memberCount : undefined,
81
+ };
82
+ }
83
+ catch {
84
+ return null;
85
+ }
86
+ }
87
+ async function readFunctionFile(p) {
88
+ try {
89
+ const raw = await fs.readFile(p, 'utf-8');
90
+ const { fields, body } = parseFrontmatter(raw);
91
+ if (!fields.capability)
92
+ return null;
93
+ return {
94
+ capability: String(fields.capability),
95
+ description: body || undefined,
96
+ mediaType: fields.mediaType,
97
+ endpoint: fields.endpoint ? String(fields.endpoint) : undefined,
98
+ };
99
+ }
100
+ catch {
101
+ return null;
102
+ }
103
+ }
104
+ async function readExportmentFile(p) {
105
+ try {
106
+ const raw = await fs.readFile(p, 'utf-8');
107
+ const { fields, body } = parseFrontmatter(raw);
108
+ if (!fields.name)
109
+ return null;
110
+ return {
111
+ name: String(fields.name),
112
+ description: body || undefined,
113
+ genre: fields.genre ? String(fields.genre) : undefined,
114
+ minPlayers: typeof fields.minPlayers === 'number' ? fields.minPlayers : undefined,
115
+ maxPlayers: typeof fields.maxPlayers === 'number' ? fields.maxPlayers : undefined,
116
+ };
117
+ }
118
+ catch {
119
+ return null;
120
+ }
121
+ }
122
+ async function readScienceFile(p) {
123
+ try {
124
+ const raw = await fs.readFile(p, 'utf-8');
125
+ const { fields, body } = parseFrontmatter(raw);
126
+ if (!fields.id)
127
+ return null;
128
+ return {
129
+ id: String(fields.id),
130
+ title: String(fields.title || fields.id),
131
+ description: body || undefined,
132
+ status: fields.status,
133
+ tags: Array.isArray(fields.tags) ? fields.tags.map(String) : undefined,
134
+ };
135
+ }
136
+ catch {
137
+ return null;
138
+ }
139
+ }
140
+ /**
141
+ * 读本机所有 4 类资源. 任何失败 → 该类别返回空 (不阻塞其他类别).
142
+ */
143
+ export async function loadLocalResources() {
144
+ const out = { ...EMPTY };
145
+ const [gFiles, fFiles, eFiles, sFiles] = await Promise.all([
146
+ readCategoryDir('groups'),
147
+ readCategoryDir('functions'),
148
+ readCategoryDir('exportments'),
149
+ readCategoryDir('sciences'),
150
+ ]);
151
+ for (const f of gFiles) {
152
+ const v = await readGroupFile(f);
153
+ if (v)
154
+ out.groups.push(v);
155
+ }
156
+ for (const f of fFiles) {
157
+ const v = await readFunctionFile(f);
158
+ if (v)
159
+ out.functions.push(v);
160
+ }
161
+ for (const f of eFiles) {
162
+ const v = await readExportmentFile(f);
163
+ if (v)
164
+ out.exportments.push(v);
165
+ }
166
+ for (const f of sFiles) {
167
+ const v = await readScienceFile(f);
168
+ if (v)
169
+ out.sciences.push(v);
170
+ }
171
+ return out;
172
+ }
173
+ /**
174
+ * 把 manifest 里的 4 类资源落盘到 peerFs 对应目录.
175
+ * 静默容错: 单条失败不影响其他.
176
+ */
177
+ export async function writeRemoteResources(publicKey, m) {
178
+ let groups = 0, functions = 0, exportments = 0, sciences = 0;
179
+ if (Array.isArray(m.groups)) {
180
+ for (const g of m.groups) {
181
+ try {
182
+ await peerFs.writeGroup(publicKey, g);
183
+ groups++;
184
+ }
185
+ catch { }
186
+ }
187
+ }
188
+ if (Array.isArray(m.functions)) {
189
+ for (const f of m.functions) {
190
+ try {
191
+ await peerFs.writeFunction(publicKey, f);
192
+ functions++;
193
+ }
194
+ catch { }
195
+ }
196
+ }
197
+ if (Array.isArray(m.exportments)) {
198
+ for (const e of m.exportments) {
199
+ try {
200
+ await peerFs.writeExportment(publicKey, e);
201
+ exportments++;
202
+ }
203
+ catch { }
204
+ }
205
+ }
206
+ if (Array.isArray(m.sciences)) {
207
+ for (const s of m.sciences) {
208
+ try {
209
+ await peerFs.writeScience(publicKey, s);
210
+ sciences++;
211
+ }
212
+ catch { }
213
+ }
214
+ }
215
+ return { groups, functions, exportments, sciences };
216
+ }
@@ -81,21 +81,21 @@ function getLLM() {
81
81
  }
82
82
  return cachedModel;
83
83
  }
84
- const CORRELATION_PROMPT = `你是"判断力关联分析器"。给定两条 judgment:
85
- A: {a}
86
- B: {b}
87
-
88
- 它们经常在同一对话里被同时注入 (共现 {co} 次).
89
- 判断 A 与 B 的因果关系:
90
- - "A→B": A 引发 B (A 概念在 B 之前)
91
- - "B→A": B 引发 A
92
- - "common_cause": 共同原因 (e.g. 都是某场景触发)
93
- - "unclear": 关系不明确
94
-
95
- 输出严格 JSON:
96
- {
97
- "direction": "A→B" | "B→A" | "common_cause" | "unclear",
98
- "explanation": "≤100 字解释, 含 1 个具体例"
84
+ const CORRELATION_PROMPT = `你是"判断力关联分析器"。给定两条 judgment:
85
+ A: {a}
86
+ B: {b}
87
+
88
+ 它们经常在同一对话里被同时注入 (共现 {co} 次).
89
+ 判断 A 与 B 的因果关系:
90
+ - "A→B": A 引发 B (A 概念在 B 之前)
91
+ - "B→A": B 引发 A
92
+ - "common_cause": 共同原因 (e.g. 都是某场景触发)
93
+ - "unclear": 关系不明确
94
+
95
+ 输出严格 JSON:
96
+ {
97
+ "direction": "A→B" | "B→A" | "common_cause" | "unclear",
98
+ "explanation": "≤100 字解释, 含 1 个具体例"
99
99
  }`;
100
100
  async function explainPair(judgmentA, judgmentB, coOccurrence) {
101
101
  const fallback = { direction: 'unclear', explanation: '(LLM 不可用, 仅显示统计)' };
@@ -213,21 +213,21 @@ export async function runCorrelationAnalysis(opts = {}) {
213
213
  }
214
214
  return out;
215
215
  }
216
- const INTERVENTION_PROMPT = `你是"判断力干预分析器"。判断力库有一条 judgment, 用户想评估它的边际贡献.
217
- 给定:
218
- - judgment: {judgment}
219
- - 上次用过的场景 (user 输入 + AI 回复): {scenario}
220
- - 同时存在的相邻 judgment (供参考): {peers}
221
-
222
- 模拟反事实推理: 如果库**没有**这条 judgment, AI 在同一场景下回答会怎么变?
223
-
224
- 输出严格 JSON:
225
- {
226
- "causalEffect": 0.0-1.0, // 0 = 无影响, 1 = 行为完全变
227
- "reasoning": "2-3 步推理, 含 1 个具体例",
228
- "confidence": 0.0-1.0
229
- }
230
-
216
+ const INTERVENTION_PROMPT = `你是"判断力干预分析器"。判断力库有一条 judgment, 用户想评估它的边际贡献.
217
+ 给定:
218
+ - judgment: {judgment}
219
+ - 上次用过的场景 (user 输入 + AI 回复): {scenario}
220
+ - 同时存在的相邻 judgment (供参考): {peers}
221
+
222
+ 模拟反事实推理: 如果库**没有**这条 judgment, AI 在同一场景下回答会怎么变?
223
+
224
+ 输出严格 JSON:
225
+ {
226
+ "causalEffect": 0.0-1.0, // 0 = 无影响, 1 = 行为完全变
227
+ "reasoning": "2-3 步推理, 含 1 个具体例",
228
+ "confidence": 0.0-1.0
229
+ }
230
+
231
231
  注意: causalEffect < 0 也合法 (如"没有这条 AI 反而更好" — 库污染)`;
232
232
  export async function runIntervention(judgmentId, opts = {}) {
233
233
  const fallback = {
@@ -273,27 +273,27 @@ export async function runIntervention(judgmentId, opts = {}) {
273
273
  return fallback;
274
274
  }
275
275
  }
276
- const COUNTERFACTUAL_PROMPT = `你是"判断力反事实审计员"。某次 AI 回复违反了注入的 judgment. 判断是库设计问题还是 LLM 偶然违规.
277
-
278
- 事件:
279
- - 用户: {userInput}
280
- - AI 回复: {aiReply}
281
- - 违反原则: {principles}
282
-
283
- 构造 3 个反事实 scenario:
284
- 1. 删去最相关那条 judgment
285
- 2. 把那条 judgment 改成反向 (例如"必须"→"避免")
286
- 3. 删去整个 channel 的 judgment 库 (空库)
287
-
288
- 每个 scenario 模拟 AI 在该库下的回答, 判断还会不会违规.
289
-
290
- 输出严格 JSON:
291
- {
292
- "scenarios": [
293
- { "modification": "...", "outcomeCompliant": true/false, "explanation": "≤100 字" }
294
- ],
295
- "verdict": "库设计合理" | "建议调库" | "需更多数据",
296
- "recomendaciones": "≤200 字, ≤3 条建议"
276
+ const COUNTERFACTUAL_PROMPT = `你是"判断力反事实审计员"。某次 AI 回复违反了注入的 judgment. 判断是库设计问题还是 LLM 偶然违规.
277
+
278
+ 事件:
279
+ - 用户: {userInput}
280
+ - AI 回复: {aiReply}
281
+ - 违反原则: {principles}
282
+
283
+ 构造 3 个反事实 scenario:
284
+ 1. 删去最相关那条 judgment
285
+ 2. 把那条 judgment 改成反向 (例如"必须"→"避免")
286
+ 3. 删去整个 channel 的 judgment 库 (空库)
287
+
288
+ 每个 scenario 模拟 AI 在该库下的回答, 判断还会不会违规.
289
+
290
+ 输出严格 JSON:
291
+ {
292
+ "scenarios": [
293
+ { "modification": "...", "outcomeCompliant": true/false, "explanation": "≤100 字" }
294
+ ],
295
+ "verdict": "库设计合理" | "建议调库" | "需更多数据",
296
+ "recomendaciones": "≤200 字, ≤3 条建议"
297
297
  }`;
298
298
  export async function runCounterfactualAudit(opts) {
299
299
  const fallback = {
@@ -0,0 +1,126 @@
1
+ /**
2
+ * Judgment Cleanup — 检测并清理测试/灌水数据
3
+ *
4
+ * 垃圾来源:
5
+ * 1. 早期 test 文件直接调 storeHumanJudgment() 写 test fixture
6
+ * 2. 用户在 UI 「记录」时随手输的测试文本
7
+ * 3. D-hook (AI 自动蒸馏) 在 LLM 抽风时存了无意义内容
8
+ *
9
+ * 设计原则:
10
+ * - 启发式检测, 不依赖外部 LLM (避免循环依赖)
11
+ * - 删除 = 软删除 (status='rejected'), 保留审计追溯
12
+ * - 写入时拦截 (storeHumanJudgment) + 读取时过滤 (getRelevantValues) 双保险
13
+ */
14
+ import * as fs from 'fs/promises';
15
+ import * as path from 'path';
16
+ import * as os from 'os';
17
+ /**
18
+ * 命中任一即视为垃圾
19
+ * 注: 都是精确短语, 不会误伤含 "测试" 但有实质内容的判断力
20
+ */
21
+ export const JUNK_DECISION_PATTERNS = [
22
+ /^loadAll\s*测试[你您\s::/_-]*$/i,
23
+ /^Bolloon\s*bootstrap\s*测试[你您原则]*$/i,
24
+ /^[涨升]?\s*(rising|stale|cache|unused|健康|稳定|rising|上升|下降)\s*原则$/i,
25
+ /^(测试|test|example|示例)\s*$/i,
26
+ /^[测试tT]+$/,
27
+ /^(foo|bar|baz|hello world)\s*$/i,
28
+ ];
29
+ /**
30
+ * 综合启发式: 内容是否像测试灌水?
31
+ */
32
+ export function isJunkJudgment(j) {
33
+ if (!j || typeof j !== 'object')
34
+ return true;
35
+ const decision = String(j.decision ?? '').trim();
36
+ if (!decision)
37
+ return true; // 完全空 = 必定垃圾
38
+ // 启发式 1: 决策文本命中已知垃圾 pattern
39
+ if (JUNK_DECISION_PATTERNS.some((re) => re.test(decision)))
40
+ return true;
41
+ // 启发式 2: 短决策 + 无 values + 无 reasons (实质内容缺失)
42
+ const hasValues = Array.isArray(j.values_derived) && j.values_derived.length > 0;
43
+ const hasReasons = Array.isArray(j.reasons) && j.reasons.length > 0 &&
44
+ j.reasons.some((r) => r && String(r).trim().length > 0);
45
+ if (!hasValues && !hasReasons && decision.length < 12)
46
+ return true;
47
+ // 启发式 3: data corruption — 无 timestamp, 无 domain, decision 短
48
+ const hasTs = !!j.timestamp;
49
+ const domain = j.context?.domain;
50
+ if (!hasTs && (!domain || domain === 'general') && decision.length < 12)
51
+ return true;
52
+ // 启发式 4: decision 全是 whitespace / 标点 / 重复字符
53
+ if (/^[.\s,。、,\-_=:;!?]{0,8}$/.test(decision))
54
+ return true;
55
+ if (/^(.)\1{3,}$/.test(decision))
56
+ return true; // "aaaa"
57
+ return false;
58
+ }
59
+ /**
60
+ * 把判断力分桶: kept (可保留) + removed (应清理)
61
+ */
62
+ export function classifyJudgments(judgments, opts = {}) {
63
+ const kept = [];
64
+ const removed = [];
65
+ const softDelete = opts.softDelete !== false; // 默认软删除
66
+ for (const j of judgments) {
67
+ if (isJunkJudgment(j)) {
68
+ // 软删除: 标记 status='rejected' 而非真正移除, 保留审计追溯
69
+ if (softDelete) {
70
+ removed.push({ ...j, status: 'rejected' });
71
+ }
72
+ else {
73
+ removed.push(j);
74
+ }
75
+ }
76
+ else {
77
+ kept.push(j);
78
+ }
79
+ }
80
+ return { kept, removed };
81
+ }
82
+ const VALUE_STORE_DIR = path.join(os.homedir(), '.bolloon', 'human-values');
83
+ const JUDGMENTS_FILE = path.join(VALUE_STORE_DIR, 'judgments.json');
84
+ async function ensureDir() {
85
+ await fs.mkdir(VALUE_STORE_DIR, { recursive: true });
86
+ }
87
+ async function readJudgmentsFile() {
88
+ await ensureDir();
89
+ try {
90
+ const raw = await fs.readFile(JUDGMENTS_FILE, 'utf-8');
91
+ const arr = JSON.parse(raw);
92
+ return Array.isArray(arr) ? arr : [];
93
+ }
94
+ catch {
95
+ return [];
96
+ }
97
+ }
98
+ /**
99
+ * 干跑 (推荐先跑这个看会清除多少):
100
+ * 返回报告, 不写盘
101
+ */
102
+ export async function dryCleanup() {
103
+ const judgments = await readJudgmentsFile();
104
+ const { kept, removed } = classifyJudgments(judgments, { softDelete: false });
105
+ return {
106
+ totalBefore: judgments.length,
107
+ totalAfter: kept.length,
108
+ removed: removed.length,
109
+ sample: removed.slice(0, 10).map((j) => ({ id: j.id, decision: j.decision })),
110
+ };
111
+ }
112
+ /**
113
+ * 实际清理: 软删除 + 写回磁盘
114
+ * 保留 status='rejected' 的记录在盘上 (审计追溯)
115
+ */
116
+ export async function runCleanup() {
117
+ const judgments = await readJudgmentsFile();
118
+ const { kept, removed } = classifyJudgments(judgments, { softDelete: true });
119
+ const finalized = [...kept, ...removed];
120
+ await fs.writeFile(JUDGMENTS_FILE, JSON.stringify(finalized, null, 2), 'utf-8');
121
+ return {
122
+ totalBefore: judgments.length,
123
+ totalAfter: kept.length,
124
+ removed: removed.length,
125
+ };
126
+ }
@@ -4,39 +4,39 @@
4
4
  * - 演化对齐: 判定新判断力与已有判断力的关系 (merge/contradict/unrelated)
5
5
  */
6
6
  import { getModel } from '../llm/pi-ai.js';
7
- const DISTILL_SYSTEM_PROMPT = `你是一个"判断力蒸馏器"。从给定的对话片段中,提取出**一条**可以长期复用的判断力原则。
8
-
9
- 要求:
10
- - 长度 30-80 字(中文字符),软目标 50 字
11
- - 用陈述句,不要"我觉得/我想要"这种主观前缀
12
- - 要有可操作性,能被未来的自己/AI 引用
13
- - 如果对话里没有值得提炼的判断力,返回 {"value": null}
14
-
15
- 输出格式(严格 JSON,无其他文字):
16
- {
17
- "value": "<30-80 字的判断力>" | null,
18
- "category": "rule" | "preference" | "trajectory" | "reward",
19
- "confidence": 0.0-1.0,
20
- "evidence": "<原文中支持这句话的关键句,不超过 30 字>"
7
+ const DISTILL_SYSTEM_PROMPT = `你是一个"判断力蒸馏器"。从给定的对话片段中,提取出**一条**可以长期复用的判断力原则。
8
+
9
+ 要求:
10
+ - 长度 30-80 字(中文字符),软目标 50 字
11
+ - 用陈述句,不要"我觉得/我想要"这种主观前缀
12
+ - 要有可操作性,能被未来的自己/AI 引用
13
+ - 如果对话里没有值得提炼的判断力,返回 {"value": null}
14
+
15
+ 输出格式(严格 JSON,无其他文字):
16
+ {
17
+ "value": "<30-80 字的判断力>" | null,
18
+ "category": "rule" | "preference" | "trajectory" | "reward",
19
+ "confidence": 0.0-1.0,
20
+ "evidence": "<原文中支持这句话的关键句,不超过 30 字>"
21
21
  }`;
22
- const EVOLVE_SYSTEM_PROMPT = `你是"判断力演化对齐器"。对比一条新判断力与已有判断力,判定关系。
23
-
24
- 新判断力:
25
- {new_value}
26
-
27
- 已有判断力列表(最多 10 条):
28
- {existing_list}
29
-
30
- 对每条已有判断力,判定:
31
- - "merge": 新判断力是这条的更新版/具体版/纠正版 → 旧条应被 superseded
32
- - "contradict": 新判断力与这条方向相反(例如"保守"vs"激进") → 旧条应被 superseded
33
- - "unrelated": 两者主题不同,各自保留
34
-
35
- 输出严格 JSON:
36
- {
37
- "relations": [
38
- {"id": "...", "relation": "merge" | "contradict" | "unrelated", "reason": "≤20 字"}
39
- ]
22
+ const EVOLVE_SYSTEM_PROMPT = `你是"判断力演化对齐器"。对比一条新判断力与已有判断力,判定关系。
23
+
24
+ 新判断力:
25
+ {new_value}
26
+
27
+ 已有判断力列表(最多 10 条):
28
+ {existing_list}
29
+
30
+ 对每条已有判断力,判定:
31
+ - "merge": 新判断力是这条的更新版/具体版/纠正版 → 旧条应被 superseded
32
+ - "contradict": 新判断力与这条方向相反(例如"保守"vs"激进") → 旧条应被 superseded
33
+ - "unrelated": 两者主题不同,各自保留
34
+
35
+ 输出严格 JSON:
36
+ {
37
+ "relations": [
38
+ {"id": "...", "relation": "merge" | "contradict" | "unrelated", "reason": "≤20 字"}
39
+ ]
40
40
  }`;
41
41
  let cachedModel = null;
42
42
  function getDistillModel() {
@@ -56,13 +56,13 @@ export async function detectIfWorthStoring(turns) {
56
56
  if (!model)
57
57
  return fallback;
58
58
  const conversation = formatTurns(turns);
59
- const prompt = `请判断以下对话是否包含"值得长期保留的判断力"(用户的偏好/规则/原则/价值观)。
60
- 如果包含,返回 {"worth": true, "reason": "≤20 字理由"}
61
- 如果不包含,返回 {"worth": false, "reason": "≤20 字理由"}
62
-
63
- 对话:
64
- ${conversation}
65
-
59
+ const prompt = `请判断以下对话是否包含"值得长期保留的判断力"(用户的偏好/规则/原则/价值观)。
60
+ 如果包含,返回 {"worth": true, "reason": "≤20 字理由"}
61
+ 如果不包含,返回 {"worth": false, "reason": "≤20 字理由"}
62
+
63
+ 对话:
64
+ ${conversation}
65
+
66
66
  输出严格 JSON:`;
67
67
  try {
68
68
  const res = await withRetry(() => model.chat(prompt, '判断力检测专家'));
@@ -84,9 +84,9 @@ export async function distillFromConversation(turns) {
84
84
  if (!model)
85
85
  return fallback;
86
86
  const conversation = formatTurns(turns);
87
- const userPrompt = `对话上下文(最多 10 轮):
88
- ${conversation}
89
-
87
+ const userPrompt = `对话上下文(最多 10 轮):
88
+ ${conversation}
89
+
90
90
  输出:`;
91
91
  try {
92
92
  const res = await withRetry(() => model.chat(userPrompt, DISTILL_SYSTEM_PROMPT));
@@ -143,20 +143,20 @@ async function llmDistill(rawInput, trigger, context, conversationHistory) {
143
143
  const historyText = conversationHistory
144
144
  ? conversationHistory.slice(-5).join('\n')
145
145
  : 'No history';
146
- const prompt = `从以下人类输入中提取判断力原理。
147
-
148
- 输入类型: ${trigger}
149
- 输入内容: ${rawInput}
150
- 上下文: ${context}
151
- 对话历史:
152
- ${historyText}
153
-
154
- 请提取:
155
- 1. type: rule(明确规则) | preference(偏好) | trajectory(行为轨迹) | reward(奖励信号)
156
- 2. content: 凝练后的原理(简洁,1-2句话)
157
- 3. confidence: 0.0-1.0 的置信度
158
- 4. evidence: 支持证据(如有)
159
-
146
+ const prompt = `从以下人类输入中提取判断力原理。
147
+
148
+ 输入类型: ${trigger}
149
+ 输入内容: ${rawInput}
150
+ 上下文: ${context}
151
+ 对话历史:
152
+ ${historyText}
153
+
154
+ 请提取:
155
+ 1. type: rule(明确规则) | preference(偏好) | trajectory(行为轨迹) | reward(奖励信号)
156
+ 2. content: 凝练后的原理(简洁,1-2句话)
157
+ 3. confidence: 0.0-1.0 的置信度
158
+ 4. evidence: 支持证据(如有)
159
+
160
160
  直接输出JSON格式,不需要解释。`;
161
161
  try {
162
162
  const response = await llmModel.chat(`对话: ${historyText}\n\n输入: ${rawInput}`, `你是判断力提取专家。从人类输入中提取判断力原理。输入类型: ${trigger}`);