foxclaw 0.1.2 → 0.1.4

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 (368) hide show
  1. package/index.js +1 -8
  2. package/package.json +1 -1
  3. package/python/.env.example +8 -0
  4. package/python/.github/workflows/ci.yml +47 -2
  5. package/python/.github/workflows/release.yml +5 -0
  6. package/python/CHANGELOG.md +100 -0
  7. package/python/CHANGELOG_CN.md +100 -0
  8. package/python/README.md +17 -2
  9. package/python/README_CN.md +38 -20
  10. package/python/bench/bm25_audit.py +1 -14
  11. package/python/bench/bm25_regression.py +0 -1
  12. package/python/bench/bm25_stress.py +0 -4
  13. package/python/bench/cd_audit.py +0 -23
  14. package/python/bench/chaos.py +6 -8
  15. package/python/bench/e2e_real_models.py +0 -1
  16. package/python/bench/llm_retry_test.py +2 -9
  17. package/python/bench/load_test.py +5 -8
  18. package/python/bench/vector_ivf_upgrade.py +1 -7
  19. package/python/docs/CONTENT_GUARD.md +189 -0
  20. package/python/docs/CONTENT_GUARD_CN.md +189 -0
  21. package/python/docs/RELEASE.md +78 -37
  22. package/python/docs/RUN_CN.md +2 -2
  23. package/python/evals/governance/cases.py +0 -37
  24. package/python/evals/governance/run_evals.py +5 -37
  25. package/python/examples/governance_middleware_demo.py +1 -6
  26. package/python/examples/langgraph_governance_demo.py +7 -11
  27. package/python/foxclaw/__init__.py +74 -152
  28. package/python/foxclaw/agents/base.py +82 -136
  29. package/python/foxclaw/agents/impl/_helpers.py +2 -10
  30. package/python/foxclaw/agents/impl/finance.py +4 -21
  31. package/python/foxclaw/agents/impl/office.py +7 -24
  32. package/python/foxclaw/agents/impl/supervisor.py +12 -79
  33. package/python/foxclaw/agents/mixins/_context.py +0 -23
  34. package/python/foxclaw/agents/mixins/augment.py +10 -16
  35. package/python/foxclaw/agents/mixins/llm.py +7 -6
  36. package/python/foxclaw/agents/mixins/memory.py +23 -3
  37. package/python/foxclaw/agents/mixins/preference.py +58 -8
  38. package/python/foxclaw/agents/mixins/prompt.py +59 -12
  39. package/python/foxclaw/agents/mixins/skillbox.py +6 -6
  40. package/python/foxclaw/agents/mixins/tool_exec.py +16 -42
  41. package/python/foxclaw/agents/rules/finance/RULES.md +131 -0
  42. package/python/foxclaw/api/__init__.py +18 -77
  43. package/python/foxclaw/api/_state.py +43 -0
  44. package/python/foxclaw/api/bootstrap.py +114 -0
  45. package/python/foxclaw/api/middleware.py +5 -28
  46. package/python/foxclaw/api/routes/ahs.py +60 -73
  47. package/python/foxclaw/api/routes/attachments.py +5 -6
  48. package/python/foxclaw/api/routes/browser.py +7 -11
  49. package/python/foxclaw/api/routes/domain.py +18 -26
  50. package/python/foxclaw/api/routes/knowledge.py +3 -21
  51. package/python/foxclaw/api/routes/llm_admin.py +21 -33
  52. package/python/foxclaw/api/routes/memory.py +50 -12
  53. package/python/foxclaw/api/routes/orchestration.py +3 -5
  54. package/python/foxclaw/api/routes/recovery.py +4 -3
  55. package/python/foxclaw/api/routes/review.py +2 -11
  56. package/python/foxclaw/api/routes/search.py +3 -7
  57. package/python/foxclaw/api/routes/system.py +33 -49
  58. package/python/foxclaw/api/routes/task.py +31 -49
  59. package/python/foxclaw/api/routes/ws.py +2 -6
  60. package/python/foxclaw/api/spine.py +1 -4
  61. package/python/foxclaw/behavior/__init__.py +20 -0
  62. package/python/foxclaw/behavior/behavior.yaml +62 -0
  63. package/python/foxclaw/behavior/spec.py +287 -0
  64. package/python/foxclaw/browser/action/action_executor.py +1 -5
  65. package/python/foxclaw/browser/action/action_types.py +0 -1
  66. package/python/foxclaw/browser/action/url_policy.py +1 -5
  67. package/python/foxclaw/browser/adapter/web_adapter.py +1 -1
  68. package/python/foxclaw/browser/driver/playwright_driver.py +20 -16
  69. package/python/foxclaw/browser/perception/dom_extractor.py +0 -1
  70. package/python/foxclaw/browser/perception/element_indexer.py +1 -2
  71. package/python/foxclaw/browser/service.py +7 -11
  72. package/python/foxclaw/capability/embedding_service.py +4 -6
  73. package/python/foxclaw/channels/__init__.py +9 -11
  74. package/python/foxclaw/channels/discord.py +4 -13
  75. package/python/foxclaw/channels/dispatcher.py +2 -27
  76. package/python/foxclaw/channels/feishu.py +10 -20
  77. package/python/foxclaw/channels/openclaw_bridge.py +4 -9
  78. package/python/foxclaw/channels/signing.py +9 -9
  79. package/python/foxclaw/channels/telegram.py +3 -4
  80. package/python/foxclaw/channels/weixin.py +7 -17
  81. package/python/foxclaw/cli.py +42 -13
  82. package/python/foxclaw/cognitive/reasoner.py +9 -10
  83. package/python/foxclaw/cognitive/state.py +18 -24
  84. package/python/foxclaw/core/audit_chain.py +1 -3
  85. package/python/foxclaw/core/audit_sink.py +3 -3
  86. package/python/foxclaw/core/compaction.py +8 -26
  87. package/python/foxclaw/core/config.py +2 -2
  88. package/python/foxclaw/core/confirm_nonce.py +6 -12
  89. package/python/foxclaw/core/content_guard.py +341 -0
  90. package/python/foxclaw/core/envfile.py +2 -2
  91. package/python/foxclaw/core/failure_policy.py +17 -26
  92. package/python/foxclaw/core/gateway.py +6 -10
  93. package/python/foxclaw/core/governance_audit.py +3 -7
  94. package/python/foxclaw/core/idempotency.py +15 -22
  95. package/python/foxclaw/core/injection_guard.py +10 -29
  96. package/python/foxclaw/core/memory_adapter.py +53 -60
  97. package/python/foxclaw/core/metrics.py +4 -5
  98. package/python/foxclaw/core/model_router.py +74 -150
  99. package/python/foxclaw/core/paths.py +1 -1
  100. package/python/foxclaw/core/recovery.py +21 -34
  101. package/python/foxclaw/core/scheduler.py +23 -26
  102. package/python/foxclaw/core/secrets.py +0 -3
  103. package/python/foxclaw/core/sensitive_write.py +283 -0
  104. package/python/foxclaw/core/sessions.py +4 -6
  105. package/python/foxclaw/core/settings.py +16 -32
  106. package/python/foxclaw/core/shared_write.py +11 -23
  107. package/python/foxclaw/core/steering_queue.py +12 -11
  108. package/python/foxclaw/core/system_bus.py +1 -1
  109. package/python/foxclaw/core/thought_chain.py +30 -32
  110. package/python/foxclaw/core/token_meter.py +9 -13
  111. package/python/foxclaw/core/tools.py +4 -12
  112. package/python/foxclaw/core/tracing.py +25 -40
  113. package/python/foxclaw/core/truth_pipeline.py +5 -9
  114. package/python/foxclaw/core/update_check.py +149 -0
  115. package/python/foxclaw/core/vec_recall_adapter.py +11 -37
  116. package/python/foxclaw/core/verify.py +6 -14
  117. package/python/foxclaw/core/web_search.py +4 -28
  118. package/python/foxclaw/finance/evidence.py +14 -18
  119. package/python/foxclaw/finance/fx.py +1 -3
  120. package/python/foxclaw/finance/graph.py +9 -18
  121. package/python/foxclaw/finance/models.py +20 -24
  122. package/python/foxclaw/finance/nlparse.py +12 -72
  123. package/python/foxclaw/finance/policy.py +8 -36
  124. package/python/foxclaw/finance/reasoner.py +3 -11
  125. package/python/foxclaw/finance/reasoning.py +13 -34
  126. package/python/foxclaw/finance/reconcile.py +5 -10
  127. package/python/foxclaw/finance/runtime.py +19 -46
  128. package/python/foxclaw/governance/middleware.py +13 -21
  129. package/python/foxclaw/harness/_base.py +2 -8
  130. package/python/foxclaw/harness/_policy.py +19 -38
  131. package/python/foxclaw/harness/drift.py +1 -13
  132. package/python/foxclaw/harness/event_bus.py +2 -5
  133. package/python/foxclaw/harness/harness.py +9 -97
  134. package/python/foxclaw/harness/loop_detection.py +11 -18
  135. package/python/foxclaw/itinerary/amap_client.py +2 -5
  136. package/python/foxclaw/itinerary/models.py +7 -7
  137. package/python/foxclaw/itinerary/reasoner.py +1 -6
  138. package/python/foxclaw/itinerary/reasoning.py +15 -21
  139. package/python/foxclaw/itinerary/runtime.py +8 -12
  140. package/python/foxclaw/kernel/capabilities.py +5 -6
  141. package/python/foxclaw/kernel/policy_gate.py +4 -10
  142. package/python/foxclaw/kernel/process_manager.py +17 -36
  143. package/python/foxclaw/kernel/scheduler.py +3 -9
  144. package/python/foxclaw/kernel/sentinel.py +13 -23
  145. package/python/foxclaw/kernel/sentinel_client.py +12 -15
  146. package/python/foxclaw/kernel/spine.py +9 -9
  147. package/python/foxclaw/knowledge/__init__.py +4 -20
  148. package/python/foxclaw/knowledge/truth_crystallizer.py +5 -8
  149. package/python/foxclaw/learning/knowledge_graph.py +4 -9
  150. package/python/foxclaw/learning/models.py +13 -13
  151. package/python/foxclaw/learning/reasoner.py +1 -4
  152. package/python/foxclaw/learning/runtime.py +19 -31
  153. package/python/foxclaw/learning/spaced_repetition.py +2 -7
  154. package/python/foxclaw/mcp_server.py +2 -3
  155. package/python/foxclaw/orchestration/__init__.py +16 -33
  156. package/python/foxclaw/pipeline/cognitive_pipeline.py +45 -97
  157. package/python/foxclaw/pipeline/stage_meta.py +21 -0
  158. package/python/foxclaw/pipeline/supervisor_stages.py +13 -42
  159. package/python/foxclaw/planning/llm_planner.py +3 -3
  160. package/python/foxclaw/planning/planner.py +6 -11
  161. package/python/foxclaw/search/agent_port.py +7 -11
  162. package/python/foxclaw/search/evidence.py +0 -4
  163. package/python/foxclaw/search/internal_search.py +3 -5
  164. package/python/foxclaw/search/models.py +11 -13
  165. package/python/foxclaw/search/planner.py +3 -3
  166. package/python/foxclaw/search/retriever.py +1 -1
  167. package/python/foxclaw/search/runtime.py +1 -8
  168. package/python/foxclaw/skills/__init__.py +46 -100
  169. package/python/foxclaw/skills/archive.py +111 -0
  170. package/python/foxclaw/skills/fetch.py +226 -0
  171. package/python/foxclaw/skills/hooks_spec.py +21 -25
  172. package/python/foxclaw/skills/install_cmd.py +216 -0
  173. package/python/foxclaw/skills/lifecycle.py +16 -42
  174. package/python/foxclaw/skills/markdown_skill.py +10 -9
  175. package/python/foxclaw/skills/mcp_client.py +5 -11
  176. package/python/foxclaw/skills/mcp_store.py +0 -3
  177. package/python/foxclaw/skills/permission.py +13 -48
  178. package/python/foxclaw/skills/pipeline.py +21 -53
  179. package/python/foxclaw/skills/policy.py +4 -10
  180. package/python/foxclaw/skills/review.py +3 -3
  181. package/python/frontend/deck/auth.js +0 -7
  182. package/python/frontend/deck/chat_model_picker.js +0 -54
  183. package/python/frontend/deck/domain.js +0 -20
  184. package/python/frontend/deck/main.js +0 -144
  185. package/python/frontend/deck/markdown.js +0 -4
  186. package/python/frontend/deck/settings.js +1 -18
  187. package/python/frontend/deck/state.js +0 -1
  188. package/python/frontend/deck/util.js +0 -2
  189. package/python/frontend/deck/visuals.js +0 -22
  190. package/python/frontend/planet/planet.js +18 -201
  191. package/python/frontend/v3/assets/index-JKfHlb-a.css +1 -0
  192. package/python/frontend/v3/assets/index-tN90dpUH.js +34 -0
  193. package/python/frontend/v3/index.html +3 -3
  194. package/python/frontend/widget_runtime.js +0 -43
  195. package/python/frontend/widgets.js +0 -57
  196. package/python/frontend_src/index.html +1 -1
  197. package/python/frontend_src/package-lock.json +2 -2
  198. package/python/frontend_src/package.json +1 -1
  199. package/python/frontend_src/src/App.vue +3 -7
  200. package/python/frontend_src/src/api.js +0 -7
  201. package/python/frontend_src/src/components/ChatDock.vue +27 -39
  202. package/python/frontend_src/src/components/DocViewer.vue +0 -9
  203. package/python/frontend_src/src/components/Inspector.vue +0 -6
  204. package/python/frontend_src/src/components/LeftRail.vue +60 -39
  205. package/python/frontend_src/src/components/MenuPopover.vue +9 -11
  206. package/python/frontend_src/src/components/MessageStream.vue +18 -30
  207. package/python/frontend_src/src/components/ModelPicker.vue +0 -5
  208. package/python/frontend_src/src/components/QuickIngest.vue +0 -6
  209. package/python/frontend_src/src/components/Stage.vue +71 -25
  210. package/python/frontend_src/src/components/ToolMenu.vue +0 -3
  211. package/python/frontend_src/src/components/TopBar.vue +38 -10
  212. package/python/frontend_src/src/components/panels/ActivityPanel.vue +0 -2
  213. package/python/frontend_src/src/components/panels/AgentsPanel.vue +2 -5
  214. package/python/frontend_src/src/components/panels/KnowledgePanel.vue +0 -16
  215. package/python/frontend_src/src/components/panels/MemoryPanel.vue +42 -3
  216. package/python/frontend_src/src/components/panels/PanelBox.vue +6 -7
  217. package/python/frontend_src/src/components/panels/ReviewPanel.vue +0 -16
  218. package/python/frontend_src/src/components/panels/SettingsPanel.vue +142 -38
  219. package/python/frontend_src/src/components/panels/TasksPanel.vue +0 -1
  220. package/python/frontend_src/src/components/panels/ToolsPanel.vue +125 -19
  221. package/python/frontend_src/src/lib/fmt.js +0 -4
  222. package/python/frontend_src/src/lib/i18n.js +53 -0
  223. package/python/frontend_src/src/lib/locales/en.js +173 -0
  224. package/python/frontend_src/src/lib/locales/zh.js +174 -0
  225. package/python/frontend_src/src/lib/md.js +0 -14
  226. package/python/frontend_src/src/main.js +2 -0
  227. package/python/frontend_src/src/stores/app.js +17 -32
  228. package/python/frontend_src/src/stores/chat.js +0 -34
  229. package/python/frontend_src/src/stores/model.js +0 -8
  230. package/python/frontend_src/src/stores/panels.js +16 -44
  231. package/python/frontend_src/src/stores/profile.js +31 -0
  232. package/python/frontend_src/src/stores/system.js +25 -0
  233. package/python/frontend_src/vite.config.js +0 -7
  234. package/python/pyproject.toml +17 -3
  235. package/python/requirements.txt +311 -0
  236. package/python/tests/conftest.py +0 -22
  237. package/python/tests/run_all.py +4 -66
  238. package/python/tests/test_agent_lifecycle.py +4 -38
  239. package/python/tests/test_agent_rules.py +81 -0
  240. package/python/tests/test_ahs_p2.py +4 -25
  241. package/python/tests/test_anthropic_tools.py +1 -15
  242. package/python/tests/test_api.py +19 -9
  243. package/python/tests/test_api_auth.py +1 -5
  244. package/python/tests/test_attachments.py +9 -25
  245. package/python/tests/test_audit_chain.py +2 -7
  246. package/python/tests/test_audit_sink.py +0 -6
  247. package/python/tests/test_behavior_spec.py +198 -0
  248. package/python/tests/test_browser.py +2 -6
  249. package/python/tests/test_browser_request_guard.py +0 -4
  250. package/python/tests/test_capabilities.py +0 -6
  251. package/python/tests/test_channel_signing.py +2 -9
  252. package/python/tests/test_channels.py +1 -11
  253. package/python/tests/test_config_layering.py +0 -4
  254. package/python/tests/test_confirm_nonce.py +1 -12
  255. package/python/tests/test_conflict_dismiss.py +143 -0
  256. package/python/tests/test_content_guard.py +177 -0
  257. package/python/tests/test_context_compaction_wiring.py +1 -7
  258. package/python/tests/test_dispatch.py +0 -6
  259. package/python/tests/test_domain_evals.py +11 -80
  260. package/python/tests/test_domain_import.py +0 -6
  261. package/python/tests/test_domain_reasoners.py +0 -14
  262. package/python/tests/test_e2e.py +0 -17
  263. package/python/tests/test_emb_cache.py +7 -17
  264. package/python/tests/test_embedding_singleton.py +1 -3
  265. package/python/tests/test_evals_smoke.py +0 -24
  266. package/python/tests/test_event_spine.py +10 -18
  267. package/python/tests/test_evidence_semantic.py +1 -14
  268. package/python/tests/test_evidence_sse.py +3 -6
  269. package/python/tests/test_file_ingest.py +0 -11
  270. package/python/tests/test_finance.py +0 -9
  271. package/python/tests/test_finance_ledger.py +5 -12
  272. package/python/tests/test_finance_persist.py +8 -12
  273. package/python/tests/test_gateway.py +3 -22
  274. package/python/tests/test_governance.py +5 -52
  275. package/python/tests/test_governance_audit.py +4 -39
  276. package/python/tests/test_governance_middleware.py +1 -7
  277. package/python/tests/test_hkc.py +6 -24
  278. package/python/tests/test_hkc_index_build_manager.py +0 -33
  279. package/python/tests/test_hkc_manifest_reuse.py +4 -27
  280. package/python/tests/test_hkc_search_event_sync.py +3 -54
  281. package/python/tests/test_import_path_guard.py +0 -6
  282. package/python/tests/test_injection_guard.py +18 -36
  283. package/python/tests/test_integration.py +5 -29
  284. package/python/tests/test_itinerary.py +0 -3
  285. package/python/tests/test_kee_semantic.py +0 -5
  286. package/python/tests/test_kernel.py +1 -11
  287. package/python/tests/test_learning.py +3 -12
  288. package/python/tests/test_llm_admin.py +4 -19
  289. package/python/tests/test_llm_planner.py +1 -23
  290. package/python/tests/test_markdown_skills.py +3 -14
  291. package/python/tests/test_markdown_skills_openclaw.py +4 -9
  292. package/python/tests/test_mcp_connectors.py +3 -15
  293. package/python/tests/test_mcp_guardian_discovery.py +2 -6
  294. package/python/tests/test_mcp_no_memory.py +3 -3
  295. package/python/tests/test_mcp_policy_gate.py +0 -1
  296. package/python/tests/test_mcp_server.py +6 -9
  297. package/python/tests/test_memory_recall.py +1 -4
  298. package/python/tests/test_metrics.py +0 -8
  299. package/python/tests/test_multi_chain.py +1 -13
  300. package/python/tests/test_multimodal.py +5 -18
  301. package/python/tests/test_negotiation.py +3 -13
  302. package/python/tests/test_orchestration.py +1 -11
  303. package/python/tests/test_orchestration_decoupled.py +0 -6
  304. package/python/tests/test_p3_p5_hardening.py +3 -17
  305. package/python/tests/test_parallel_dispatch.py +4 -12
  306. package/python/tests/test_pipeline.py +17 -58
  307. package/python/tests/test_plan_visible.py +4 -4
  308. package/python/tests/test_planner.py +0 -7
  309. package/python/tests/test_policy_gate.py +2 -3
  310. package/python/tests/test_profile.py +67 -0
  311. package/python/tests/test_readme_claims.py +163 -0
  312. package/python/tests/test_reasoner.py +2 -17
  313. package/python/tests/test_release_check.py +2 -13
  314. package/python/tests/test_resume_checkpoint.py +7 -15
  315. package/python/tests/test_routing.py +2 -12
  316. package/python/tests/test_scheduler.py +7 -10
  317. package/python/tests/test_search.py +1 -11
  318. package/python/tests/test_secrets.py +4 -10
  319. package/python/tests/test_semantic.py +1 -10
  320. package/python/tests/test_sensitive_write.py +181 -0
  321. package/python/tests/test_sessions.py +3 -4
  322. package/python/tests/test_settings.py +2 -18
  323. package/python/tests/test_shadow_learning.py +3 -43
  324. package/python/tests/test_shared_write.py +0 -7
  325. package/python/tests/test_skill_taint_gate.py +1 -10
  326. package/python/tests/test_skills.py +2 -18
  327. package/python/tests/test_skills_fetch.py +282 -0
  328. package/python/tests/test_stats_and_events.py +2 -5
  329. package/python/tests/test_streaming.py +2 -7
  330. package/python/tests/test_supervisor_pipeline.py +4 -5
  331. package/python/tests/test_supervisor_triage.py +4 -10
  332. package/python/tests/test_taint.py +2 -7
  333. package/python/tests/test_task_stream.py +1 -12
  334. package/python/tests/test_thinking_sse.py +0 -1
  335. package/python/tests/test_tool_center.py +1 -17
  336. package/python/tests/test_tool_parallel.py +2 -2
  337. package/python/tests/test_tool_params.py +1 -5
  338. package/python/tests/test_tool_use.py +0 -13
  339. package/python/tests/test_toplevel_concurrency.py +3 -4
  340. package/python/tests/test_tracing.py +7 -41
  341. package/python/tests/test_truth_crystallizer.py +4 -6
  342. package/python/tests/test_truth_flow.py +2 -7
  343. package/python/tests/test_update_check.py +95 -0
  344. package/python/tests/test_verify_evidence.py +8 -21
  345. package/python/tests/test_version_sync.py +35 -6
  346. package/python/tests/test_web_trigger.py +0 -17
  347. package/python/tools/build_content_lexicon.py +218 -0
  348. package/python/tools/bundle_web.py +98 -0
  349. package/python/tools/check_faiss_type.py +0 -1
  350. package/python/tools/check_log.ps1 +0 -8
  351. package/python/tools/mypy_baseline.txt +12 -4
  352. package/python/tools/mypy_ratchet.py +52 -6
  353. package/python/tools/pack.py +0 -5
  354. package/python/tools/recheck_conflicts.py +156 -0
  355. package/python/tools/release_check.py +24 -15
  356. package/python/tools/restart_foxclaw.ps1 +5 -8
  357. package/python/tools/shared_write_audit.py +1 -15
  358. package/python/tools/size_check.py +1 -1
  359. package/python/tools/strip_comments.py +228 -0
  360. package/python/vendor/hkc/hkc_api/routes/ability.py +31 -0
  361. package/python/vendor/hkc/hkc_api/schemas.py +11 -0
  362. package/python/vendor/hkc/hkc_kee/kee.py +124 -3
  363. package/python/vendor/hkc/hkc_sdk/base.py +22 -0
  364. package/python/vendor/hkc/hkc_sdk/direct_client.py +10 -0
  365. package/python/vendor/hkc/hkc_sdk/http_client.py +19 -0
  366. package/python/foxclaw/api/app.py +0 -123
  367. package/python/frontend/v3/assets/index-BD7VPbMV.js +0 -33
  368. package/python/frontend/v3/assets/index-CAvnYWGH.css +0 -1
@@ -44,9 +44,6 @@ async function flip(s) {
44
44
  busy.value = ''
45
45
  }
46
46
 
47
- /* ── 单技能测试:POST /ahs/skills/{id}/test ──
48
- 走真管线(权限/断路器/SSRF),所以界面要能填参数,也要把 needs_confirmation /
49
- blocked / circuit_open 这些非成功态原样显示,不能只画个绿勾。 */
50
47
  const tId = ref('')
51
48
  const tArgs = ref({})
52
49
  const tBusy = ref(false)
@@ -74,7 +71,6 @@ function beginTest(s) {
74
71
  err.value = ''
75
72
  }
76
73
 
77
- /* params 是 {名: 类型} 的朴素 schema,类型只是提示;这里按声明做最小转换,其余原样送字符串 */
78
74
  function coerce(params, args) {
79
75
  const out = {}
80
76
  for (const [k, ty] of Object.entries(params || {})) {
@@ -133,7 +129,6 @@ async function dropSkill(s) {
133
129
 
134
130
  const splitList = (t) => String(t || '').split(/[,,\s]+/).map((s) => s.trim()).filter(Boolean)
135
131
 
136
- /* "city:str, days:int" → {city:"str", days:"int"} */
137
132
  function parseParams(txt) {
138
133
  const out = {}
139
134
  for (const part of String(txt || '').split(/[,,;\n]/)) {
@@ -145,7 +140,6 @@ function parseParams(txt) {
145
140
  return out
146
141
  }
147
142
 
148
- /* "Authorization: Bearer x" 每行一条 → dict(空行 / 无冒号行忽略) */
149
143
  function parseHeaders(txt) {
150
144
  const out = {}
151
145
  for (const line of String(txt || '').split('\n')) {
@@ -155,8 +149,6 @@ function parseHeaders(txt) {
155
149
  return out
156
150
  }
157
151
 
158
- /* ── 安装技能:POST /ahs/skills ──
159
- 后端只收 web_api / mcp;审核门 deny → 403, warn → 409 needs_ack(要再点一次「已知风险」) */
160
152
  const SIDE = { read: 'read · 只读', write: 'write · 写入', send: 'send · 代发', pay: 'pay · 付款' }
161
153
  const showIns = ref(false)
162
154
  const insBusy = ref(false)
@@ -220,8 +212,93 @@ async function doInstall(ack = false) {
220
212
  }
221
213
  }
222
214
 
223
- /* ── 连接器:POST|DELETE /ahs/mcp/servers ──
224
- 接入会真连一次 server 拉工具清单(可能几十秒);连不上是 502,原样显示 */
215
+ const MI_MAX = 4 * 1024 * 1024
216
+ const miOpen = ref(false)
217
+ const miBusy = ref(false)
218
+ const miErr = ref('')
219
+ const miOk = ref('')
220
+ const miAck = ref(false)
221
+ const miText = ref('')
222
+ const miFile = ref('')
223
+ const miB64 = ref('') // zip 的 base64;非空时优先于 miText
224
+ const miRef = ref(null)
225
+
226
+ function toggleMi() {
227
+ miOpen.value = !miOpen.value
228
+ miErr.value = ''
229
+ miOk.value = ''
230
+ miAck.value = false
231
+ }
232
+
233
+ function resetMi() {
234
+ miText.value = ''
235
+ miFile.value = ''
236
+ miB64.value = ''
237
+ miAck.value = false
238
+ if (miRef.value) miRef.value.value = ''
239
+ }
240
+
241
+ function toB64(file) {
242
+ return new Promise((resolve, reject) => {
243
+ const fr = new FileReader()
244
+ fr.onload = () => {
245
+ const s = String(fr.result || '')
246
+ resolve(s.slice(s.indexOf(',') + 1)) // 去掉 data:...;base64, 前缀
247
+ }
248
+ fr.onerror = () => reject(new Error('读取文件失败'))
249
+ fr.readAsDataURL(file)
250
+ })
251
+ }
252
+
253
+ async function onMiFile(ev) {
254
+ const f = ev.target.files && ev.target.files[0]
255
+ miFile.value = ''
256
+ miB64.value = ''
257
+ miErr.value = ''
258
+ miOk.value = ''
259
+ miAck.value = false
260
+ if (!f) return
261
+ miFile.value = `${f.name} · ${(f.size / 1024).toFixed(0)} KB`
262
+ if (f.size > MI_MAX) { miErr.value = '文件超过 4MB,拒绝上传'; return }
263
+ try {
264
+ if (/\.zip$/i.test(f.name)) {
265
+ miB64.value = await toB64(f)
266
+ miText.value = ''
267
+ } else {
268
+ miText.value = await f.text()
269
+ }
270
+ } catch (e) {
271
+ miErr.value = String(e.message || e)
272
+ }
273
+ }
274
+
275
+ async function doMdInstall(ack = false) {
276
+ if (miBusy.value) return
277
+ const content = miText.value.trim()
278
+ if (!ack && !content && !miB64.value) {
279
+ miErr.value = '粘贴 SKILL.md 正文,或选一个 .md / .zip 文件'
280
+ return
281
+ }
282
+ miBusy.value = true
283
+ miErr.value = ''
284
+ miOk.value = ''
285
+ const body = { acknowledged: ack }
286
+ if (miB64.value) body.package_b64 = miB64.value
287
+ else body.content = content
288
+ try {
289
+ const d = await postJSON('/ahs/md-skills', body)
290
+ const name = (d.skill && (d.skill.name || d.skill.id)) || '指令技能'
291
+ miOk.value = `${d.created ? '已安装' : '已更新'}「${name}」`
292
+ resetMi()
293
+ await refreshPanel('tools')
294
+ } catch (e) {
295
+ miErr.value = String(e.message || e)
296
+ miAck.value = !!(e.detail && e.detail.needs_ack)
297
+ } finally {
298
+ miBusy.value = false
299
+ }
300
+ }
301
+
225
302
  const showMcpAdd = ref(false)
226
303
  const mcpBusy = ref(false)
227
304
  const mcpErr = ref('')
@@ -265,7 +342,6 @@ async function addMcp(ack = false) {
265
342
  }
266
343
  }
267
344
 
268
- /* 重连:server 那边的工具会变,POST .../refresh 增量对齐注册表 */
269
345
  async function refreshMcp(s) {
270
346
  if (mcpBusy.value) return
271
347
  mcpBusy.value = true
@@ -392,6 +468,43 @@ async function delMcp(s) {
392
468
  </div>
393
469
  </div>
394
470
 
471
+ <div class="pn-sec">
472
+ <div class="pn-h">
473
+ 安装指令技能
474
+ <button class="mbtn" @click="toggleMi">{{ miOpen ? '收起' : '+ 上传' }}</button>
475
+ </div>
476
+ <div v-if="miOpen" class="tk-form">
477
+ <label class="f"><span>SKILL.md 或 OpenClaw 包(.md / .zip)</span>
478
+ <input ref="miRef" type="file" accept=".md,.markdown,.zip" @change="onMiFile" />
479
+ </label>
480
+ <div v-if="miFile" class="pn-note">{{ miFile }}</div>
481
+ <label class="f"><span>或粘贴正文(frontmatter + 指示)</span>
482
+ <textarea
483
+ v-model="miText"
484
+ rows="8"
485
+ spellcheck="false"
486
+ :disabled="!!miB64"
487
+ placeholder="--- name: my-skill / description: 什么时候用它 --- 然后写正文"
488
+ />
489
+ </label>
490
+ <div class="fbar">
491
+ <button class="go" :disabled="miBusy" @click="doMdInstall(false)">
492
+ {{ miBusy ? '安装中…' : '安装' }}
493
+ </button>
494
+ <button v-if="miAck" class="go warn" :disabled="miBusy" @click="doMdInstall(true)">
495
+ 已知风险,继续安装
496
+ </button>
497
+ <span v-if="miErr" class="tip bad">{{ miErr }}</span>
498
+ <span v-else-if="miOk" class="tip ok">{{ miOk }}</span>
499
+ <span v-else class="tip dim">只取 SKILL.md 与 _meta.json;包内 scripts/ 不落地、不执行</span>
500
+ </div>
501
+ </div>
502
+ <div v-else class="pn-note">
503
+ 指令技能是注入提示词的 markdown,不是可执行工具。命令行也能装:
504
+ <code>foxclaw skills install @owner/slug</code>、<code>github:owner/repo</code>、<code>./pkg.zip</code>。
505
+ </div>
506
+ </div>
507
+
395
508
  <div class="pn-sec">
396
509
  <div class="pn-h">
397
510
  安装技能
@@ -532,11 +645,6 @@ async function delMcp(s) {
532
645
  <button class="mbtn danger" @click="delMcp(s)">移除</button>
533
646
  </div>
534
647
  </div>
535
-
536
- <div class="pn-note">
537
- 指令技能正文 <code>/api/ahs/md-skills/{id}</code>,执行技能运行 <code>POST /api/ahs/skills/{id}/test</code>;
538
- 连接器与技能面板是同一份数据(<code>/api/ahs/mcp/servers</code>)。
539
- </div>
540
648
  </PanelBox>
541
649
  </template>
542
650
 
@@ -550,7 +658,6 @@ async function delMcp(s) {
550
658
  .sw.on { background: rgba(26, 157, 95, 0.12); color: var(--green); }
551
659
  .sw:disabled { opacity: 0.5; }
552
660
 
553
- /* 行内小按钮:测试 / 删除 / 新增 —— 原来「执行技能」整行是死的,点了没反应 */
554
661
  .mbtn {
555
662
  flex-shrink: 0; padding: 4px 10px; border-radius: var(--r-pill);
556
663
  font-size: 11px; font-family: var(--mono); color: var(--dim);
@@ -562,7 +669,6 @@ async function delMcp(s) {
562
669
  .mbtn.danger:hover { color: var(--red); border-color: rgba(229, 72, 77, 0.35); }
563
670
  .mbtn:disabled { opacity: 0.5; }
564
671
 
565
- /* ── 表单(安装技能 / 接入连接器 / 技能测试)── */
566
672
  .tk-form, .tk-test {
567
673
  margin: 4px 0 6px;
568
674
  padding: 11px 12px;
@@ -595,6 +701,7 @@ async function delMcp(s) {
595
701
  .f textarea { resize: vertical; line-height: 1.6; }
596
702
  .f input:focus, .f select:focus, .f textarea:focus { border-color: var(--line); background: #fff; }
597
703
  .f input::placeholder, .f textarea::placeholder { color: var(--dim); }
704
+ .f input[type='file'] { padding: 4px 6px; font-size: 11.5px; color: var(--dim); }
598
705
 
599
706
  .chk {
600
707
  display: flex; align-items: center; gap: 6px;
@@ -622,7 +729,6 @@ async function delMcp(s) {
622
729
  .tip.ok { color: var(--green); }
623
730
  .tip.bad { color: var(--red); white-space: normal; }
624
731
 
625
- /* 测试结果:成功/失败都原文展示,失败(needs_confirmation/blocked)不涂成成功色 */
626
732
  .tk-res {
627
733
  margin-top: 4px; padding: 8px 10px; border-radius: var(--r-sm);
628
734
  background: rgba(23, 32, 26, 0.03); border: 1px solid var(--line-soft);
@@ -1,7 +1,4 @@
1
- /* 7 个面板共用的时间/数字格式化。集中一份,避免每个组件各写一遍还写得不一样。 */
2
1
 
3
- /* 后端时间戳三种形态都有:秒 float(事件总线)、毫秒 int、ISO 字符串(记忆 created_at)。
4
- 字符串交给 Date 自己解析,数字按量级判断。 */
5
2
  function toDate(ts) {
6
3
  if (!ts) return null
7
4
  if (typeof ts === 'string') {
@@ -41,7 +38,6 @@ export function fmtMs(ms) {
41
38
  return ms >= 1000 ? `${(ms / 1000).toFixed(1)}s` : `${Math.round(ms)}ms`
42
39
  }
43
40
 
44
- /* 截断到 n 个字符(中文按 1 计),用于行内摘要 */
45
41
  export function clip(s, n = 46) {
46
42
  const t = String(s ?? '').replace(/\s+/g, ' ').trim()
47
43
  return t.length > n ? t.slice(0, n) + '…' : t
@@ -0,0 +1,53 @@
1
+ import { reactive } from 'vue'
2
+ import zh from './locales/zh.js'
3
+ import en from './locales/en.js'
4
+
5
+ const DICTS = { zh, en }
6
+ const STORE_KEY = 'foxclawLang'
7
+
8
+ export const LOCALES = [
9
+ { id: 'zh', label: '中文', tag: 'Chinese', htmlLang: 'zh-CN', locale: 'zh-CN' },
10
+ { id: 'en', label: 'English', tag: 'English', htmlLang: 'en', locale: 'en-US' },
11
+ ]
12
+
13
+ const stored = (() => {
14
+ try {
15
+ return localStorage.getItem(STORE_KEY)
16
+ } catch {
17
+ return null
18
+ }
19
+ })()
20
+
21
+ export const i18n = reactive({ locale: DICTS[stored] ? stored : 'zh' })
22
+
23
+ export const currentLocale = () => LOCALES.find((l) => l.id === i18n.locale) || LOCALES[0]
24
+
25
+ /** 数字/日期格式化用的 BCP-47 标签,跟随界面语言 */
26
+ export const numberLocale = () => currentLocale().locale
27
+
28
+ export function applyLangTag() {
29
+ document.documentElement.lang = currentLocale().htmlLang
30
+ }
31
+
32
+ export function setLocale(id) {
33
+ if (!DICTS[id] || id === i18n.locale) return
34
+ i18n.locale = id
35
+ try {
36
+ localStorage.setItem(STORE_KEY, id)
37
+ } catch {
38
+ /* 隐私模式下写不进去,不影响本次会话 */
39
+ }
40
+ applyLangTag()
41
+ }
42
+
43
+ /** 取文案。读 i18n.locale 使其在模板中被 Vue 追踪,切换语言即时生效。 */
44
+ export function t(key, vars) {
45
+ const dict = DICTS[i18n.locale] || DICTS.zh
46
+ let s = dict[key]
47
+ if (s === undefined) s = DICTS.zh[key]
48
+ if (s === undefined) return key
49
+ if (vars) {
50
+ for (const k of Object.keys(vars)) s = s.split(`{${k}}`).join(String(vars[k]))
51
+ }
52
+ return s
53
+ }
@@ -0,0 +1,173 @@
1
+ export default {
2
+ 'nav.overview': 'Overview',
3
+ 'nav.activity': 'Activity',
4
+ 'nav.tasks': 'Scheduled',
5
+ 'nav.agents': 'Agents',
6
+ 'nav.tools': 'Skills · Connectors',
7
+ 'nav.usage': 'Usage',
8
+ 'nav.knowledge': 'Library',
9
+ 'nav.review': 'Review',
10
+ 'nav.memory': 'Memory',
11
+ 'nav.settings': 'Settings',
12
+
13
+ 'group.workspace': 'Workspace',
14
+ 'group.capability': 'Capability',
15
+ 'group.knowledge': 'Knowledge',
16
+ 'group.system': 'System',
17
+
18
+ 'common.refresh': 'Refresh',
19
+ 'common.loading': 'Loading…',
20
+ 'common.offline': 'Backend offline',
21
+ 'common.offlinePanel': 'Backend offline — this panel cannot load data right now',
22
+ 'common.online': 'Online',
23
+ 'common.offlineShort': 'Offline',
24
+ 'common.save': 'Save',
25
+ 'common.notSet': 'Not set',
26
+ 'common.count': '{n}',
27
+
28
+ 'rail.newSession': 'Start a new session',
29
+ 'rail.newSessionBtn': '+ New session',
30
+ 'rail.more': 'More',
31
+ 'menu.title': 'More features',
32
+ 'menu.close': 'Close (Esc)',
33
+ 'rail.otherFeatures': 'Other features',
34
+ 'rail.history': 'Sessions',
35
+ 'rail.empty': 'No sessions yet · send a message to start',
36
+ 'rail.untitled': 'New session',
37
+ 'rail.rename': 'Rename session',
38
+ 'rail.delete': 'Delete session',
39
+ 'rail.sessionTitle': 'Session title',
40
+ 'rail.open': 'Open {label}',
41
+ 'rail.deleteConfirm': 'Delete session "{name}"?\nIts conversation history will be removed permanently.',
42
+
43
+ 'app.expandInspector': 'Expand inspector',
44
+ 'app.inspector': 'Inspect',
45
+
46
+ 'topbar.systemStatus': 'Status',
47
+ 'topbar.newVersion': 'Version {latest} available (current {current}) — open settings',
48
+ 'topbar.planet': 'Open HKC Knowledge Planet',
49
+ 'topbar.planetBtn': '🌐 Planet',
50
+ 'topbar.settings': 'Settings (Ctrl+,)',
51
+
52
+ 'settings.title': 'Settings',
53
+ 'settings.tag': 'Settings',
54
+ 'settings.groupModel': 'Model',
55
+ 'settings.modelProvider': 'Model & provider',
56
+ 'settings.modelProviderSub': 'Takes effect server-side immediately, no restart',
57
+ 'settings.current': 'Active',
58
+ 'settings.unconfigured': 'No key',
59
+ 'settings.providerNote': '“No key” means the backend has no credential for that vendor. Custom model keys and base URLs go in the model capsule left of the composer.',
60
+ 'settings.usage': 'Usage',
61
+ 'settings.usageSub': 'Tokens, calls, balance',
62
+ 'settings.groupChat': 'Chat',
63
+ 'settings.mode': 'Mode',
64
+ 'settings.modeSub': 'Token-by-token streaming / plan first, then execute',
65
+ 'settings.stream': 'Stream',
66
+ 'settings.orchestrate': 'Orchestrate',
67
+ 'settings.nickname': 'Nickname',
68
+ 'settings.nicknameSub': 'How the model addresses you',
69
+ 'settings.nicknamePh': 'e.g. snow',
70
+ 'settings.nicknameNote': 'Stored as a preference and attached to every turn; save empty to clear.',
71
+ 'settings.shortcuts': 'Shortcuts',
72
+ 'settings.shortcutsSub': 'Keys inside the composer',
73
+ 'settings.groupSystem': 'System',
74
+ 'settings.backend': 'Backend',
75
+ 'settings.probing': 'probing…',
76
+ 'settings.ok': 'OK',
77
+ 'settings.retry': 'Retry',
78
+ 'settings.updates': 'Updates',
79
+ 'settings.groupUi': 'Interface',
80
+ 'settings.language': 'Language',
81
+ 'settings.languageSub': 'Switches interface copy instantly',
82
+ 'settings.languageNote': 'Interface only — it does not change the language the model replies in.',
83
+
84
+ 'settings.updNotEnabled': 'Off',
85
+ 'settings.updAvailable': '{v} available',
86
+ 'settings.updLatest': 'Up to date',
87
+ 'settings.updFailed': 'Check failed',
88
+ 'settings.updPending': 'Pending',
89
+ 'settings.updHintOff': 'Off by default · set FOXCLAW_UPDATE_CHECK=1 to enable',
90
+ 'settings.updHintError': 'Check failed (usage unaffected): {msg}',
91
+ 'settings.updHintNew': 'Current v{cur} · latest v{latest}',
92
+ 'settings.updHintOk': 'Current v{cur} · checked every 24h',
93
+ 'settings.buildLocal': 'local build',
94
+ 'settings.buildToday': 'today',
95
+ 'settings.buildDays': '{n} days ago',
96
+
97
+ 'settings.errSaveNick': 'Save failed: {msg}',
98
+ 'settings.errSwitch': 'Switch failed: {msg}',
99
+ 'settings.saidNick': 'I will call you {name} from now on',
100
+ 'settings.saidNickCleared': 'Nickname cleared',
101
+ 'settings.saidSwitched': 'Model switched to {label}',
102
+ 'settings.saidStream': 'Streaming: token by token',
103
+ 'settings.saidOrchestrate': 'Orchestrate: plan first, then execute step by step',
104
+ 'settings.saidLang': 'Interface language set to {name}',
105
+
106
+ 'chat.cmd.new': 'Start a new session',
107
+ 'chat.cmd.stream': 'Switch to streaming chat',
108
+ 'chat.cmd.orchestrate': 'Switch to plan-and-execute',
109
+ 'chat.cmd.search': 'Search memory / knowledge / web: /search <query>',
110
+ 'chat.cmd.ingest': 'Pick files to ingest into the library',
111
+ 'chat.cmd.settings': 'Open settings',
112
+ 'chat.cmd.stop': 'Stop the current generation',
113
+ 'chat.cmd.clear': 'Clear this view only, backend untouched',
114
+ 'chat.cmd.help': 'List all commands',
115
+ 'chat.saidStream': 'Switched to streaming chat',
116
+ 'chat.saidOrchestrate': 'Switched to plan-and-execute',
117
+ 'chat.hintSlash': 'Commands',
118
+ 'chat.hintAt': 'Mention a skill',
119
+ 'chat.tagArg': 'takes an argument',
120
+ 'chat.tagSkill': 'skill',
121
+ 'chat.tagTool': 'tool',
122
+ 'chat.unknownCmd': 'Unknown command: {head}',
123
+ 'chat.ingestFailed': 'failed',
124
+ 'chat.placeholder': 'Tell me what you need… / commands · @ skills · Enter to send',
125
+ 'chat.send': 'Send',
126
+ 'chat.stopGen': 'Stop generating',
127
+
128
+ 'hero.title': 'Ask me anything',
129
+ 'hero.cap': 'The supervisor agent dispatches sub-agents on demand; ask directly if you want it to read your library',
130
+ 'hero.askName': 'What should I call you?',
131
+ 'hero.namePh': 'e.g. snow',
132
+ 'hero.confirm': 'Call me that',
133
+ 'hero.skip': 'Skip',
134
+ 'hero.skipTip': 'You can change this later in settings',
135
+ 'hero.close': 'Close',
136
+ 'hero.resume': 'Resume',
137
+ 'hero.untitled': 'Untitled session',
138
+ 'hero.msgs': '{n} messages',
139
+ 'hero.recentKnowledge': 'Recent knowledge',
140
+ 'hero.saidNick': 'Got it, I will call you {name}',
141
+ 'hero.errSave': 'Save failed: {msg}',
142
+ 'hero.q1': 'What skills are available right now?',
143
+ 'hero.q2': 'Help me prioritise what I need to do today',
144
+ 'hero.q3': 'Describe in one sentence what you can do for me',
145
+
146
+ 'msg.supervisor': 'Supervisor',
147
+ 'msg.generating': 'generating',
148
+ 'msg.reasoning': 'Reasoning',
149
+ 'msg.chars': '{n} chars',
150
+ 'msg.plan': 'Plan',
151
+ 'msg.steps': '{n} steps',
152
+ 'msg.confidence': 'Confidence {n}%',
153
+ 'msg.iterations': '{n} iterations',
154
+ 'msg.evidence': 'Evidence',
155
+ 'msg.items': '{n} items',
156
+ 'msg.tool': 'tool',
157
+ 'msg.copied': 'Copied',
158
+ 'msg.copy': 'Copy',
159
+ 'msg.retry': 'Retry',
160
+ 'msg.srcMemory': 'memory',
161
+ 'msg.srcKnowledge': 'knowledge',
162
+ 'msg.srcWeb': 'web',
163
+ 'msg.srcAgent': 'agent',
164
+ 'msg.srcEvidence': 'evidence',
165
+
166
+ 'key.enter': 'Send',
167
+ 'key.shiftEnter': 'New line',
168
+ 'key.slash': 'Command completion (e.g. /search)',
169
+ 'key.at': 'Skill completion',
170
+ 'key.arrows': 'Pick from the completion list',
171
+ 'key.esc': 'Close completion / overlay',
172
+ 'key.ctrlComma': 'Open settings',
173
+ }
@@ -0,0 +1,174 @@
1
+ export default {
2
+ 'nav.overview': '概览',
3
+ 'nav.activity': '活动',
4
+ 'nav.tasks': '定时任务',
5
+ 'nav.agents': '代理',
6
+ 'nav.tools': '技能·连接器',
7
+ 'nav.usage': '使用情况',
8
+ 'nav.knowledge': '学习库',
9
+ 'nav.review': '复习',
10
+ 'nav.memory': '记忆中心',
11
+ 'nav.settings': '设置',
12
+
13
+ 'group.workspace': '工作台',
14
+ 'group.capability': '能力',
15
+ 'group.knowledge': '知识',
16
+ 'group.system': '系统',
17
+
18
+ 'common.refresh': '刷新',
19
+ 'common.loading': '加载中…',
20
+ 'common.offline': '后端未连接',
21
+ 'common.offlinePanel': '后端未连接,这个面板暂时拉不到数据',
22
+ 'common.online': '在线',
23
+ 'common.offlineShort': '离线',
24
+ 'common.save': '保存',
25
+ 'common.notSet': '未设置',
26
+ 'common.count': '{n} 条',
27
+
28
+ 'rail.newSession': '开一个新会话',
29
+ 'rail.newSessionBtn': '+ 新会话',
30
+ 'rail.more': '更多',
31
+ 'menu.title': '更多功能',
32
+ 'menu.close': '关闭 (Esc)',
33
+ 'rail.otherFeatures': '其它功能',
34
+ 'rail.history': '会话历史',
35
+ 'rail.empty': '还没有会话 · 发一条消息即开始',
36
+ 'rail.untitled': '新会话',
37
+ 'rail.rename': '重命名会话',
38
+ 'rail.delete': '删除会话',
39
+ 'rail.sessionTitle': '会话标题',
40
+ 'rail.open': '打开{label}',
41
+ 'rail.deleteConfirm': '删除会话「{name}」?\n对话历史会一起删掉,不可恢复。',
42
+
43
+ 'app.expandInspector': '展开检视栏',
44
+ 'app.inspector': '检视',
45
+
46
+ 'topbar.systemStatus': '系统状态',
47
+ 'topbar.newVersion': '有新版本 {latest}(当前 {current}),点这里看设置',
48
+ 'topbar.planet': '打开 HKC 知识星球',
49
+ 'topbar.planetBtn': '🌐 知识星球',
50
+ 'topbar.settings': '设置 (Ctrl+,)',
51
+
52
+ 'settings.title': '设置',
53
+ 'settings.tag': 'Settings',
54
+ 'settings.groupModel': '模型',
55
+ 'settings.modelProvider': '模型与供应商',
56
+ 'settings.modelProviderSub': '切换后服务端立即生效,不用重启',
57
+ 'settings.current': '当前',
58
+ 'settings.unconfigured': '未配置',
59
+ 'settings.providerNote': '「未配置」= 后端缺该厂商的 Key。自定义模型的 Key / Base URL 在输入框左侧的模型胶囊里加。',
60
+ 'settings.usage': '使用情况',
61
+ 'settings.usageSub': 'token、调用次数、余额',
62
+ 'settings.groupChat': '对话',
63
+ 'settings.mode': '模式',
64
+ 'settings.modeSub': '逐字流式 / 先出计划再逐步执行',
65
+ 'settings.stream': '流式',
66
+ 'settings.orchestrate': '编排',
67
+ 'settings.nickname': '称呼',
68
+ 'settings.nicknameSub': '模型会这么叫你',
69
+ 'settings.nicknamePh': '例如:snow',
70
+ 'settings.nicknameNote': '存成一条偏好,每轮对话都会带上;留空保存 = 清除。',
71
+ 'settings.shortcuts': '快捷键',
72
+ 'settings.shortcutsSub': '输入框里的键位',
73
+ 'settings.groupSystem': '系统',
74
+ 'settings.backend': '后端连接',
75
+ 'settings.probing': '探测中…',
76
+ 'settings.ok': '正常',
77
+ 'settings.retry': '重试',
78
+ 'settings.reprobe': '再探一次',
79
+ 'settings.updates': '新版本',
80
+ 'settings.groupUi': '界面',
81
+ 'settings.language': '语言',
82
+ 'settings.languageSub': '切换界面文案,立即生效',
83
+ 'settings.languageNote': '只影响界面文字,不影响模型回复的语言。',
84
+
85
+ 'settings.updNotEnabled': '未开启',
86
+ 'settings.updAvailable': '新版本 {v}',
87
+ 'settings.updLatest': '已是最新',
88
+ 'settings.updFailed': '检查失败',
89
+ 'settings.updPending': '待检查',
90
+ 'settings.updHintOff': '默认关闭 · 设 FOXCLAW_UPDATE_CHECK=1 开启',
91
+ 'settings.updHintError': '检查失败(不影响使用):{msg}',
92
+ 'settings.updHintNew': '当前 v{cur} · 最新 v{latest}',
93
+ 'settings.updHintOk': '当前 v{cur} · 24 小时查一次',
94
+ 'settings.buildLocal': '本地构建',
95
+ 'settings.buildToday': '今天',
96
+ 'settings.buildDays': '{n} 天前',
97
+
98
+ 'settings.errSaveNick': '保存失败:{msg}',
99
+ 'settings.errSwitch': '切换失败:{msg}',
100
+ 'settings.saidNick': '以后称呼你为 {name}',
101
+ 'settings.saidNickCleared': '已清除称呼',
102
+ 'settings.saidSwitched': '模型已切到 {label}',
103
+ 'settings.saidStream': '流式:逐字输出',
104
+ 'settings.saidOrchestrate': '编排:先出计划再逐步执行',
105
+ 'settings.saidLang': '界面语言已切换为{name}',
106
+
107
+ 'chat.cmd.new': '开一个新会话',
108
+ 'chat.cmd.stream': '切到流式对话',
109
+ 'chat.cmd.orchestrate': '切到编排任务',
110
+ 'chat.cmd.search': '检索记忆/知识/联网:/搜索 关键词',
111
+ 'chat.cmd.ingest': '选文件摄入知识库',
112
+ 'chat.cmd.settings': '打开设置面板',
113
+ 'chat.cmd.stop': '停止当前生成',
114
+ 'chat.cmd.clear': '只清空当前显示,不动后端',
115
+ 'chat.cmd.help': '列出全部命令',
116
+ 'chat.saidStream': '已切到流式对话',
117
+ 'chat.saidOrchestrate': '已切到编排任务',
118
+ 'chat.hintSlash': '命令',
119
+ 'chat.hintAt': '提及技能',
120
+ 'chat.tagArg': '带参数',
121
+ 'chat.tagSkill': '技能',
122
+ 'chat.tagTool': '工具',
123
+ 'chat.unknownCmd': '未知命令:{head}',
124
+ 'chat.ingestFailed': '失败',
125
+ 'chat.placeholder': '告诉我你想做什么… / 命令 · @ 技能 · Enter 发送',
126
+ 'chat.send': '发送',
127
+ 'chat.stopGen': '停止生成',
128
+
129
+ 'hero.title': '问我任何事',
130
+ 'hero.cap': '主管 Agent 会按需调度子 Agent;想让它读你的知识库,直接问就行',
131
+ 'hero.askName': '我该怎么称呼你?',
132
+ 'hero.namePh': '例如:snow',
133
+ 'hero.confirm': '就这么叫',
134
+ 'hero.skip': '跳过',
135
+ 'hero.skipTip': '以后在设置里也能填',
136
+ 'hero.close': '关闭',
137
+ 'hero.resume': '继续上次',
138
+ 'hero.untitled': '未命名会话',
139
+ 'hero.msgs': '{n} 条消息',
140
+ 'hero.recentKnowledge': '最近知识',
141
+ 'hero.saidNick': '记住了,以后称呼你为 {name}',
142
+ 'hero.errSave': '保存失败:{msg}',
143
+ 'hero.q1': '现在系统里有哪些技能可以用?',
144
+ 'hero.q2': '帮我把今天要做的事排个优先级',
145
+ 'hero.q3': '用一句话说清你能帮我做什么',
146
+
147
+ 'msg.supervisor': '主管 Agent',
148
+ 'msg.generating': '生成中',
149
+ 'msg.reasoning': '推理过程',
150
+ 'msg.chars': '{n} 字',
151
+ 'msg.plan': '执行计划',
152
+ 'msg.steps': '{n} 步',
153
+ 'msg.confidence': '置信度 {n}%',
154
+ 'msg.iterations': '{n} 轮迭代',
155
+ 'msg.evidence': '执行证据',
156
+ 'msg.items': '{n} 项',
157
+ 'msg.tool': '工具',
158
+ 'msg.copied': '已复制',
159
+ 'msg.copy': '复制',
160
+ 'msg.retry': '重试',
161
+ 'msg.srcMemory': '记忆',
162
+ 'msg.srcKnowledge': '知识',
163
+ 'msg.srcWeb': '联网',
164
+ 'msg.srcAgent': '态势',
165
+ 'msg.srcEvidence': '证据',
166
+
167
+ 'key.enter': '发送',
168
+ 'key.shiftEnter': '换行',
169
+ 'key.slash': '命令补全(如 /搜索)',
170
+ 'key.at': '技能补全',
171
+ 'key.arrows': '在补全列表里选',
172
+ 'key.esc': '关闭补全 / 浮层',
173
+ 'key.ctrlComma': '打开设置',
174
+ }