@bolloon/bolloon-agent 0.1.35 → 0.1.36

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (194) hide show
  1. package/.playwright-mcp/page-2026-06-16T07-51-45-706Z.yml +130 -0
  2. package/.playwright-mcp/page-2026-06-16T07-56-44-116Z.yml +131 -0
  3. package/Bolloon.md +45 -4
  4. package/Dive-into/CITATION.cff +17 -0
  5. package/Dive-into/LICENSE +25 -0
  6. package/Dive-into/README.md +598 -0
  7. package/Dive-into/README_zh.md +599 -0
  8. package/Dive-into/assets/context.png +0 -0
  9. package/Dive-into/assets/extensibility.png +0 -0
  10. package/Dive-into/assets/iteration.png +0 -0
  11. package/Dive-into/assets/layered_architecture.png +0 -0
  12. package/Dive-into/assets/main_structure.png +0 -0
  13. package/Dive-into/assets/permission.png +0 -0
  14. package/Dive-into/assets/session_compact.png +0 -0
  15. package/Dive-into/assets/subagent.png +0 -0
  16. package/Dive-into/paper/Dive_into_Claude_Code.pdf +0 -0
  17. package/README.md +1 -1
  18. package/dist/agents/p2p-chat-tools.js +6 -6
  19. package/dist/agents/permission-mode.js +115 -0
  20. package/dist/agents/pi-sdk.js +435 -25
  21. package/dist/agents/pre-tool-validator.js +194 -0
  22. package/dist/agents/workflow-pivot-loop.js +113 -12
  23. package/dist/bollharness/src/scripts/checks/check_doc_freshness.js +1 -1
  24. package/dist/bollharness/src/scripts/checks/check_doc_links.js +1 -1
  25. package/dist/bollharness/src/scripts/context_router.js +1 -1
  26. package/dist/bollharness/src/scripts/deploy-guard.js +1 -1
  27. package/dist/bollharness/src/scripts/guard_router.js +1 -1
  28. package/dist/bollharness/src/scripts/hooks/_hook_output.js +1 -1
  29. package/dist/bollharness/src/scripts/hooks/risk-tracker.js +1 -1
  30. package/dist/bollharness-integration/context-router.js +2 -2
  31. package/dist/bollharness-integration/guard-checker.js +1 -1
  32. package/dist/bootstrap/bootstrap.js +3 -0
  33. package/dist/bootstrap/context-collector.js +17 -1
  34. package/dist/bootstrap/context-hierarchy.js +218 -0
  35. package/dist/bootstrap/lifecycle-hooks.js +86 -24
  36. package/dist/bootstrap/project-context.js +10 -3
  37. package/dist/context-compaction/auto-compact.js +144 -0
  38. package/dist/context-compaction/budget-gate.js +28 -0
  39. package/dist/context-compaction/budget-reduce.js +35 -0
  40. package/dist/context-compaction/context-collapse.js +66 -0
  41. package/dist/context-compaction/index.js +21 -0
  42. package/dist/context-compaction/microcompact.js +51 -0
  43. package/dist/context-compaction/pipeline.js +123 -0
  44. package/dist/context-compaction/snip.js +45 -0
  45. package/dist/context-compaction/token-estimator.js +35 -0
  46. package/dist/context-compaction/types.js +19 -0
  47. package/dist/heartbeat/HealthMonitor.js +3 -2
  48. package/dist/index.js +38 -2
  49. package/dist/llm/llm-judgment-client.js +32 -30
  50. package/dist/llm/pi-ai.js +103 -16
  51. package/dist/llm/system-prompt/health.js +129 -0
  52. package/dist/llm/system-prompt/registry.js +246 -0
  53. package/dist/llm/system-prompt/strip-hibsml.js +51 -0
  54. package/dist/llm/tool-manifest/ask_user_input.js +35 -0
  55. package/dist/llm/tool-manifest/bash.js +23 -0
  56. package/dist/llm/tool-manifest/create_file.js +24 -0
  57. package/dist/llm/tool-manifest/fetch_sports_data.js +26 -0
  58. package/dist/llm/tool-manifest/image_search.js +24 -0
  59. package/dist/llm/tool-manifest/index.js +69 -0
  60. package/dist/llm/tool-manifest/mcp.js +43 -0
  61. package/dist/llm/tool-manifest/message_compose.js +31 -0
  62. package/dist/llm/tool-manifest/places.js +83 -0
  63. package/dist/llm/tool-manifest/present_files.js +21 -0
  64. package/dist/llm/tool-manifest/recipe.js +40 -0
  65. package/dist/llm/tool-manifest/recommend_apps.js +23 -0
  66. package/dist/llm/tool-manifest/str_replace.js +27 -0
  67. package/dist/llm/tool-manifest/types.js +7 -0
  68. package/dist/llm/tool-manifest/view.js +24 -0
  69. package/dist/llm/tool-manifest/weather.js +27 -0
  70. package/dist/llm/tool-manifest/web.js +51 -0
  71. package/dist/network/p2p-direct.js +23 -0
  72. package/dist/network/source-intent-broadcaster.js +203 -0
  73. package/dist/network/source-intent.js +100 -0
  74. package/dist/pi-ecosystem-judgment/adaptive-scan.js +48 -0
  75. package/dist/pi-ecosystem-judgment/injection-gate.js +54 -12
  76. package/dist/pi-ecosystem-judgment/value-injection.js +8 -2
  77. package/dist/security/context-router-tool.js +1 -1
  78. package/dist/security/input-scanner.js +223 -0
  79. package/dist/web/client.js +3677 -4161
  80. package/dist/web/components/p2p/P2PModal.js +188 -0
  81. package/dist/web/components/p2p/index.js +264 -226
  82. package/dist/web/components/p2p/p2p-modal.js +657 -0
  83. package/dist/web/components/p2p/p2p-tools.js +248 -0
  84. package/dist/web/index.html +58 -67
  85. package/dist/web/server.js +299 -117
  86. package/dist/web/style.css +531 -249
  87. package/dist/web/ui/message-renderer.js +463 -0
  88. package/dist/web/ui/step-timeline.js +375 -0
  89. package/lefthook.yml +4 -0
  90. package/package.json +1 -1
  91. package/scripts/auto-evolve-loop.ts +105 -0
  92. package/scripts/build-web.ts +35 -1
  93. package/scripts/validate-system-prompt.ts +142 -0
  94. package/src/agents/p2p-chat-tools.ts +6 -6
  95. package/src/agents/permission-mode.ts +127 -0
  96. package/src/agents/pi-sdk.ts +461 -28
  97. package/src/agents/pre-tool-validator.ts +213 -0
  98. package/src/agents/workflow-pivot-loop.ts +110 -19
  99. package/src/bollharness/CLAUDE.md +1 -1
  100. package/src/bollharness/README.md +2 -2
  101. package/src/bollharness/README.zh-CN.md +2 -2
  102. package/src/bollharness/reference/boll-reference/scripts/hooks/find-boll-root.sh +2 -2
  103. package/src/bollharness/scripts/context-fragments/truth-source-hierarchy.md +2 -2
  104. package/src/bollharness/scripts/context-fragments/version-sources.md +1 -1
  105. package/src/bollharness/scripts/hooks/find-project-root.sh +4 -4
  106. package/src/bollharness/src/scripts/checks/check_doc_freshness.ts +1 -1
  107. package/src/bollharness/src/scripts/checks/check_doc_links.ts +1 -1
  108. package/src/bollharness/src/scripts/context_router.ts +1 -1
  109. package/src/bollharness/src/scripts/deploy-guard.ts +1 -1
  110. package/src/bollharness/src/scripts/guard_router.ts +1 -1
  111. package/src/bollharness/src/scripts/hooks/_hook_output.ts +1 -1
  112. package/src/bollharness/src/scripts/hooks/risk-tracker.ts +1 -1
  113. package/src/bollharness/templates/scaffold/.gitignore.append +1 -1
  114. package/src/bollharness/templates/scaffold/CLAUDE.md +2 -2
  115. package/src/bollharness-integration/context-router.ts +2 -2
  116. package/src/bollharness-integration/guard-checker.ts +1 -1
  117. package/src/bootstrap/bootstrap.ts +3 -0
  118. package/src/bootstrap/context-collector.ts +30 -1
  119. package/src/bootstrap/context-hierarchy.ts +283 -0
  120. package/src/bootstrap/lifecycle-hooks.ts +139 -26
  121. package/src/bootstrap/project-context.ts +11 -3
  122. package/src/context-compaction/auto-compact.ts +153 -0
  123. package/src/context-compaction/budget-gate.ts +32 -0
  124. package/src/context-compaction/budget-reduce.ts +37 -0
  125. package/src/context-compaction/context-collapse.ts +72 -0
  126. package/src/context-compaction/index.ts +24 -0
  127. package/src/context-compaction/microcompact.ts +54 -0
  128. package/src/context-compaction/pipeline.ts +133 -0
  129. package/src/context-compaction/snip.ts +51 -0
  130. package/src/context-compaction/token-estimator.ts +36 -0
  131. package/src/context-compaction/types.ts +99 -0
  132. package/src/heartbeat/HealthMonitor.ts +3 -2
  133. package/src/index.ts +36 -2
  134. package/src/llm/llm-judgment-client.ts +36 -35
  135. package/src/llm/pi-ai.ts +111 -16
  136. package/src/llm/system-prompt/health.ts +159 -0
  137. package/src/llm/system-prompt/layers/channel/local.md +14 -0
  138. package/src/llm/system-prompt/layers/channel/p2p-agent.md +18 -0
  139. package/src/llm/system-prompt/layers/channel/p2p-visitor.md +19 -0
  140. package/src/llm/system-prompt/layers/core/artifacts_storage.md +89 -0
  141. package/src/llm/system-prompt/layers/core/evenhandedness.md +21 -0
  142. package/src/llm/system-prompt/layers/core/hibs_reminders.md +15 -0
  143. package/src/llm/system-prompt/layers/core/identity.md +37 -0
  144. package/src/llm/system-prompt/layers/core/knowledge.md +17 -0
  145. package/src/llm/system-prompt/layers/core/memory_system.md +12 -0
  146. package/src/llm/system-prompt/layers/core/network_filesystem.md +28 -0
  147. package/src/llm/system-prompt/layers/core/refusal.md +37 -0
  148. package/src/llm/system-prompt/layers/core/tone.md +31 -0
  149. package/src/llm/system-prompt/layers/core/tools.thin.md +13 -0
  150. package/src/llm/system-prompt/layers/core/wellbeing.md +41 -0
  151. package/src/llm/system-prompt/layers/role/architect.md +20 -0
  152. package/src/llm/system-prompt/layers/role/expert.md +19 -0
  153. package/src/llm/system-prompt/layers/role/implementer.md +15 -0
  154. package/src/llm/system-prompt/layers/role/security.md +15 -0
  155. package/src/llm/system-prompt/layers/tool/artifacts.md +72 -0
  156. package/src/llm/system-prompt/layers/tool/bash.md +25 -0
  157. package/src/llm/system-prompt/layers/tool/hibs_api.md +171 -0
  158. package/src/llm/system-prompt/layers/tool/image_search.md +70 -0
  159. package/src/llm/system-prompt/layers/tool/manifest.md +89 -0
  160. package/src/llm/system-prompt/layers/tool/mcp_apps.md +53 -0
  161. package/src/llm/system-prompt/layers/tool/web_search.md +83 -0
  162. package/src/llm/system-prompt/registry.ts +325 -0
  163. package/src/llm/system-prompt/strip-hibsml.ts +52 -0
  164. package/src/llm/tool-manifest/ask_user_input.ts +37 -0
  165. package/src/llm/tool-manifest/bash.ts +25 -0
  166. package/src/llm/tool-manifest/create_file.ts +26 -0
  167. package/src/llm/tool-manifest/fetch_sports_data.ts +28 -0
  168. package/src/llm/tool-manifest/image_search.ts +26 -0
  169. package/src/llm/tool-manifest/index.ts +88 -0
  170. package/src/llm/tool-manifest/mcp.ts +46 -0
  171. package/src/llm/tool-manifest/message_compose.ts +33 -0
  172. package/src/llm/tool-manifest/places.ts +86 -0
  173. package/src/llm/tool-manifest/present_files.ts +23 -0
  174. package/src/llm/tool-manifest/recipe.ts +42 -0
  175. package/src/llm/tool-manifest/recommend_apps.ts +25 -0
  176. package/src/llm/tool-manifest/str_replace.ts +29 -0
  177. package/src/llm/tool-manifest/types.ts +52 -0
  178. package/src/llm/tool-manifest/view.ts +26 -0
  179. package/src/llm/tool-manifest/weather.ts +29 -0
  180. package/src/llm/tool-manifest/web.ts +54 -0
  181. package/src/network/p2p-direct.ts +22 -0
  182. package/src/network/source-intent-broadcaster.ts +242 -0
  183. package/src/network/source-intent.ts +167 -0
  184. package/src/security/context-router-tool.ts +1 -1
  185. package/src/security/input-scanner.ts +287 -0
  186. package/src/web/client.js +271 -2817
  187. package/src/web/client.ts +4326 -0
  188. package/src/web/index.html +58 -67
  189. package/src/web/server.ts +301 -141
  190. package/src/web/style.css +531 -249
  191. package/src/web/ui/message-renderer.ts +540 -0
  192. package/src/web/ui/step-timeline.ts +394 -0
  193. package/test-results/.last-run.json +6 -0
  194. 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
package/src/web/style.css CHANGED
@@ -39,6 +39,13 @@
39
39
  --warning-bg: rgba(245, 158, 11, 0.1);
40
40
  --info: #2196f3;
41
41
  --info-bg: rgba(33, 150, 243, 0.1);
42
+
43
+ /* 二级 / 三级面 (次级背景, 嵌套层) — 补全未定义变量, 此前引用处 fallback 到 unset */
44
+ --bg-secondary: #252522;
45
+ --bg-tertiary: #2f2f2a;
46
+ --text-primary: #e8e8e0;
47
+ --font-mono: 'SF Mono', 'Monaco', 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace;
48
+ --accent-light: #e8f060;
42
49
  }
43
50
 
44
51
  [data-theme="light"] {
@@ -58,6 +65,13 @@
58
65
  --ai-text: #2a2a20;
59
66
  --border: #d0d0c0;
60
67
  --border-light: #c0c0b0;
68
+
69
+ /* 二级 / 三级面 — 补全未定义变量 */
70
+ --bg-secondary: #f5f5ed;
71
+ --bg-tertiary: #fafaf2;
72
+ --text-primary: #1a1a18;
73
+ --font-mono: 'SF Mono', 'Monaco', 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace;
74
+ --accent-light: #c4d240;
61
75
  }
62
76
 
63
77
  body {
@@ -472,6 +486,63 @@ body {
472
486
  font-weight: 500;
473
487
  }
474
488
 
489
+ /* 2026-06-16: P2P 远端 header 紧凑变体 + mini 按钮 (替代 HTML L66-74 内联) */
490
+ .section-header.is-compact {
491
+ margin-bottom: 8px;
492
+ padding-bottom: 0;
493
+ position: static;
494
+ }
495
+ .section-header.is-compact::after {
496
+ display: none;
497
+ }
498
+ .section-header.is-clickable {
499
+ cursor: pointer;
500
+ user-select: none;
501
+ transition: background 0.15s;
502
+ }
503
+ .section-header.is-clickable:hover {
504
+ background: var(--bg-hover);
505
+ }
506
+ .section-header-row {
507
+ display: flex;
508
+ align-items: center;
509
+ gap: 6px;
510
+ }
511
+ .section-header-row .section-title {
512
+ font-size: 11px;
513
+ font-weight: 600;
514
+ text-transform: uppercase;
515
+ letter-spacing: 0.5px;
516
+ color: var(--text-muted);
517
+ }
518
+ .section-header-actions {
519
+ display: flex;
520
+ gap: 4px;
521
+ }
522
+ .sidebar-mini-btn {
523
+ background: transparent;
524
+ border: 1px solid var(--border);
525
+ color: var(--text-secondary);
526
+ cursor: pointer;
527
+ padding: 2px 6px;
528
+ border-radius: 4px;
529
+ font-size: 11px;
530
+ line-height: 1;
531
+ transition: var(--transition);
532
+ }
533
+ .sidebar-mini-btn:hover {
534
+ background: var(--bg-hover);
535
+ color: var(--text-primary);
536
+ border-color: var(--border-light);
537
+ }
538
+ .sidebar-empty-hint {
539
+ color: var(--text-muted);
540
+ font-size: 11px;
541
+ padding: 8px 4px;
542
+ text-align: center;
543
+ list-style: none;
544
+ }
545
+
475
546
  .channel-icon {
476
547
  width: 28px;
477
548
  height: 28px;
@@ -938,8 +1009,12 @@ body {
938
1009
  .bubble {
939
1010
  padding: 14px 18px;
940
1011
  border-radius: var(--radius);
941
- line-height: 1.6;
942
- white-space: pre-wrap;
1012
+ line-height: 1.7;
1013
+ /* 2026-06-16: pre-wrap 改为 pre-line — 保留换行, 但折叠 token 间的多余空格.
1014
+ pre-wrap 模式下 marked 输出里 "\n\n" 之外的 token 边界空格被原样保留,
1015
+ 视觉上字符间隔过大. pre-line 保持段落结构 (换行生效), 不再放大空格.
1016
+ 重要: .bubble pre 子元素走 pre-wrap (见 .bubble pre), 代码块缩进不受影响. */
1017
+ white-space: pre-line;
943
1018
  word-break: break-word;
944
1019
  font-size: 15px;
945
1020
  }
@@ -958,6 +1033,21 @@ body {
958
1033
  border-bottom-left-radius: 4px;
959
1034
  }
960
1035
 
1036
+ /* System / Error 变体 — 2026-06-16 补全, 之前 system/error 走 addMessage 缺样式
1037
+ - system: 信息提示感, 左色条
1038
+ - error: 错误提示, 红边 */
1039
+ .bubble-system {
1040
+ background: var(--bg-secondary);
1041
+ border-left: 3px solid var(--accent-dark);
1042
+ color: var(--text);
1043
+ }
1044
+ .bubble-error {
1045
+ background: #3a2a2a;
1046
+ border: 1px solid var(--error);
1047
+ border-left: 3px solid var(--error);
1048
+ color: #f0d0d0;
1049
+ }
1050
+
961
1051
  .message-header {
962
1052
  font-family: 'JetBrains Mono', monospace;
963
1053
  font-size: 12px;
@@ -1139,10 +1229,6 @@ body {
1139
1229
  }
1140
1230
 
1141
1231
  /* Markdown Styles */
1142
- .bubble {
1143
- line-height: 1.7;
1144
- }
1145
-
1146
1232
  .bubble h1, .bubble h2, .bubble h3, .bubble h4, .bubble h5, .bubble h6 {
1147
1233
  margin-top: 16px;
1148
1234
  margin-bottom: 8px;
@@ -1225,96 +1311,6 @@ body {
1225
1311
  max-width: 100%;
1226
1312
  border-radius: var(--radius-sm);
1227
1313
  }
1228
- .workflow-display {
1229
- background: var(--bg-secondary);
1230
- border: 1px solid var(--accent);
1231
- border-radius: var(--radius);
1232
- padding: 12px 16px;
1233
- margin: 8px 0;
1234
- animation: fadeIn 0.3s ease;
1235
- }
1236
-
1237
- .workflow-header {
1238
- display: flex;
1239
- align-items: center;
1240
- gap: 10px;
1241
- margin-bottom: 12px;
1242
- padding-bottom: 8px;
1243
- border-bottom: 1px solid var(--border);
1244
- }
1245
-
1246
- .workflow-icon {
1247
- font-size: 18px;
1248
- animation: pulse 1.5s infinite;
1249
- }
1250
-
1251
- .workflow-title {
1252
- font-size: 14px;
1253
- font-weight: 500;
1254
- color: var(--text-primary);
1255
- }
1256
-
1257
- .workflow-loop-count {
1258
- font-size: 12px;
1259
- color: var(--accent);
1260
- background: var(--bg-tertiary);
1261
- padding: 2px 8px;
1262
- border-radius: 10px;
1263
- display: none;
1264
- }
1265
-
1266
- .workflow-steps-list {
1267
- margin-bottom: 10px;
1268
- }
1269
-
1270
- .workflow-step-item {
1271
- display: flex;
1272
- align-items: center;
1273
- gap: 8px;
1274
- font-size: 13px;
1275
- color: var(--text-secondary);
1276
- padding: 4px 0;
1277
- }
1278
-
1279
- .step-running {
1280
- animation: spin 1s linear infinite;
1281
- color: var(--accent);
1282
- }
1283
-
1284
- .workflow-streams {
1285
- max-height: 200px;
1286
- overflow-y: auto;
1287
- }
1288
-
1289
- .workflow-step-stream {
1290
- background: var(--bg);
1291
- border: 1px solid var(--border);
1292
- border-radius: var(--radius-sm);
1293
- padding: 8px 12px;
1294
- margin-bottom: 8px;
1295
- }
1296
-
1297
- .workflow-step-stream .step-label {
1298
- font-size: 12px;
1299
- color: var(--accent);
1300
- margin-bottom: 4px;
1301
- }
1302
-
1303
- .workflow-step-stream .step-content {
1304
- font-size: 13px;
1305
- color: var(--text-secondary);
1306
- white-space: pre-wrap;
1307
- }
1308
-
1309
- .workflow-loop-item {
1310
- background: linear-gradient(135deg, var(--bg) 0%, var(--bg-tertiary) 100%);
1311
- border: 1px solid var(--accent);
1312
- border-radius: var(--radius-sm);
1313
- padding: 10px 14px;
1314
- margin-bottom: 8px;
1315
- animation: slideIn 0.3s ease;
1316
- }
1317
-
1318
1314
  /* User Command Display - inside message div */
1319
1315
  .message-user .user-command-display {
1320
1316
  background: linear-gradient(135deg, var(--bg) 0%, var(--bg-tertiary) 100%);
@@ -1351,120 +1347,11 @@ body {
1351
1347
  margin: 0;
1352
1348
  }
1353
1349
 
1354
- @keyframes blink {
1355
- 0%, 100% { opacity: 1; }
1356
- 50% { opacity: 0.3; }
1357
- }
1358
-
1359
- /* Tool Results Container */
1360
- .tool-results-container {
1361
- margin: 8px 0;
1362
- }
1363
-
1364
- .tool-result-item {
1365
- background: var(--bg-secondary);
1366
- border: 1px solid var(--border);
1367
- border-radius: var(--radius-sm);
1368
- margin-bottom: 6px;
1369
- overflow: hidden;
1370
- }
1371
-
1372
- .tool-result-item.collapsed .tool-result-content {
1373
- display: none;
1374
- }
1375
-
1376
- .tool-result-item.expanded {
1377
- border-color: var(--accent);
1378
- }
1379
-
1380
- .tool-result-header {
1381
- display: flex;
1382
- align-items: center;
1383
- gap: 8px;
1384
- padding: 8px 12px;
1385
- cursor: pointer;
1386
- background: var(--bg-tertiary);
1387
- transition: background 0.2s;
1388
- }
1389
-
1390
- .tool-result-header:hover {
1391
- background: var(--bg);
1392
- }
1393
-
1394
- .tool-result-icon {
1395
- font-size: 14px;
1396
- }
1397
-
1398
- .tool-result-name {
1399
- font-size: 12px;
1400
- color: var(--text-secondary);
1401
- flex: 1;
1402
- }
1403
-
1404
- .tool-result-toggle {
1405
- font-size: 10px;
1406
- color: var(--text-muted);
1407
- transition: transform 0.2s;
1408
- }
1409
-
1410
- .tool-result-item.expanded .tool-result-toggle {
1411
- transform: rotate(90deg);
1412
- }
1413
-
1414
- .tool-result-content {
1415
- padding: 10px 12px;
1416
- background: var(--bg);
1417
- }
1418
-
1419
- .tool-result-content pre {
1420
- font-family: 'JetBrains Mono', monospace;
1421
- font-size: 11px;
1422
- color: var(--text-secondary);
1423
- margin: 0;
1424
- white-space: pre-wrap;
1425
- word-break: break-all;
1426
- }
1427
-
1428
- .loop-header {
1429
- display: flex;
1430
- align-items: center;
1431
- gap: 10px;
1432
- margin-bottom: 6px;
1433
- }
1434
-
1435
- .loop-icon {
1436
- font-size: 16px;
1437
- }
1438
-
1439
- .loop-status {
1440
- font-size: 11px;
1441
- color: var(--accent);
1442
- background: var(--bg-tertiary);
1443
- padding: 2px 6px;
1444
- border-radius: 4px;
1445
- }
1446
-
1447
- .loop-content {
1448
- font-size: 13px;
1449
- color: var(--text-secondary);
1450
- white-space: pre-wrap;
1451
- }
1452
-
1453
- @keyframes pulse {
1454
- 0%, 100% { opacity: 1; transform: scale(1); }
1455
- 50% { opacity: 0.7; transform: scale(1.1); }
1456
- }
1457
-
1458
1350
  @keyframes slideIn {
1459
1351
  from { opacity: 0; transform: translateY(-10px); }
1460
1352
  to { opacity: 1; transform: translateY(0); }
1461
1353
  }
1462
1354
 
1463
- @keyframes fadeIn {
1464
- from { opacity: 0; }
1465
- to { opacity: 1; }
1466
- }
1467
-
1468
1355
  /* Typing Indicator */
1469
1356
  .typing {
1470
1357
  display: flex;
@@ -1488,10 +1375,6 @@ body {
1488
1375
  font-size: 14px;
1489
1376
  }
1490
1377
 
1491
- @keyframes spin {
1492
- to { transform: rotate(360deg); }
1493
- }
1494
-
1495
1378
  /* Streaming Indicator */
1496
1379
  .streaming-content {
1497
1380
  display: flex;
@@ -1605,13 +1488,138 @@ body {
1605
1488
  -webkit-text-fill-color: var(--text-secondary);
1606
1489
  }
1607
1490
  }
1608
-
1609
- /* Input Area */
1610
- .input-area {
1611
- padding: 20px 24px;
1612
- border-top: 1px solid var(--border);
1613
- background: var(--bg-sidebar);
1491
+
1492
+ /* Input Area */
1493
+ .input-area {
1494
+ padding: 20px 24px;
1495
+ border-top: 1px solid var(--border);
1496
+ background: var(--bg-sidebar);
1497
+ flex-shrink: 0;
1498
+ }
1499
+
1500
+ /* 2026-06-16: 循环 status bar — 三态机 (loading / error / done)
1501
+ loading: spinner + 描述文本
1502
+ error: 🔴 提示 + 「重试」按钮 → POST /api/loop/retry
1503
+ done: ✓ 提示 + 「检查」按钮 → GET /api/loop/inspect (弹 modal 看循环产出)
1504
+ 不再显示循环计数, 不再显示百分比. */
1505
+ .loop-status-bar {
1506
+ position: relative;
1507
+ display: flex;
1508
+ align-items: center;
1509
+ gap: 10px;
1510
+ padding: 8px 24px;
1511
+ background: var(--bg-tertiary);
1512
+ border-top: 1px solid var(--border);
1513
+ font-size: 12px;
1514
+ color: var(--text-secondary);
1515
+ flex-shrink: 0;
1516
+ transition: opacity 0.2s ease, max-height 0.2s ease, background 0.2s ease;
1517
+ max-height: 60px;
1518
+ overflow: hidden;
1519
+ }
1520
+ .loop-status-bar[hidden] {
1521
+ display: none !important;
1522
+ }
1523
+ .loop-status-bar[data-tone="warn"] {
1524
+ background: rgba(245, 158, 11, 0.12);
1525
+ color: var(--warning, #f59e0b);
1526
+ border-top-color: rgba(245, 158, 11, 0.35);
1527
+ }
1528
+ .loop-status-bar[data-state="error"] {
1529
+ background: rgba(239, 68, 68, 0.12);
1530
+ color: var(--error, #ef4444);
1531
+ border-top-color: rgba(239, 68, 68, 0.35);
1532
+ animation: loop-status-shake 0.4s ease-out;
1533
+ }
1534
+ .loop-status-bar[data-state="retrying"] {
1535
+ background: rgba(245, 158, 11, 0.12);
1536
+ color: var(--warning, #f59e0b);
1537
+ border-top-color: rgba(245, 158, 11, 0.35);
1538
+ }
1539
+ .loop-status-bar[data-state="done"] {
1540
+ background: rgba(34, 197, 94, 0.12);
1541
+ color: var(--success, #22c55e);
1542
+ border-top-color: rgba(34, 197, 94, 0.35);
1543
+ animation: loop-status-fade-in 0.3s ease-out;
1544
+ }
1545
+ @keyframes loop-status-shake {
1546
+ 0%, 100% { transform: translateX(0); }
1547
+ 25% { transform: translateX(-3px); }
1548
+ 75% { transform: translateX(3px); }
1549
+ }
1550
+ @keyframes loop-status-fade-in {
1551
+ from { opacity: 0; transform: translateY(4px); }
1552
+ to { opacity: 1; transform: translateY(0); }
1553
+ }
1554
+ .loop-status-spinner {
1555
+ display: inline-block;
1556
+ width: 14px;
1557
+ height: 14px;
1558
+ border: 2px solid currentColor;
1559
+ border-right-color: transparent;
1560
+ border-radius: 50%;
1561
+ animation: loop-status-spin 0.7s linear infinite;
1562
+ flex-shrink: 0;
1563
+ opacity: 0.85;
1564
+ }
1565
+ .loop-status-bar[data-state="done"] .loop-status-spinner {
1566
+ animation: none;
1567
+ border-right-color: currentColor;
1568
+ opacity: 1;
1569
+ }
1570
+ .loop-status-icon {
1571
+ display: none;
1572
+ font-size: 14px;
1573
+ flex-shrink: 0;
1574
+ line-height: 1;
1575
+ }
1576
+ .loop-status-bar[data-state="done"] .loop-status-icon::before { content: '✓'; }
1577
+ .loop-status-bar[data-state="done"] .loop-status-icon {
1578
+ display: inline-block;
1579
+ }
1580
+ .loop-status-retry {
1581
+ flex-shrink: 0;
1582
+ font-size: 11px;
1583
+ font-weight: 600;
1584
+ font-variant-numeric: tabular-nums;
1585
+ padding: 2px 8px;
1586
+ background: rgba(245, 158, 11, 0.2);
1587
+ border-radius: 3px;
1588
+ letter-spacing: 0.3px;
1589
+ }
1590
+ @keyframes loop-status-spin {
1591
+ to { transform: rotate(360deg); }
1592
+ }
1593
+ .loop-status-text {
1594
+ flex: 1;
1595
+ font-weight: 500;
1596
+ white-space: nowrap;
1597
+ overflow: hidden;
1598
+ text-overflow: ellipsis;
1599
+ }
1600
+ .loop-status-action {
1614
1601
  flex-shrink: 0;
1602
+ padding: 4px 12px;
1603
+ font-size: 12px;
1604
+ font-weight: 600;
1605
+ border: 1px solid currentColor;
1606
+ border-radius: 4px;
1607
+ background: transparent;
1608
+ color: inherit;
1609
+ cursor: pointer;
1610
+ transition: background 0.15s ease, transform 0.1s ease;
1611
+ }
1612
+ .loop-status-action:hover {
1613
+ background: currentColor;
1614
+ color: var(--bg);
1615
+ }
1616
+ .loop-status-action:active {
1617
+ transform: scale(0.96);
1618
+ }
1619
+ .loop-status-action:disabled {
1620
+ opacity: 0.5;
1621
+ cursor: not-allowed;
1622
+ pointer-events: none;
1615
1623
  }
1616
1624
 
1617
1625
  .input-wrapper {
@@ -1667,6 +1675,24 @@ body {
1667
1675
  transform: scale(0.95);
1668
1676
  }
1669
1677
 
1678
+ /* 2026-06-15: 流式期间切到 abort 状态 — 红色边框 + 终止图标 */
1679
+ .send-btn[data-state="abort"] {
1680
+ background: var(--bg-main);
1681
+ border: 1.5px solid var(--warning);
1682
+ color: var(--warning);
1683
+ }
1684
+ .send-btn[data-state="abort"]:hover {
1685
+ background: color-mix(in srgb, var(--warning) 12%, var(--bg-main));
1686
+ transform: scale(1.05);
1687
+ }
1688
+ .send-btn[data-state="aborting"] {
1689
+ background: var(--bg-main);
1690
+ border: 1.5px solid var(--warning);
1691
+ color: var(--warning);
1692
+ opacity: 0.7;
1693
+ cursor: wait;
1694
+ }
1695
+
1670
1696
  /* Responsive */
1671
1697
  @media (max-width: 768px) {
1672
1698
  .sidebar {
@@ -1706,6 +1732,125 @@ body {
1706
1732
  display: flex;
1707
1733
  }
1708
1734
 
1735
+ /* 2026-06-16: Judgment Modal tabs (替换 HTML L233-258 内联) */
1736
+ .judgment-tab-bar {
1737
+ display: flex;
1738
+ border-bottom: 1px solid var(--border);
1739
+ margin-top: 20px;
1740
+ }
1741
+ .judgment-tab {
1742
+ flex: 1;
1743
+ padding: 10px 12px;
1744
+ background: transparent;
1745
+ border: none;
1746
+ border-bottom: 2px solid transparent;
1747
+ color: var(--text-secondary);
1748
+ font-size: 13px;
1749
+ font-weight: 600;
1750
+ cursor: pointer;
1751
+ transition: var(--transition);
1752
+ }
1753
+ .judgment-tab:hover {
1754
+ background: var(--bg-hover);
1755
+ color: var(--text-primary);
1756
+ }
1757
+ .judgment-tab.active {
1758
+ color: var(--accent-hover);
1759
+ border-bottom-color: var(--accent-hover);
1760
+ }
1761
+ .judgment-tab .tab-channel-name {
1762
+ font-weight: normal;
1763
+ color: var(--text-muted);
1764
+ }
1765
+ .judgment-status-bar {
1766
+ display: flex;
1767
+ gap: 6px;
1768
+ margin-top: 10px;
1769
+ font-size: 12px;
1770
+ align-items: center;
1771
+ }
1772
+ .judgment-status-bar .label {
1773
+ color: var(--text-muted);
1774
+ }
1775
+ .judgment-status-tab {
1776
+ background: var(--bg-hover);
1777
+ color: var(--text-secondary);
1778
+ border: none;
1779
+ padding: 3px 10px;
1780
+ border-radius: 3px;
1781
+ cursor: pointer;
1782
+ font-size: 11px;
1783
+ transition: var(--transition);
1784
+ }
1785
+ .judgment-status-tab:hover {
1786
+ background: var(--bg-active);
1787
+ color: var(--text-primary);
1788
+ }
1789
+ .judgment-status-tab.active {
1790
+ background: var(--accent);
1791
+ color: var(--bg);
1792
+ }
1793
+ .judgment-form-row {
1794
+ display: flex;
1795
+ gap: 8px;
1796
+ align-items: center;
1797
+ }
1798
+ .judgment-form-row label {
1799
+ margin: 0;
1800
+ }
1801
+ .judgment-form-row label + label {
1802
+ margin-left: 16px;
1803
+ }
1804
+ .judgment-list-header {
1805
+ margin-top: 16px;
1806
+ font-size: 14px;
1807
+ font-weight: 600;
1808
+ display: flex;
1809
+ align-items: center;
1810
+ gap: 12px;
1811
+ flex-wrap: wrap;
1812
+ }
1813
+ .judgment-list-actions {
1814
+ display: flex;
1815
+ align-items: center;
1816
+ gap: 6px;
1817
+ margin-left: auto;
1818
+ font-size: 12px;
1819
+ font-weight: normal;
1820
+ }
1821
+ .judgment-select-all-label {
1822
+ display: flex;
1823
+ align-items: center;
1824
+ gap: 4px;
1825
+ cursor: pointer;
1826
+ color: var(--text-muted);
1827
+ }
1828
+ .judgment-bulk-delete {
1829
+ background: transparent;
1830
+ border: 1px solid var(--error);
1831
+ color: var(--error);
1832
+ padding: 1px 8px;
1833
+ border-radius: 3px;
1834
+ cursor: pointer;
1835
+ font-size: 11px;
1836
+ opacity: 0.5;
1837
+ }
1838
+ .judgment-bulk-delete:not(:disabled):hover {
1839
+ opacity: 1;
1840
+ background: var(--error-bg);
1841
+ }
1842
+ .judgment-bulk-delete:disabled {
1843
+ cursor: not-allowed;
1844
+ }
1845
+ .judgment-error {
1846
+ color: var(--error);
1847
+ display: none;
1848
+ }
1849
+ .judgment-list {
1850
+ max-height: 420px;
1851
+ overflow-y: auto;
1852
+ }
1853
+
1709
1854
  .modal-content {
1710
1855
  background: var(--bg);
1711
1856
  border: 1px solid var(--border);
@@ -2775,10 +2920,6 @@ body {
2775
2920
  .btn-save:hover {
2776
2921
  opacity: 0.9;
2777
2922
  }
2778
-
2779
- @keyframes spin {
2780
- to { transform: rotate(360deg); }
2781
- }
2782
2923
  background: var(--bg-sidebar);
2783
2924
  border: 1px solid var(--border);
2784
2925
  border-radius: var(--radius-sm);
@@ -3094,10 +3235,6 @@ body:has(> .api-config-page) {
3094
3235
  will-change: transform;
3095
3236
  }
3096
3237
 
3097
- @keyframes spin {
3098
- to { transform: rotate(360deg); }
3099
- }
3100
-
3101
3238
  .error-state {
3102
3239
  display: flex;
3103
3240
  flex-direction: column;
@@ -3238,11 +3375,6 @@ body:has(> .api-config-page) {
3238
3375
  display: block;
3239
3376
  }
3240
3377
 
3241
- @keyframes fadeIn {
3242
- from { opacity: 0; }
3243
- to { opacity: 1; }
3244
- }
3245
-
3246
3378
  /* P2P Identity Card */
3247
3379
  .p2p-identity-card {
3248
3380
  background: var(--bg-secondary);
@@ -3280,11 +3412,6 @@ body:has(> .api-config-page) {
3280
3412
  background: var(--text-muted);
3281
3413
  }
3282
3414
 
3283
- @keyframes pulse {
3284
- 0%, 100% { opacity: 1; }
3285
- 50% { opacity: 0.5; }
3286
- }
3287
-
3288
3415
  .identity-info {
3289
3416
  margin-bottom: 16px;
3290
3417
  }
@@ -3862,11 +3989,6 @@ body:has(> .api-config-page) {
3862
3989
  animation: pulse 2s infinite;
3863
3990
  }
3864
3991
 
3865
- @keyframes pulse {
3866
- 0%, 100% { opacity: 1; }
3867
- 50% { opacity: 0.6; }
3868
- }
3869
-
3870
3992
  .peer-status-indicator {
3871
3993
  flex-shrink: 0;
3872
3994
  }
@@ -4356,18 +4478,8 @@ body:has(> .api-config-page) {
4356
4478
  }
4357
4479
 
4358
4480
  /* ============================================================
4359
- * 2026-06-10: Toast 入场动画 (simple-toast 用)
4481
+ * 2026-06-10: Toast 入场动画 (simple-toast 用 — 实际用 toastFade @ L3992, toast-in 是死代码)
4360
4482
  * ============================================================ */
4361
- @keyframes toast-in {
4362
- from {
4363
- opacity: 0;
4364
- transform: translateX(20px);
4365
- }
4366
- to {
4367
- opacity: 1;
4368
- transform: translateX(0);
4369
- }
4370
- }
4371
4483
 
4372
4484
  /* ============================================================
4373
4485
  * 2026-06-10: P2P peer-group 可折叠 — 复用 #remote-agents-section.collapsed 模式
@@ -4453,3 +4565,173 @@ body:has(> .api-config-page) {
4453
4565
  margin-top: 2px;
4454
4566
  font-family: 'JetBrains Mono', monospace;
4455
4567
  }
4568
+
4569
+ /* ============================================================================
4570
+ * 2026-06-15: step-timeline — 气泡内 4 状态步骤条
4571
+ * 摘要条 (折叠态) + 详情区 (展开态) 共用同一份 steps: Step[] 数据
4572
+ * 状态: idle ○ / active ● / done 🟢 / error 🔴
4573
+ * ========================================================================== */
4574
+
4575
+ .step-timeline {
4576
+ margin: 8px 0 4px 0;
4577
+ border: 1px solid var(--border);
4578
+ border-radius: 6px;
4579
+ background: var(--bg-hover);
4580
+ font-size: 12px;
4581
+ color: var(--text);
4582
+ overflow: hidden;
4583
+ }
4584
+
4585
+ .step-timeline-summary {
4586
+ display: flex;
4587
+ align-items: center;
4588
+ gap: 10px;
4589
+ padding: 6px 10px;
4590
+ cursor: pointer;
4591
+ user-select: none;
4592
+ transition: background 0.15s;
4593
+ }
4594
+ .step-timeline-summary:hover { background: var(--bg-main); }
4595
+
4596
+ .step-timeline-title {
4597
+ font-weight: 500;
4598
+ color: var(--text-secondary);
4599
+ white-space: nowrap;
4600
+ font-family: 'JetBrains Mono', monospace;
4601
+ font-size: 11px;
4602
+ }
4603
+
4604
+ .step-timeline-dots {
4605
+ display: flex;
4606
+ gap: 4px;
4607
+ align-items: center;
4608
+ flex: 1;
4609
+ min-width: 0;
4610
+ overflow: hidden;
4611
+ }
4612
+
4613
+ .step-dot {
4614
+ display: inline-block;
4615
+ width: 7px;
4616
+ height: 7px;
4617
+ border-radius: 50%;
4618
+ background: var(--text-muted);
4619
+ flex-shrink: 0;
4620
+ transition: background 0.2s, box-shadow 0.2s;
4621
+ }
4622
+ .step-dot[data-status="active"] {
4623
+ background: var(--accent);
4624
+ box-shadow: 0 0 0 0 var(--accent);
4625
+ animation: step-dot-pulse 1.4s infinite;
4626
+ }
4627
+ .step-dot[data-status="done"] { background: var(--success); }
4628
+ .step-dot[data-status="error"] { background: var(--warning); }
4629
+
4630
+ @keyframes step-dot-pulse {
4631
+ 0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 60%, transparent); }
4632
+ 70% { box-shadow: 0 0 0 5px color-mix(in srgb, var(--accent) 0%, transparent); }
4633
+ 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 0%, transparent); }
4634
+ }
4635
+
4636
+ .step-timeline-arrow {
4637
+ font-size: 10px;
4638
+ color: var(--text-muted);
4639
+ transition: transform 0.2s;
4640
+ flex-shrink: 0;
4641
+ }
4642
+
4643
+ .step-timeline-body {
4644
+ max-height: 0;
4645
+ overflow: hidden;
4646
+ transition: max-height 0.3s ease-in-out;
4647
+ border-top: 1px solid transparent;
4648
+ }
4649
+ .step-timeline:not([data-empty]) .step-timeline-body {
4650
+ /* 内容存在时给 body 一个合理上限, 避免长任务撑爆 */
4651
+ max-height: 320px;
4652
+ overflow-y: auto;
4653
+ border-top-color: var(--border);
4654
+ }
4655
+
4656
+ .step-timeline-list {
4657
+ list-style: none;
4658
+ margin: 0;
4659
+ padding: 6px 10px 8px 24px;
4660
+ position: relative;
4661
+ }
4662
+ /* 详情区垂直时间轴线 */
4663
+ .step-timeline-list::before {
4664
+ content: '';
4665
+ position: absolute;
4666
+ left: 14px;
4667
+ top: 12px;
4668
+ bottom: 12px;
4669
+ width: 1px;
4670
+ background: var(--border);
4671
+ }
4672
+
4673
+ .step-timeline-node {
4674
+ position: relative;
4675
+ padding: 4px 0;
4676
+ font-size: 12px;
4677
+ line-height: 1.5;
4678
+ color: var(--text-secondary);
4679
+ display: flex;
4680
+ align-items: baseline;
4681
+ gap: 8px;
4682
+ }
4683
+ .step-timeline-node:last-child { padding-bottom: 2px; }
4684
+
4685
+ .step-timeline-marker {
4686
+ position: absolute;
4687
+ left: -18px;
4688
+ top: 9px;
4689
+ width: 9px;
4690
+ height: 9px;
4691
+ border-radius: 50%;
4692
+ background: var(--text-muted);
4693
+ border: 2px solid var(--bg-hover);
4694
+ box-shadow: 0 0 0 1px var(--border);
4695
+ flex-shrink: 0;
4696
+ transition: background 0.2s, box-shadow 0.2s;
4697
+ }
4698
+ .step-timeline-node[data-status="active"] .step-timeline-marker {
4699
+ background: var(--accent);
4700
+ box-shadow: 0 0 0 1px var(--accent);
4701
+ animation: step-dot-pulse 1.4s infinite;
4702
+ }
4703
+ .step-timeline-node[data-status="done"] .step-timeline-marker { background: var(--success); box-shadow: 0 0 0 1px var(--success); }
4704
+ .step-timeline-node[data-status="error"] .step-timeline-marker { background: var(--warning); box-shadow: 0 0 0 1px var(--warning); }
4705
+
4706
+ .step-timeline-label {
4707
+ font-family: 'JetBrains Mono', monospace;
4708
+ font-size: 11px;
4709
+ color: var(--text);
4710
+ flex-shrink: 0;
4711
+ }
4712
+ .step-timeline-node[data-status="error"] .step-timeline-label { color: var(--warning); }
4713
+ .step-timeline-node[data-status="done"] .step-timeline-label { color: var(--success); }
4714
+
4715
+ .step-timeline-args {
4716
+ font-family: 'JetBrains Mono', monospace;
4717
+ font-size: 10px;
4718
+ color: var(--text-muted);
4719
+ white-space: nowrap;
4720
+ overflow: hidden;
4721
+ text-overflow: ellipsis;
4722
+ flex: 1;
4723
+ min-width: 0;
4724
+ }
4725
+
4726
+ .step-timeline-more {
4727
+ list-style: none;
4728
+ padding: 4px 0 4px 0;
4729
+ margin: 0;
4730
+ font-size: 11px;
4731
+ color: var(--accent);
4732
+ cursor: pointer;
4733
+ user-select: none;
4734
+ font-family: 'JetBrains Mono', monospace;
4735
+ }
4736
+ .step-timeline-more:hover { text-decoration: underline; }
4737
+