@bolloon/bolloon-agent 0.4.5 → 0.4.6

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 (206) hide show
  1. package/README.md +135 -135
  2. package/bin/bolloon-cli.cjs +183 -183
  3. package/bin/bolloon.cjs +0 -0
  4. package/bin/bolloon.js +157 -0
  5. package/dist/agents/constraint-layer.js +19 -19
  6. package/dist/agents/judgment-protocol.js +14 -14
  7. package/dist/agents/pi-sdk-tools.js +62 -45
  8. package/dist/agents/pi-sdk-types.js +12 -12
  9. package/dist/agents/pi-sdk.js +103 -90
  10. package/dist/agents/skill-organizer.js +19 -19
  11. package/dist/agents/skill-writer.js +15 -3
  12. package/dist/agents/workflow-pivot-loop.js +13 -3
  13. package/dist/bollharness/src/scripts/deploy-guard.js +8 -8
  14. package/dist/bollharness-integration/context-router-judgment.js +4 -4
  15. package/dist/bollharness-integration/context-router.js +292 -292
  16. package/dist/bollharness-integration/gate-state-machine.js +13 -13
  17. package/dist/bollharness-integration/llm-judgment-engine.js +134 -134
  18. package/dist/bollharness-integration/skill-adapter.js +21 -21
  19. package/dist/bootstrap/chat-archiver.js +14 -14
  20. package/dist/bootstrap/context-os.js +24 -24
  21. package/dist/bootstrap/memory-compressor.js +14 -14
  22. package/dist/cli/ink-app.js +18 -0
  23. package/dist/cli-entry.js +36 -36
  24. package/dist/context-compaction/auto-compact.js +7 -7
  25. package/dist/electron/first-run.js +54 -54
  26. package/dist/electron-build/electron/first-run.js +54 -54
  27. package/dist/electron-preload.js.map +1 -1
  28. package/dist/electron.js.map +1 -1
  29. package/dist/index.js +222 -138
  30. package/dist/llm/llm-judgment-client.js +102 -102
  31. package/dist/llm/pi-ai.js +48 -48
  32. package/dist/llm/system-prompt/layers/channel/human-async.md +41 -41
  33. package/dist/llm/system-prompt/layers/channel/local.md +14 -14
  34. package/dist/llm/system-prompt/layers/channel/p2p-agent.md +18 -18
  35. package/dist/llm/system-prompt/layers/channel/p2p-peer-sync.md +51 -51
  36. package/dist/llm/system-prompt/layers/channel/p2p-proactive.md +43 -43
  37. package/dist/llm/system-prompt/layers/channel/p2p-visitor.md +19 -19
  38. package/dist/llm/system-prompt/layers/channel/session-handoff.md +61 -61
  39. package/dist/llm/system-prompt/layers/core/artifacts_storage.md +89 -89
  40. package/dist/llm/system-prompt/layers/core/evenhandedness.md +21 -21
  41. package/dist/llm/system-prompt/layers/core/external-engagement.md +73 -73
  42. package/dist/llm/system-prompt/layers/core/hibs_reminders.md +15 -15
  43. package/dist/llm/system-prompt/layers/core/identity.md +48 -48
  44. package/dist/llm/system-prompt/layers/core/knowledge.md +17 -17
  45. package/dist/llm/system-prompt/layers/core/memory_system.md +12 -12
  46. package/dist/llm/system-prompt/layers/core/network_filesystem.md +28 -28
  47. package/dist/llm/system-prompt/layers/core/refusal.md +37 -37
  48. package/dist/llm/system-prompt/layers/core/tone.md +31 -31
  49. package/dist/llm/system-prompt/layers/core/tools.thin.md +13 -13
  50. package/dist/llm/system-prompt/layers/core/wellbeing.md +41 -41
  51. package/dist/llm/system-prompt/layers/role/architect.md +20 -20
  52. package/dist/llm/system-prompt/layers/role/expert.md +19 -19
  53. package/dist/llm/system-prompt/layers/role/implementer.md +15 -15
  54. package/dist/llm/system-prompt/layers/role/security.md +15 -15
  55. package/dist/llm/system-prompt/layers/tool/artifacts.md +72 -72
  56. package/dist/llm/system-prompt/layers/tool/bash.md +25 -25
  57. package/dist/llm/system-prompt/layers/tool/goal_handoff.md +77 -77
  58. package/dist/llm/system-prompt/layers/tool/hibs_api.md +171 -171
  59. package/dist/llm/system-prompt/layers/tool/image_search.md +70 -70
  60. package/dist/llm/system-prompt/layers/tool/manifest.md +89 -89
  61. package/dist/llm/system-prompt/layers/tool/mcp_apps.md +53 -53
  62. package/dist/llm/system-prompt/layers/tool/p2p_request.md +61 -61
  63. package/dist/llm/system-prompt/layers/tool/web_search.md +83 -83
  64. package/dist/llm/tool-manifest/ask_user_input.js +1 -1
  65. package/dist/llm/tool-manifest/bash.js +3 -3
  66. package/dist/llm/tool-manifest/create_file.js +4 -4
  67. package/dist/llm/tool-manifest/fetch_sports_data.js +3 -3
  68. package/dist/llm/tool-manifest/image_search.js +2 -2
  69. package/dist/llm/tool-manifest/index.js +0 -59
  70. package/dist/llm/tool-manifest/mcp.js +2 -2
  71. package/dist/llm/tool-manifest/message_compose.js +3 -3
  72. package/dist/llm/tool-manifest/places.js +2 -2
  73. package/dist/llm/tool-manifest/present_files.js +1 -1
  74. package/dist/llm/tool-manifest/recipe.js +2 -2
  75. package/dist/llm/tool-manifest/str_replace.js +5 -5
  76. package/dist/llm/tool-manifest/view.js +3 -3
  77. package/dist/llm/tool-manifest/weather.js +4 -4
  78. package/dist/llm/tool-manifest/web.js +4 -4
  79. package/dist/orbitdb/agent-tools.js +139 -0
  80. package/dist/orbitdb/kanban-store.js +259 -0
  81. package/dist/orbitdb/task-store.js +112 -0
  82. package/dist/pi-ecosystem-colony/index.js +365 -0
  83. package/dist/pi-ecosystem-judgment/causal-judge.js +51 -51
  84. package/dist/pi-ecosystem-judgment/distill-prompt.js +42 -42
  85. package/dist/pi-ecosystem-judgment/distillation.js +14 -14
  86. package/dist/pi-ecosystem-judgment/monitor-gate.js +28 -28
  87. package/dist/pi-ecosystem-judgment/value-injection.js +102 -102
  88. package/dist/security/context-router-tool.js +15 -15
  89. package/dist/security/tool-gate.js +2 -0
  90. package/dist/social/ant-colony/AdaptiveHeartbeat.js +101 -0
  91. package/dist/social/ant-colony/PheromoneEngine.js +227 -0
  92. package/dist/social/ant-colony/index.js +6 -0
  93. package/dist/social/ant-colony/types.js +24 -0
  94. package/dist/storage/trajectory.js +101 -0
  95. package/dist/test/ai-judgment-test.js +80 -0
  96. package/dist/test/bollharness-integration.test.js +318 -0
  97. package/dist/test/channel-agent-multi-dialogue.js +205 -0
  98. package/dist/test/channel-heartbeat-agent-test.js +201 -0
  99. package/dist/test/constraint-layer.test.js +164 -0
  100. package/dist/test/diap-identity-test.js +172 -0
  101. package/dist/test/diap-quick-test.js +62 -0
  102. package/dist/test/global-shared-context.test.js +315 -0
  103. package/dist/test/harness-judgment-injection.test.js +246 -0
  104. package/dist/test/harness-workflow-integrator-test.js +228 -0
  105. package/dist/test/human-value-store.test.js +243 -0
  106. package/dist/test/hybrid-integration-test.js +118 -0
  107. package/dist/test/hybrid-messenger-verify.js +55 -0
  108. package/dist/test/iroh-bistream-debug.js +38 -0
  109. package/dist/test/iroh-communication.test.js +66 -0
  110. package/dist/test/iroh-debug-test.js +57 -0
  111. package/dist/test/iroh-diap-test.js +71 -0
  112. package/dist/test/iroh-direct-connect.js +55 -0
  113. package/dist/test/iroh-e2e-fixed.js +89 -0
  114. package/dist/test/iroh-e2e-same-process.js +63 -0
  115. package/dist/test/iroh-e2e.js +66 -0
  116. package/dist/test/iroh-final-e2e.js +72 -0
  117. package/dist/test/iroh-relay-test.js +37 -0
  118. package/dist/test/iroh-simple-test.js +41 -0
  119. package/dist/test/iroh-transport-verify.js +54 -0
  120. package/dist/test/iroh-transport.test.js +37 -0
  121. package/dist/test/iroh-two-nodes.js +70 -0
  122. package/dist/test/iroh-verify.js +44 -0
  123. package/dist/test/judgment-decision.test.js +219 -0
  124. package/dist/test/llm-judgment-integration.test.js +220 -0
  125. package/dist/test/p2p-agent-complex-dialogue.js +385 -0
  126. package/dist/test/p2p-agent-dialogue.js +341 -0
  127. package/dist/test/p2p-agent-full-bidirectional.js +510 -0
  128. package/dist/test/p2p-agent-harness-flow.js +437 -0
  129. package/dist/test/p2p-agent-harness-single.js +143 -0
  130. package/dist/test/p2p-ai-dialogue-test.js +318 -0
  131. package/dist/test/p2p-cid-connect-test.js +195 -0
  132. package/dist/test/p2p-connect-receiver.js +69 -0
  133. package/dist/test/p2p-doc-transfer.js +110 -0
  134. package/dist/test/p2p-identity-page-test.js +77 -0
  135. package/dist/test/p2p-iroh-test.js +171 -0
  136. package/dist/test/p2p-minimal-test.js +241 -0
  137. package/dist/test/p2p-node-1.js +148 -0
  138. package/dist/test/p2p-node-2.js +148 -0
  139. package/dist/test/p2p-server.js +281 -0
  140. package/dist/test/p2p-two-nodes-test.js +438 -0
  141. package/dist/test/pi-sdk.test.js +44 -0
  142. package/dist/test/set-persona.js +40 -0
  143. package/dist/test/simple.test.js +9 -0
  144. package/dist/test/storage-integration.test.js +150 -0
  145. package/dist/test/subagent-manager.test.js +276 -0
  146. package/dist/test/test-gate-flow.test.js +81 -0
  147. package/dist/test/workflow-engine.test.js +87 -0
  148. package/dist/test/workflow-pivot-loop.test.js +246 -0
  149. package/dist/web/api-config.html +779 -779
  150. package/dist/web/client-hearth.js +10 -10
  151. package/dist/web/components/wallet-viem.mjs +118 -118
  152. package/dist/web/index.html +472 -472
  153. package/dist/web/manifest.json +20 -20
  154. package/dist/web/server-storage.js +29 -0
  155. package/dist/web/server.js +30 -14
  156. package/dist/web/style.css +4946 -4946
  157. package/package.json +195 -195
  158. package/scripts/build-cli.js +215 -215
  159. package/scripts/build-web.ts +130 -130
  160. package/scripts/postinstall.js +152 -152
  161. package/bin/bolloon-daemon.sh +0 -207
  162. package/dist/constraint-runtime/reference_data/archive_surface_snapshot.json +0 -63
  163. package/dist/constraint-runtime/reference_data/commands_snapshot.json +0 -1037
  164. package/dist/constraint-runtime/reference_data/subsystems/assistant.json +0 -8
  165. package/dist/constraint-runtime/reference_data/subsystems/bootstrap.json +0 -8
  166. package/dist/constraint-runtime/reference_data/subsystems/bridge.json +0 -32
  167. package/dist/constraint-runtime/reference_data/subsystems/buddy.json +0 -13
  168. package/dist/constraint-runtime/reference_data/subsystems/cli.json +0 -26
  169. package/dist/constraint-runtime/reference_data/subsystems/components.json +0 -32
  170. package/dist/constraint-runtime/reference_data/subsystems/constants.json +0 -28
  171. package/dist/constraint-runtime/reference_data/subsystems/coordinator.json +0 -8
  172. package/dist/constraint-runtime/reference_data/subsystems/entrypoints.json +0 -15
  173. package/dist/constraint-runtime/reference_data/subsystems/hooks.json +0 -32
  174. package/dist/constraint-runtime/reference_data/subsystems/keybindings.json +0 -21
  175. package/dist/constraint-runtime/reference_data/subsystems/memdir.json +0 -15
  176. package/dist/constraint-runtime/reference_data/subsystems/migrations.json +0 -18
  177. package/dist/constraint-runtime/reference_data/subsystems/moreright.json +0 -8
  178. package/dist/constraint-runtime/reference_data/subsystems/native_ts.json +0 -11
  179. package/dist/constraint-runtime/reference_data/subsystems/outputStyles.json +0 -8
  180. package/dist/constraint-runtime/reference_data/subsystems/plugins.json +0 -9
  181. package/dist/constraint-runtime/reference_data/subsystems/remote.json +0 -11
  182. package/dist/constraint-runtime/reference_data/subsystems/schemas.json +0 -8
  183. package/dist/constraint-runtime/reference_data/subsystems/screens.json +0 -10
  184. package/dist/constraint-runtime/reference_data/subsystems/server.json +0 -10
  185. package/dist/constraint-runtime/reference_data/subsystems/services.json +0 -32
  186. package/dist/constraint-runtime/reference_data/subsystems/skills.json +0 -27
  187. package/dist/constraint-runtime/reference_data/subsystems/state.json +0 -13
  188. package/dist/constraint-runtime/reference_data/subsystems/types.json +0 -18
  189. package/dist/constraint-runtime/reference_data/subsystems/upstreamproxy.json +0 -9
  190. package/dist/constraint-runtime/reference_data/subsystems/utils.json +0 -32
  191. package/dist/constraint-runtime/reference_data/subsystems/vim.json +0 -12
  192. package/dist/constraint-runtime/reference_data/subsystems/voice.json +0 -8
  193. package/dist/constraint-runtime/reference_data/tools_snapshot.json +0 -922
  194. package/dist/electron/config.js.map +0 -1
  195. package/dist/electron/dialogs.js.map +0 -1
  196. package/dist/electron/first-run.js.map +0 -1
  197. package/dist/electron/ipc.js.map +0 -1
  198. package/dist/electron/logger.js.map +0 -1
  199. package/dist/electron/main.js.map +0 -1
  200. package/dist/electron/menu.js.map +0 -1
  201. package/dist/electron/paths.js.map +0 -1
  202. package/dist/electron/server.js.map +0 -1
  203. package/dist/electron/tray.js.map +0 -1
  204. package/dist/electron/window.js.map +0 -1
  205. package/dist/utils/auto-update.js.map +0 -1
  206. package/dist/web/client.js.map +0 -7
package/dist/index.js CHANGED
@@ -16,7 +16,7 @@ import { getGlobalSharedContext } from './social/global-shared-context.js';
16
16
  import { createBollharnessIntegration } from './bollharness-integration/index.js';
17
17
  import * as readline from 'readline';
18
18
  import { printBanner, renderDialog, renderUserMessage, renderAgentMessage, renderMessageBox, renderToolCallListItem, termWidth } from './cli/loading-tui.js';
19
- import { startInk, stopInk, inkAppendLine as appendLine, inkSetStatus, inkSetThinking, inkSetTransient } from './cli/ink-app.js';
19
+ import { startInk, stopInk, inkAppendLine as appendLine, inkReplaceLastLine as replaceLastLine, inkSetStatus, inkSetThinking, inkSetTransient } from './cli/ink-app.js';
20
20
  // 启动自动检查更新:后台、节流、检测到新版本自动安装(可被 --no-update / BOLLOON_SKIP_UPDATE 关闭)
21
21
  import { createRequire } from 'module';
22
22
  const _require = createRequire(import.meta.url);
@@ -423,6 +423,9 @@ let cliStartTime = 0;
423
423
  let cliModelName = '…';
424
424
  let cliAgentName = '…';
425
425
  let cliActiveChannelId = null;
426
+ // 2026-08-12: 当前 active channel 的 agentId (如 agent-alice). memory 落盘按 agentId 存,
427
+ // /memory /resume /did 读路径必须用 agentId 而非 display name (cliAgentName), 否则路径不一致读不到.
428
+ let cliAgentId = null;
426
429
  // 2026-08-10: CLI 自动整理心跳 (与社交心跳并列, 独立于 server) — 退出时 stop
427
430
  let cliOrganizeHeartbeat = null;
428
431
  function fmtDuration(ms) {
@@ -435,6 +438,13 @@ function fmtDuration(ms) {
435
438
  const h = Math.floor(m / 60);
436
439
  return `${h}h ${m % 60}m`;
437
440
  }
441
+ /** 2026-08-12: 返回当前 agentId (memory 路径用). 优先 cliAgentId, fallback cliAgentName. */
442
+ function getCliAgentId() {
443
+ if (cliAgentId)
444
+ return cliAgentId;
445
+ // 无显式 agentId 时退到 cliAgentName (harness 默认 'agent', 其余用名字)
446
+ return cliAgentName === 'bolloon' ? 'agent' : (cliAgentName || 'agent');
447
+ }
438
448
  /** 2026-08-06: 从 ContextManager 读上下文用量 (CLI 状态栏数据源, 失败退化 0/1M) */
439
449
  // 2026-08-07: 不能用 require 加载 ESM 模块 (ERR_REQUIRE_ESM) → startCLI 里 await import 一次缓存引用,
440
450
  // 同步函数 getCliCtxUsage/getStatus 复用 — 之前裸 require 与 _require 都抛错被 catch → 状态栏恒 0/1M
@@ -563,6 +573,9 @@ async function startCLI(comm) {
563
573
  if (active) {
564
574
  cliAgentName = active.name;
565
575
  cliActiveChannelId = active.channelId ?? null;
576
+ // 2026-08-12: 同步 agentId (memory 路径一致) — 从 rawChannels 按 channelId 取 agentId
577
+ const raw = active.channelId ? store.rawChannels.find((c) => c.id === active.channelId) : undefined;
578
+ cliAgentId = raw?.agentId || null;
566
579
  }
567
580
  }
568
581
  catch {
@@ -692,23 +705,36 @@ async function processInput(input, comm) {
692
705
  const runEndOkSteps = [];
693
706
  // each iteration
694
707
  let lastToolEvent = null;
695
- // !command — 直接执行终端命令
708
+ // !command — 直接执行终端命令. 2026-08-12 (Task4): 支持多命令 (&& / ;) 逐段顺序执行 + 加载显示.
696
709
  if (trimmed.startsWith('!')) {
697
710
  const cmd = trimmed.slice(1).trim();
698
711
  if (!cmd) {
699
- appendLine(`${C_DIM}!<命令> 执行终端命令, 如 !ls -la${RESET}`);
712
+ appendLine(`${C_DIM}!<命令> 执行终端命令 (支持 && 串联多命令), 如 !ls -la${RESET}`);
700
713
  return;
701
714
  }
702
- appendLine(`${C_DIM}── $ ${cmd}${RESET}`);
715
+ const { execSync } = await import('child_process');
716
+ // 拆成多段: && 逻辑与 (前失败则停) / ; 无条件顺序. 保留每段顺序执行, 显示加载态.
717
+ const segments = cmd.split(/\s*;\s*/).filter(Boolean);
703
718
  try {
704
- const { execSync } = await import('child_process');
705
- const out = execSync(cmd, { timeout: 30000, encoding: 'utf-8', cwd: process.cwd() });
706
- appendLine(`${C_DIM}${out || '(无输出)'}${RESET}`);
719
+ for (const seg of segments) {
720
+ const segCmds = seg.split(/\s*&&\s*/).filter(Boolean);
721
+ for (const c of segCmds) {
722
+ appendLine(`${C_DIM}── $ ${c}${RESET}`);
723
+ try {
724
+ const out = execSync(c, { timeout: 30000, encoding: 'utf-8', cwd: process.cwd() });
725
+ appendLine(`${C_DIM}${out || '(无输出)'}${RESET}`);
726
+ }
727
+ catch (e) {
728
+ appendLine(`${C_ERROR}${e.stderr || e.message}${RESET}`);
729
+ // && 逻辑与: 某段失败则中止后续 && 段
730
+ break;
731
+ }
732
+ }
733
+ }
707
734
  }
708
- catch (e) {
709
- appendLine(`${C_ERROR}${e.stderr || e.message}${RESET}`);
735
+ finally {
736
+ appendLine(`${C_DIM}──${RESET}`);
710
737
  }
711
- appendLine(`${C_DIM}──${RESET}`);
712
738
  return;
713
739
  }
714
740
  // /channel — 切换当前智能体 (agent channel), 参数 name/id/number 自动解析
@@ -743,6 +769,7 @@ async function processInput(input, comm) {
743
769
  await store.setActive(r.channel.id);
744
770
  cliAgentName = r.identity.name;
745
771
  cliActiveChannelId = r.channel.id;
772
+ cliAgentId = r.channel.agentId || null; // 2026-08-12: memory 路径一致
746
773
  // 2026-08-09: 切 channel 必须重建 agent session — 否则身份/记忆停留在旧 channel (bug 修复)
747
774
  invalidateAgent();
748
775
  // 立即重建 (提前建好, 避免下次输入才卡顿; 失败不阻塞切换)
@@ -809,6 +836,7 @@ async function processInput(input, comm) {
809
836
  await store.setActive(id);
810
837
  cliAgentName = name.trim();
811
838
  cliActiveChannelId = id;
839
+ cliAgentId = agentId; // 2026-08-12: memory 路径一致
812
840
  // 2026-08-09: 新建 agent 后立即重建 session — 否则新 agent 身份不加载 (bug 修复)
813
841
  invalidateAgent();
814
842
  try {
@@ -1107,7 +1135,7 @@ async function processInput(input, comm) {
1107
1135
  const { getMemoryDir } = await import('./bootstrap/memory-compressor.js');
1108
1136
  const { readdir, readFile } = await import('fs/promises');
1109
1137
  const { join } = await import('path');
1110
- const dir = getMemoryDir(cliAgentName === 'bolloon' ? 'agent' : cliAgentName);
1138
+ const dir = getMemoryDir(getCliAgentId());
1111
1139
  const files = (await readdir(join(dir, 'sessions')).catch(() => [])).filter((f) => f.endsWith('.summary.md'));
1112
1140
  appendLine(`${C_ACCENT}记忆摘要 (${files.length} 个 session):${RESET}`);
1113
1141
  for (const f of files.slice(-5)) {
@@ -1126,10 +1154,10 @@ async function processInput(input, comm) {
1126
1154
  // /resume — 恢复: 最近记忆摘要 + 进行中计划
1127
1155
  if (cmd === '/resume' || cmd.startsWith('/resume ')) {
1128
1156
  try {
1129
- const { getMemoryDir, getSessionSummaryPath } = await import('./bootstrap/memory-compressor.js');
1157
+ const { getMemoryDir } = await import('./bootstrap/memory-compressor.js');
1130
1158
  const { readFile, readdir } = await import('fs/promises');
1131
1159
  const { join } = await import('path');
1132
- const dir = getMemoryDir(cliAgentName === 'bolloon' ? 'agent' : cliAgentName);
1160
+ const dir = getMemoryDir(getCliAgentId());
1133
1161
  const files = (await readdir(join(dir, 'sessions')).catch(() => [])).filter((f) => f.endsWith('.summary.md'));
1134
1162
  appendLine(`${C_ACCENT}↻ 恢复上下文:${RESET}`);
1135
1163
  if (files.length > 0) {
@@ -1286,6 +1314,50 @@ async function processInput(input, comm) {
1286
1314
  catch { /* 静默 */ }
1287
1315
  return;
1288
1316
  }
1317
+ // /skills [名] — 查看正式技能 (2026-08-12 Task5): 无参列全部, 带名看详情. 运行时开始前的技能 view.
1318
+ if (cmd === '/skills' || cmd.startsWith('/skills ')) {
1319
+ try {
1320
+ const { defaultSkillPaths, loadSkillsDir } = await import('./agents/skill-loader.js');
1321
+ const dirs = defaultSkillPaths();
1322
+ const metas = [];
1323
+ for (const d of dirs) {
1324
+ const m = await loadSkillsDir(d);
1325
+ for (const s of m)
1326
+ if (s.status === 'active' && !metas.some(x => x.name === s.name))
1327
+ metas.push(s);
1328
+ }
1329
+ const q = cmd.startsWith('/skills ') ? cmd.slice('/skills '.length).trim().toLowerCase() : '';
1330
+ if (!q) {
1331
+ appendLine(`${C_ACCENT}技能 (${metas.length}):${RESET}`);
1332
+ if (metas.length === 0)
1333
+ appendLine(` ${C_DIM}暂无正式技能 — run-end 经验可沉淀为 skill${RESET}`);
1334
+ for (const s of metas.slice(0, 20)) {
1335
+ const desc = (s.description || '').slice(0, 60);
1336
+ appendLine(` ${C_DIM}·${RESET} ${C_ACCENT}${s.name}${RESET}${desc ? ` ${C_DIM}${desc}${RESET}` : ''}`);
1337
+ }
1338
+ appendLine(`${C_DIM}用法: /skills <名> 查看详情${RESET}`);
1339
+ }
1340
+ else {
1341
+ const hit = metas.find(s => s.name.toLowerCase() === q || s.name.toLowerCase().includes(q));
1342
+ if (!hit) {
1343
+ appendLine(`${C_WARN}未找到技能: '${q}'${RESET}`);
1344
+ return;
1345
+ }
1346
+ appendLine(`${C_ACCENT}═ ${hit.name} ═${RESET}`);
1347
+ if (hit.description)
1348
+ appendLine(` ${C_DIM}描述:${RESET} ${hit.description}`);
1349
+ if (hit.triggers && hit.triggers.length > 0)
1350
+ appendLine(` ${C_DIM}触发:${RESET} ${hit.triggers.join(', ')}`);
1351
+ const body = (hit.body || '').trim().slice(0, 1200);
1352
+ if (body)
1353
+ appendLine(` ${C_DIM}---${RESET}\n${body}`);
1354
+ }
1355
+ }
1356
+ catch (e) {
1357
+ appendLine(`${C_ERROR}/skills 失败: ${String(e?.message || e).slice(0, 120)}${RESET}`);
1358
+ }
1359
+ return;
1360
+ }
1289
1361
  // /mcp — MCP 插件/工具列表
1290
1362
  if (cmd === '/mcp') {
1291
1363
  try {
@@ -1324,7 +1396,7 @@ async function processInput(input, comm) {
1324
1396
  if (cmd === '/did') {
1325
1397
  try {
1326
1398
  const { loadOrCreateAgentIdentity } = await import('./agents/agent-identity.js');
1327
- const identity = loadOrCreateAgentIdentity(cliAgentName === 'bolloon' ? 'default-agent' : cliAgentName);
1399
+ const identity = loadOrCreateAgentIdentity(getCliAgentId());
1328
1400
  appendLine(`${C_ACCENT}DID 身份:${RESET}`);
1329
1401
  appendLine(` ${C_DIM}did:${RESET} ${identity.did}`);
1330
1402
  appendLine(` ${C_DIM}publicKey:${RESET} ${identity.publicKey?.slice(0, 32) || '—'}...`);
@@ -1649,6 +1721,7 @@ async function processInput(input, comm) {
1649
1721
  appendLine(` ${C_ACCENT}/todo${RESET} 查看/勾选循环步骤 ${C_DIM}/todo <planId> <序号>${RESET}`);
1650
1722
  appendLine(` ${C_ACCENT}/tools${RESET} 可用工具列表 (名/参数/简介)`);
1651
1723
  appendLine(` ${C_ACCENT}/skill${RESET} 技能候选 ${C_DIM}skill-writer 沉淀候选${RESET}`);
1724
+ appendLine(` ${C_ACCENT}/skills${RESET} 查看正式技能 ${C_DIM}/skills <名> 看详情 (运行时开始前 view)${RESET}`);
1652
1725
  appendLine(` ${C_ACCENT}/mcp${RESET} MCP 服务器列表`);
1653
1726
  appendLine(` ${C_ACCENT}/agent${RESET} 当前智能体身份`);
1654
1727
  appendLine(` ${C_ACCENT}/did${RESET} DID 身份`);
@@ -1753,15 +1826,8 @@ async function processInput(input, comm) {
1753
1826
  // 真正思考内容在 status 的 Reflection/💡 事件 → 下方框渲染
1754
1827
  }
1755
1828
  else if (e.phase && !e.type) {
1756
- const ph = String(e.phase);
1757
- const detail = e.detail ? ` (${String(e.detail).slice(0, 60)})` : '';
1758
- const phLabel = {
1759
- intent_classified: '意图识别',
1760
- tool_selected: '工具选择',
1761
- reflection: '反思',
1762
- planning: '规划',
1763
- };
1764
- appendLine(`${C_WARN}◈ ${phLabel[ph] || ph}${detail}${RESET}`);
1829
+ // 2026-08-12 (Task4): phase (意图识别/工具选择/规划) 是模型内部规划过程,
1830
+ // 用户偏好"中间过程不显示" 静默丢弃, 不污染终端. (仅 Reflection 框保留, status 分支)
1765
1831
  }
1766
1832
  else if (e.type === 'status' && e.content) {
1767
1833
  const content = String(e.content);
@@ -1771,13 +1837,24 @@ async function processInput(input, comm) {
1771
1837
  if (body.trim())
1772
1838
  appendLine(renderMessageBox({ title: '💡 反思', body, color: C_WARN }));
1773
1839
  }
1774
- else if (!content.includes('🔄 循环') && !content.includes('📋 参数')) {
1840
+ else if (!content.includes('🔄 循环') && !content.includes('📋 参数')
1841
+ && !content.includes('🔍 任务复杂度') && !content.includes('⚙️ 动态配置')
1842
+ && !content.includes('⏹️ pivot loop')
1843
+ // 2026-08-12 (Task4): 循环过渡噪音 — "工具执行完成继续循环"/"继续总结" 是内部推进过程,
1844
+ // 不是给用户看的内容, 一律静默丢弃 (用户抱怨"每次显示触发下一轮循环"的真凶).
1845
+ && !content.includes('继续循环') && !content.includes('继续总结')) {
1775
1846
  appendLine(`${C_DIM}${content}${RESET}`);
1776
1847
  }
1777
1848
  }
1778
1849
  else if (e.type === 'step_start') {
1779
1850
  tuiToolCounter++;
1780
- tuiToolCalls.push({ tool: e.tool || '?', args: e.args, _t: Date.now() });
1851
+ const toolName = e.tool || '?';
1852
+ tuiToolCalls.push({ tool: toolName, args: e.args, _t: Date.now() });
1853
+ // 2026-08-12 (Task4): 命令/工具调用显示加载态 — 追加一行 "运行中", done 时原地替换.
1854
+ // system/loop 这类内部步骤不显示, 只显示真实工具/命令调用.
1855
+ if (toolName !== 'system' && toolName !== 'loop' && toolName !== '?') {
1856
+ appendLine(` ${C_DIM}🔧 ${toolName} 运行中...${RESET}`);
1857
+ }
1781
1858
  }
1782
1859
  else if (e.type === 'step_done' || e.type === 'step_error') {
1783
1860
  const p = tuiToolCalls.shift();
@@ -1795,7 +1872,14 @@ async function processInput(input, comm) {
1795
1872
  runEndOkSteps.push({ status: 'ok', name: t, output: e.output });
1796
1873
  }
1797
1874
  }
1798
- appendLine(renderToolCallListItem(doneItem, tuiToolCalls.length + 1, tuiToolCounter));
1875
+ // 2026-08-12 (Task4): done/error 原地替换 step_start 的加载行 (若 tool 非内部).
1876
+ const doneTool = e.tool ?? p?.tool;
1877
+ if (doneTool !== 'system' && doneTool !== 'loop' && doneTool !== '?') {
1878
+ replaceLastLine(renderToolCallListItem(doneItem, tuiToolCalls.length + 1, tuiToolCounter));
1879
+ }
1880
+ else {
1881
+ appendLine(renderToolCallListItem(doneItem, tuiToolCalls.length + 1, tuiToolCounter));
1882
+ }
1799
1883
  }
1800
1884
  }
1801
1885
  });
@@ -1981,10 +2065,10 @@ async function runToolCommand(tool, args, outputJson, comm, model, prompt) {
1981
2065
  const running = irohTransport.isRunning();
1982
2066
  const irohPeers = irohTransport.getPeers();
1983
2067
  const messenger = hybridMessenger ? 'HybridMessenger 就绪' : 'HybridMessenger 未初始化';
1984
- response = `iroh P2P 状态:
1985
- 运行中: ${running ? '是' : '否'}
1986
- Node ID: ${nodeId ? nodeId.substring(0, 32) + '...' : 'N/A'}
1987
- 已知节点: ${irohPeers.length}
2068
+ response = `iroh P2P 状态:
2069
+ 运行中: ${running ? '是' : '否'}
2070
+ Node ID: ${nodeId ? nodeId.substring(0, 32) + '...' : 'N/A'}
2071
+ 已知节点: ${irohPeers.length}
1988
2072
  ${messenger}`;
1989
2073
  break;
1990
2074
  }
@@ -3118,114 +3202,114 @@ function parseArgs() {
3118
3202
  return result;
3119
3203
  }
3120
3204
  function printHelp() {
3121
- console.log(`
3122
- 🤖 Bolloon Agent - AI 可调用文档处理智能体
3123
-
3124
- 用法:
3125
- npx tsx src/index.ts [选项] [参数]
3126
-
3127
- 选项:
3128
- # 文档处理
3129
- --read <file> 读取文档 (txt, md, pdf, docx)
3130
- --summarize <file> [ctx] 总结文档,可选上下文
3131
- --improve <file> <req> 改进文档,req 为改进要求
3132
-
3133
- # P2P 网络
3134
- --peers 列出已连接的对等节点
3135
- --broadcast <msg> 广播消息到所有节点
3136
- --send <peerId> <msg> 向指定节点发送消息
3137
-
3138
- # 智能体
3139
- --identity 显示当前智能体身份
3140
- --logs 显示操作日志
3141
- --search <keyword> 搜索文件
3142
- --tools 显示所有可用工具
3143
-
3144
- # SubAgent 管理
3145
- --agents 列出所有 SubAgent
3146
- --register-agent <name> [cap1] [cap2]... 注册新 SubAgent
3147
- --delegate <任务描述> [能力要求...] 委派任务给最佳 Agent
3148
-
3149
- # 全局共享上下文
3150
- --context 显示全局共享上下文摘要
3151
- --global-agents 显示全局 Agent 注册表
3152
- --add-action <内容> [重要性] 添加用户行动到共享上下文
3153
-
3154
- # Bollharness 治理框架
3155
- --harness-init 初始化 Bollharness 治理框架
3156
- --harness-gate 显示当前 Gate 状态
3157
- --harness-transition [PASS|BLOCK] 执行 Gate 转移
3158
- --harness-skill <name> [action] 执行 Harness Skill
3159
- --harness-classify <描述> 分类变更类型
3160
- --harness-context <file> 获取文件上下文
3161
- --harness-check <file> 执行 Guard 检查
3162
- --harness-archive 归档当前 Session 到 Harness
3163
- --harness-sessions 列出 Session 归档记录
3164
- --harness-session-context [id] 获取 Session 上下文
3165
-
3166
- # 自动更新
3167
- --update-check 检查 npm 包更新
3168
- --update-now [pkg] 更新到最新版本
3169
-
3170
- # 跨机聊天 (commits-as-messages, 共享 GitHub 仓库)
3171
- --chat-init 初始化 .comm/ 目录 (一次性)
3172
- --chat-send "消息正文" 把消息写到 .comm/<role>/, commit + push
3173
- --chat-pull 拉取远端 .comm/ 的新消息并显示
3174
- --chat-list 列出本地所有已同步消息
3175
- --chat-watch [--interval 15s] 后台定时拉取, 有新消息时输出
3176
- --chat-status 一屏查看: role / publicKey / remote / ahead-behind
3177
-
3178
- # 纯 P2P 私聊 (不走 GitHub, 不写 git, 不持久化)
3179
- --chat-p2p-send <peer|publicKey> "消息正文" 通过 P2P 直接发一条
3180
- --chat-p2p-listen 后台监听对方 P2P 私聊消息 (Ctrl-C 退出)
3181
-
3182
- # 跨机 agent 协作 (对方 bolloon --web 起着才能处理, 走 P2P 不经 GitHub)
3183
- --collab <peer|publicKey> "<任务描述>" 派任务给对端 LLM 干活, 等回结果 (90s 超时)
3184
-
3185
- # 外部编码智能体委派
3186
- --engine, -e <id> [--model <m>] <prompt> 委派任务给外部引擎,如 opencode/codex
3187
- --model <name> 指定委派时使用的模型
3188
-
3189
- # 输出控制
3190
- --json, -j 输出 JSON 格式
3191
- --output, -o <file> 结果保存到文件
3192
- --web 启动 Web UI 模式
3193
- --help, -h 显示帮助信息
3194
-
3195
- 示例:
3196
- # 文档处理
3197
- npx tsx src/index.ts --read 想法.md
3198
- npx tsx src/index.ts --summarize docs/想法.md
3199
- npx tsx src/index.ts --improve docs/README.md "让内容更简洁"
3200
- npx tsx src/index.ts --read 想法.md -o summary.txt
3201
-
3202
- # P2P 网络
3203
- npx tsx src/index.ts --peers
3204
- npx tsx src/index.ts --broadcast "Hello everyone"
3205
- npx tsx src/index.ts --send QmABC... "私信内容"
3206
-
3207
- # AI 对话
3208
- npx tsx src/index.ts --prompt "总结 README.md"
3209
- npx tsx src/index.ts -p "分析这个项目" -j
3210
-
3211
- # 交互模式
3212
- npx tsx src/index.ts
3213
-
3214
- # 外部引擎委派
3215
- npx tsx src/index.ts --engine opencode --model opencode/deepseek-v4-flash-free "说你好"
3216
-
3217
- # Web 模式
3218
- npx tsx src/index.ts --web
3219
-
3220
- 环境变量:
3221
- MINIMAX_API_KEY MiniMax API 密钥
3222
- DEEPSEEK_API_KEY DeepSeek API 密钥
3223
- KIMI_API_KEY / MOONSHOT_API_KEY Kimi/Moonshot API 密钥
3224
- GLM_API_KEY / ZHIPU_API_KEY 智谱 GLM API 密钥
3225
- QWEN_API_KEY / DASHSCOPE_API_KEY 通义千问 API 密钥
3226
- OPENAI_API_KEY OpenAI API 密钥(Pi SDK)
3227
- ANTHROPIC_API_KEY Anthropic API 密钥(Pi SDK)
3228
- PORT Web 服务端口(默认 54188)
3205
+ console.log(`
3206
+ 🤖 Bolloon Agent - AI 可调用文档处理智能体
3207
+
3208
+ 用法:
3209
+ npx tsx src/index.ts [选项] [参数]
3210
+
3211
+ 选项:
3212
+ # 文档处理
3213
+ --read <file> 读取文档 (txt, md, pdf, docx)
3214
+ --summarize <file> [ctx] 总结文档,可选上下文
3215
+ --improve <file> <req> 改进文档,req 为改进要求
3216
+
3217
+ # P2P 网络
3218
+ --peers 列出已连接的对等节点
3219
+ --broadcast <msg> 广播消息到所有节点
3220
+ --send <peerId> <msg> 向指定节点发送消息
3221
+
3222
+ # 智能体
3223
+ --identity 显示当前智能体身份
3224
+ --logs 显示操作日志
3225
+ --search <keyword> 搜索文件
3226
+ --tools 显示所有可用工具
3227
+
3228
+ # SubAgent 管理
3229
+ --agents 列出所有 SubAgent
3230
+ --register-agent <name> [cap1] [cap2]... 注册新 SubAgent
3231
+ --delegate <任务描述> [能力要求...] 委派任务给最佳 Agent
3232
+
3233
+ # 全局共享上下文
3234
+ --context 显示全局共享上下文摘要
3235
+ --global-agents 显示全局 Agent 注册表
3236
+ --add-action <内容> [重要性] 添加用户行动到共享上下文
3237
+
3238
+ # Bollharness 治理框架
3239
+ --harness-init 初始化 Bollharness 治理框架
3240
+ --harness-gate 显示当前 Gate 状态
3241
+ --harness-transition [PASS|BLOCK] 执行 Gate 转移
3242
+ --harness-skill <name> [action] 执行 Harness Skill
3243
+ --harness-classify <描述> 分类变更类型
3244
+ --harness-context <file> 获取文件上下文
3245
+ --harness-check <file> 执行 Guard 检查
3246
+ --harness-archive 归档当前 Session 到 Harness
3247
+ --harness-sessions 列出 Session 归档记录
3248
+ --harness-session-context [id] 获取 Session 上下文
3249
+
3250
+ # 自动更新
3251
+ --update-check 检查 npm 包更新
3252
+ --update-now [pkg] 更新到最新版本
3253
+
3254
+ # 跨机聊天 (commits-as-messages, 共享 GitHub 仓库)
3255
+ --chat-init 初始化 .comm/ 目录 (一次性)
3256
+ --chat-send "消息正文" 把消息写到 .comm/<role>/, commit + push
3257
+ --chat-pull 拉取远端 .comm/ 的新消息并显示
3258
+ --chat-list 列出本地所有已同步消息
3259
+ --chat-watch [--interval 15s] 后台定时拉取, 有新消息时输出
3260
+ --chat-status 一屏查看: role / publicKey / remote / ahead-behind
3261
+
3262
+ # 纯 P2P 私聊 (不走 GitHub, 不写 git, 不持久化)
3263
+ --chat-p2p-send <peer|publicKey> "消息正文" 通过 P2P 直接发一条
3264
+ --chat-p2p-listen 后台监听对方 P2P 私聊消息 (Ctrl-C 退出)
3265
+
3266
+ # 跨机 agent 协作 (对方 bolloon --web 起着才能处理, 走 P2P 不经 GitHub)
3267
+ --collab <peer|publicKey> "<任务描述>" 派任务给对端 LLM 干活, 等回结果 (90s 超时)
3268
+
3269
+ # 外部编码智能体委派
3270
+ --engine, -e <id> [--model <m>] <prompt> 委派任务给外部引擎,如 opencode/codex
3271
+ --model <name> 指定委派时使用的模型
3272
+
3273
+ # 输出控制
3274
+ --json, -j 输出 JSON 格式
3275
+ --output, -o <file> 结果保存到文件
3276
+ --web 启动 Web UI 模式
3277
+ --help, -h 显示帮助信息
3278
+
3279
+ 示例:
3280
+ # 文档处理
3281
+ npx tsx src/index.ts --read 想法.md
3282
+ npx tsx src/index.ts --summarize docs/想法.md
3283
+ npx tsx src/index.ts --improve docs/README.md "让内容更简洁"
3284
+ npx tsx src/index.ts --read 想法.md -o summary.txt
3285
+
3286
+ # P2P 网络
3287
+ npx tsx src/index.ts --peers
3288
+ npx tsx src/index.ts --broadcast "Hello everyone"
3289
+ npx tsx src/index.ts --send QmABC... "私信内容"
3290
+
3291
+ # AI 对话
3292
+ npx tsx src/index.ts --prompt "总结 README.md"
3293
+ npx tsx src/index.ts -p "分析这个项目" -j
3294
+
3295
+ # 交互模式
3296
+ npx tsx src/index.ts
3297
+
3298
+ # 外部引擎委派
3299
+ npx tsx src/index.ts --engine opencode --model opencode/deepseek-v4-flash-free "说你好"
3300
+
3301
+ # Web 模式
3302
+ npx tsx src/index.ts --web
3303
+
3304
+ 环境变量:
3305
+ MINIMAX_API_KEY MiniMax API 密钥
3306
+ DEEPSEEK_API_KEY DeepSeek API 密钥
3307
+ KIMI_API_KEY / MOONSHOT_API_KEY Kimi/Moonshot API 密钥
3308
+ GLM_API_KEY / ZHIPU_API_KEY 智谱 GLM API 密钥
3309
+ QWEN_API_KEY / DASHSCOPE_API_KEY 通义千问 API 密钥
3310
+ OPENAI_API_KEY OpenAI API 密钥(Pi SDK)
3311
+ ANTHROPIC_API_KEY Anthropic API 密钥(Pi SDK)
3312
+ PORT Web 服务端口(默认 54188)
3229
3313
  `);
3230
3314
  }
3231
3315
  // ---------------------------------------------------------------------------