foxclaw 0.1.2 → 0.1.3

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 (344) 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/CHANGELOG.md +57 -0
  6. package/python/CHANGELOG_CN.md +57 -0
  7. package/python/README.md +11 -2
  8. package/python/README_CN.md +32 -20
  9. package/python/bench/bm25_audit.py +1 -14
  10. package/python/bench/bm25_regression.py +0 -1
  11. package/python/bench/bm25_stress.py +0 -4
  12. package/python/bench/cd_audit.py +0 -23
  13. package/python/bench/chaos.py +6 -8
  14. package/python/bench/e2e_real_models.py +0 -1
  15. package/python/bench/llm_retry_test.py +2 -9
  16. package/python/bench/load_test.py +5 -8
  17. package/python/bench/vector_ivf_upgrade.py +1 -7
  18. package/python/docs/RELEASE.md +4 -3
  19. package/python/docs/RUN_CN.md +2 -2
  20. package/python/evals/governance/cases.py +0 -37
  21. package/python/evals/governance/run_evals.py +5 -37
  22. package/python/examples/governance_middleware_demo.py +1 -6
  23. package/python/examples/langgraph_governance_demo.py +7 -11
  24. package/python/foxclaw/__init__.py +34 -152
  25. package/python/foxclaw/agents/base.py +65 -136
  26. package/python/foxclaw/agents/impl/_helpers.py +2 -10
  27. package/python/foxclaw/agents/impl/finance.py +4 -21
  28. package/python/foxclaw/agents/impl/office.py +7 -24
  29. package/python/foxclaw/agents/impl/supervisor.py +12 -79
  30. package/python/foxclaw/agents/mixins/_context.py +0 -23
  31. package/python/foxclaw/agents/mixins/augment.py +10 -16
  32. package/python/foxclaw/agents/mixins/llm.py +7 -6
  33. package/python/foxclaw/agents/mixins/memory.py +7 -1
  34. package/python/foxclaw/agents/mixins/preference.py +58 -8
  35. package/python/foxclaw/agents/mixins/prompt.py +0 -6
  36. package/python/foxclaw/agents/mixins/skillbox.py +6 -6
  37. package/python/foxclaw/agents/mixins/tool_exec.py +16 -42
  38. package/python/foxclaw/api/__init__.py +18 -77
  39. package/python/foxclaw/api/_state.py +43 -0
  40. package/python/foxclaw/api/{app.py → bootstrap.py} +5 -32
  41. package/python/foxclaw/api/middleware.py +5 -28
  42. package/python/foxclaw/api/routes/ahs.py +60 -73
  43. package/python/foxclaw/api/routes/attachments.py +5 -6
  44. package/python/foxclaw/api/routes/browser.py +7 -11
  45. package/python/foxclaw/api/routes/domain.py +18 -26
  46. package/python/foxclaw/api/routes/knowledge.py +3 -21
  47. package/python/foxclaw/api/routes/llm_admin.py +21 -33
  48. package/python/foxclaw/api/routes/memory.py +28 -12
  49. package/python/foxclaw/api/routes/orchestration.py +3 -5
  50. package/python/foxclaw/api/routes/recovery.py +4 -3
  51. package/python/foxclaw/api/routes/review.py +2 -11
  52. package/python/foxclaw/api/routes/search.py +3 -7
  53. package/python/foxclaw/api/routes/system.py +33 -49
  54. package/python/foxclaw/api/routes/task.py +31 -49
  55. package/python/foxclaw/api/routes/ws.py +2 -6
  56. package/python/foxclaw/api/spine.py +1 -4
  57. package/python/foxclaw/browser/action/action_executor.py +1 -5
  58. package/python/foxclaw/browser/action/action_types.py +0 -1
  59. package/python/foxclaw/browser/action/url_policy.py +1 -5
  60. package/python/foxclaw/browser/adapter/web_adapter.py +1 -1
  61. package/python/foxclaw/browser/driver/playwright_driver.py +20 -16
  62. package/python/foxclaw/browser/perception/dom_extractor.py +0 -1
  63. package/python/foxclaw/browser/perception/element_indexer.py +1 -2
  64. package/python/foxclaw/browser/service.py +7 -11
  65. package/python/foxclaw/capability/embedding_service.py +4 -6
  66. package/python/foxclaw/channels/__init__.py +9 -11
  67. package/python/foxclaw/channels/discord.py +4 -13
  68. package/python/foxclaw/channels/dispatcher.py +2 -27
  69. package/python/foxclaw/channels/feishu.py +10 -20
  70. package/python/foxclaw/channels/openclaw_bridge.py +4 -9
  71. package/python/foxclaw/channels/signing.py +9 -9
  72. package/python/foxclaw/channels/telegram.py +3 -4
  73. package/python/foxclaw/channels/weixin.py +7 -17
  74. package/python/foxclaw/cli.py +42 -13
  75. package/python/foxclaw/cognitive/reasoner.py +9 -10
  76. package/python/foxclaw/cognitive/state.py +18 -24
  77. package/python/foxclaw/core/audit_chain.py +1 -3
  78. package/python/foxclaw/core/audit_sink.py +3 -3
  79. package/python/foxclaw/core/compaction.py +8 -26
  80. package/python/foxclaw/core/config.py +2 -2
  81. package/python/foxclaw/core/confirm_nonce.py +6 -12
  82. package/python/foxclaw/core/envfile.py +2 -2
  83. package/python/foxclaw/core/failure_policy.py +17 -26
  84. package/python/foxclaw/core/gateway.py +6 -10
  85. package/python/foxclaw/core/governance_audit.py +3 -7
  86. package/python/foxclaw/core/idempotency.py +15 -22
  87. package/python/foxclaw/core/injection_guard.py +10 -29
  88. package/python/foxclaw/core/memory_adapter.py +30 -57
  89. package/python/foxclaw/core/metrics.py +4 -5
  90. package/python/foxclaw/core/model_router.py +36 -148
  91. package/python/foxclaw/core/paths.py +1 -1
  92. package/python/foxclaw/core/recovery.py +21 -34
  93. package/python/foxclaw/core/scheduler.py +23 -26
  94. package/python/foxclaw/core/secrets.py +0 -3
  95. package/python/foxclaw/core/sessions.py +4 -6
  96. package/python/foxclaw/core/settings.py +16 -32
  97. package/python/foxclaw/core/shared_write.py +11 -23
  98. package/python/foxclaw/core/steering_queue.py +12 -11
  99. package/python/foxclaw/core/system_bus.py +1 -1
  100. package/python/foxclaw/core/thought_chain.py +30 -32
  101. package/python/foxclaw/core/token_meter.py +9 -13
  102. package/python/foxclaw/core/tools.py +4 -12
  103. package/python/foxclaw/core/tracing.py +25 -40
  104. package/python/foxclaw/core/truth_pipeline.py +5 -9
  105. package/python/foxclaw/core/update_check.py +149 -0
  106. package/python/foxclaw/core/vec_recall_adapter.py +11 -37
  107. package/python/foxclaw/core/verify.py +6 -14
  108. package/python/foxclaw/core/web_search.py +4 -28
  109. package/python/foxclaw/finance/evidence.py +14 -18
  110. package/python/foxclaw/finance/fx.py +1 -3
  111. package/python/foxclaw/finance/graph.py +9 -18
  112. package/python/foxclaw/finance/models.py +20 -24
  113. package/python/foxclaw/finance/nlparse.py +12 -72
  114. package/python/foxclaw/finance/policy.py +8 -36
  115. package/python/foxclaw/finance/reasoner.py +3 -11
  116. package/python/foxclaw/finance/reasoning.py +13 -34
  117. package/python/foxclaw/finance/reconcile.py +5 -10
  118. package/python/foxclaw/finance/runtime.py +19 -46
  119. package/python/foxclaw/governance/middleware.py +13 -21
  120. package/python/foxclaw/harness/_base.py +2 -8
  121. package/python/foxclaw/harness/_policy.py +19 -38
  122. package/python/foxclaw/harness/drift.py +1 -13
  123. package/python/foxclaw/harness/event_bus.py +2 -5
  124. package/python/foxclaw/harness/harness.py +9 -97
  125. package/python/foxclaw/harness/loop_detection.py +11 -18
  126. package/python/foxclaw/itinerary/amap_client.py +2 -5
  127. package/python/foxclaw/itinerary/models.py +7 -7
  128. package/python/foxclaw/itinerary/reasoner.py +1 -6
  129. package/python/foxclaw/itinerary/reasoning.py +15 -21
  130. package/python/foxclaw/itinerary/runtime.py +8 -12
  131. package/python/foxclaw/kernel/capabilities.py +5 -6
  132. package/python/foxclaw/kernel/policy_gate.py +4 -10
  133. package/python/foxclaw/kernel/process_manager.py +17 -36
  134. package/python/foxclaw/kernel/scheduler.py +3 -9
  135. package/python/foxclaw/kernel/sentinel.py +13 -23
  136. package/python/foxclaw/kernel/sentinel_client.py +12 -15
  137. package/python/foxclaw/kernel/spine.py +9 -9
  138. package/python/foxclaw/knowledge/__init__.py +4 -20
  139. package/python/foxclaw/knowledge/truth_crystallizer.py +5 -8
  140. package/python/foxclaw/learning/knowledge_graph.py +4 -9
  141. package/python/foxclaw/learning/models.py +13 -13
  142. package/python/foxclaw/learning/reasoner.py +1 -4
  143. package/python/foxclaw/learning/runtime.py +19 -31
  144. package/python/foxclaw/learning/spaced_repetition.py +2 -7
  145. package/python/foxclaw/mcp_server.py +2 -3
  146. package/python/foxclaw/orchestration/__init__.py +16 -33
  147. package/python/foxclaw/pipeline/cognitive_pipeline.py +45 -97
  148. package/python/foxclaw/pipeline/stage_meta.py +21 -0
  149. package/python/foxclaw/pipeline/supervisor_stages.py +13 -42
  150. package/python/foxclaw/planning/llm_planner.py +3 -3
  151. package/python/foxclaw/planning/planner.py +6 -11
  152. package/python/foxclaw/search/agent_port.py +7 -11
  153. package/python/foxclaw/search/evidence.py +0 -4
  154. package/python/foxclaw/search/internal_search.py +3 -5
  155. package/python/foxclaw/search/models.py +11 -13
  156. package/python/foxclaw/search/planner.py +3 -3
  157. package/python/foxclaw/search/retriever.py +1 -1
  158. package/python/foxclaw/search/runtime.py +1 -8
  159. package/python/foxclaw/skills/__init__.py +46 -100
  160. package/python/foxclaw/skills/archive.py +111 -0
  161. package/python/foxclaw/skills/fetch.py +226 -0
  162. package/python/foxclaw/skills/hooks_spec.py +21 -25
  163. package/python/foxclaw/skills/install_cmd.py +216 -0
  164. package/python/foxclaw/skills/lifecycle.py +16 -42
  165. package/python/foxclaw/skills/markdown_skill.py +10 -9
  166. package/python/foxclaw/skills/mcp_client.py +5 -11
  167. package/python/foxclaw/skills/mcp_store.py +0 -3
  168. package/python/foxclaw/skills/permission.py +13 -48
  169. package/python/foxclaw/skills/pipeline.py +21 -53
  170. package/python/foxclaw/skills/policy.py +4 -10
  171. package/python/foxclaw/skills/review.py +3 -3
  172. package/python/frontend/deck/auth.js +0 -7
  173. package/python/frontend/deck/chat_model_picker.js +0 -54
  174. package/python/frontend/deck/domain.js +0 -20
  175. package/python/frontend/deck/main.js +0 -144
  176. package/python/frontend/deck/markdown.js +0 -4
  177. package/python/frontend/deck/settings.js +1 -18
  178. package/python/frontend/deck/state.js +0 -1
  179. package/python/frontend/deck/util.js +0 -2
  180. package/python/frontend/deck/visuals.js +0 -22
  181. package/python/frontend/planet/planet.js +0 -201
  182. package/python/frontend/v3/assets/index-CQSBdxk4.js +34 -0
  183. package/python/frontend/v3/assets/index-D5nIsjms.css +1 -0
  184. package/python/frontend/v3/index.html +3 -3
  185. package/python/frontend/widget_runtime.js +0 -43
  186. package/python/frontend/widgets.js +0 -57
  187. package/python/frontend_src/index.html +1 -1
  188. package/python/frontend_src/package-lock.json +2 -2
  189. package/python/frontend_src/package.json +1 -1
  190. package/python/frontend_src/src/App.vue +3 -7
  191. package/python/frontend_src/src/api.js +0 -7
  192. package/python/frontend_src/src/components/ChatDock.vue +27 -39
  193. package/python/frontend_src/src/components/DocViewer.vue +0 -9
  194. package/python/frontend_src/src/components/Inspector.vue +0 -6
  195. package/python/frontend_src/src/components/LeftRail.vue +60 -39
  196. package/python/frontend_src/src/components/MenuPopover.vue +9 -11
  197. package/python/frontend_src/src/components/MessageStream.vue +18 -30
  198. package/python/frontend_src/src/components/ModelPicker.vue +0 -5
  199. package/python/frontend_src/src/components/QuickIngest.vue +0 -6
  200. package/python/frontend_src/src/components/Stage.vue +71 -25
  201. package/python/frontend_src/src/components/ToolMenu.vue +0 -3
  202. package/python/frontend_src/src/components/TopBar.vue +38 -10
  203. package/python/frontend_src/src/components/panels/ActivityPanel.vue +0 -2
  204. package/python/frontend_src/src/components/panels/AgentsPanel.vue +2 -5
  205. package/python/frontend_src/src/components/panels/KnowledgePanel.vue +0 -16
  206. package/python/frontend_src/src/components/panels/MemoryPanel.vue +0 -1
  207. package/python/frontend_src/src/components/panels/PanelBox.vue +6 -7
  208. package/python/frontend_src/src/components/panels/ReviewPanel.vue +0 -16
  209. package/python/frontend_src/src/components/panels/SettingsPanel.vue +142 -38
  210. package/python/frontend_src/src/components/panels/TasksPanel.vue +0 -1
  211. package/python/frontend_src/src/components/panels/ToolsPanel.vue +125 -19
  212. package/python/frontend_src/src/lib/fmt.js +0 -4
  213. package/python/frontend_src/src/lib/i18n.js +53 -0
  214. package/python/frontend_src/src/lib/locales/en.js +173 -0
  215. package/python/frontend_src/src/lib/locales/zh.js +174 -0
  216. package/python/frontend_src/src/lib/md.js +0 -14
  217. package/python/frontend_src/src/main.js +2 -0
  218. package/python/frontend_src/src/stores/app.js +17 -32
  219. package/python/frontend_src/src/stores/chat.js +0 -34
  220. package/python/frontend_src/src/stores/model.js +0 -8
  221. package/python/frontend_src/src/stores/panels.js +0 -41
  222. package/python/frontend_src/src/stores/profile.js +31 -0
  223. package/python/frontend_src/src/stores/system.js +25 -0
  224. package/python/frontend_src/vite.config.js +0 -7
  225. package/python/pyproject.toml +6 -3
  226. package/python/requirements.txt +311 -0
  227. package/python/tests/conftest.py +0 -22
  228. package/python/tests/run_all.py +3 -66
  229. package/python/tests/test_agent_lifecycle.py +4 -38
  230. package/python/tests/test_ahs_p2.py +4 -25
  231. package/python/tests/test_anthropic_tools.py +1 -15
  232. package/python/tests/test_api.py +19 -9
  233. package/python/tests/test_api_auth.py +1 -5
  234. package/python/tests/test_attachments.py +9 -25
  235. package/python/tests/test_audit_chain.py +2 -7
  236. package/python/tests/test_audit_sink.py +0 -6
  237. package/python/tests/test_browser.py +2 -6
  238. package/python/tests/test_browser_request_guard.py +0 -4
  239. package/python/tests/test_capabilities.py +0 -6
  240. package/python/tests/test_channel_signing.py +2 -9
  241. package/python/tests/test_channels.py +1 -11
  242. package/python/tests/test_config_layering.py +0 -4
  243. package/python/tests/test_confirm_nonce.py +1 -12
  244. package/python/tests/test_context_compaction_wiring.py +1 -7
  245. package/python/tests/test_dispatch.py +0 -6
  246. package/python/tests/test_domain_evals.py +11 -80
  247. package/python/tests/test_domain_import.py +0 -6
  248. package/python/tests/test_domain_reasoners.py +0 -14
  249. package/python/tests/test_e2e.py +0 -17
  250. package/python/tests/test_emb_cache.py +7 -17
  251. package/python/tests/test_embedding_singleton.py +1 -3
  252. package/python/tests/test_evals_smoke.py +0 -24
  253. package/python/tests/test_event_spine.py +10 -18
  254. package/python/tests/test_evidence_semantic.py +1 -14
  255. package/python/tests/test_evidence_sse.py +3 -6
  256. package/python/tests/test_file_ingest.py +0 -11
  257. package/python/tests/test_finance.py +0 -9
  258. package/python/tests/test_finance_ledger.py +5 -12
  259. package/python/tests/test_finance_persist.py +8 -12
  260. package/python/tests/test_gateway.py +3 -22
  261. package/python/tests/test_governance.py +5 -52
  262. package/python/tests/test_governance_audit.py +4 -39
  263. package/python/tests/test_governance_middleware.py +1 -7
  264. package/python/tests/test_hkc.py +6 -24
  265. package/python/tests/test_hkc_index_build_manager.py +0 -33
  266. package/python/tests/test_hkc_manifest_reuse.py +4 -27
  267. package/python/tests/test_hkc_search_event_sync.py +3 -54
  268. package/python/tests/test_import_path_guard.py +0 -6
  269. package/python/tests/test_injection_guard.py +18 -36
  270. package/python/tests/test_integration.py +5 -29
  271. package/python/tests/test_itinerary.py +0 -3
  272. package/python/tests/test_kee_semantic.py +0 -5
  273. package/python/tests/test_kernel.py +1 -11
  274. package/python/tests/test_learning.py +3 -12
  275. package/python/tests/test_llm_admin.py +4 -19
  276. package/python/tests/test_llm_planner.py +1 -23
  277. package/python/tests/test_markdown_skills.py +3 -14
  278. package/python/tests/test_markdown_skills_openclaw.py +4 -9
  279. package/python/tests/test_mcp_connectors.py +3 -15
  280. package/python/tests/test_mcp_guardian_discovery.py +2 -6
  281. package/python/tests/test_mcp_no_memory.py +3 -3
  282. package/python/tests/test_mcp_policy_gate.py +0 -1
  283. package/python/tests/test_mcp_server.py +6 -9
  284. package/python/tests/test_memory_recall.py +1 -4
  285. package/python/tests/test_metrics.py +0 -8
  286. package/python/tests/test_multi_chain.py +1 -13
  287. package/python/tests/test_multimodal.py +5 -18
  288. package/python/tests/test_negotiation.py +3 -13
  289. package/python/tests/test_orchestration.py +1 -11
  290. package/python/tests/test_orchestration_decoupled.py +0 -6
  291. package/python/tests/test_p3_p5_hardening.py +3 -17
  292. package/python/tests/test_parallel_dispatch.py +4 -12
  293. package/python/tests/test_pipeline.py +17 -58
  294. package/python/tests/test_plan_visible.py +4 -4
  295. package/python/tests/test_planner.py +0 -7
  296. package/python/tests/test_policy_gate.py +2 -3
  297. package/python/tests/test_profile.py +67 -0
  298. package/python/tests/test_readme_claims.py +163 -0
  299. package/python/tests/test_reasoner.py +2 -17
  300. package/python/tests/test_release_check.py +2 -13
  301. package/python/tests/test_resume_checkpoint.py +7 -15
  302. package/python/tests/test_routing.py +2 -12
  303. package/python/tests/test_scheduler.py +7 -10
  304. package/python/tests/test_search.py +1 -11
  305. package/python/tests/test_secrets.py +4 -10
  306. package/python/tests/test_semantic.py +1 -10
  307. package/python/tests/test_sessions.py +3 -4
  308. package/python/tests/test_settings.py +2 -18
  309. package/python/tests/test_shadow_learning.py +3 -43
  310. package/python/tests/test_shared_write.py +0 -7
  311. package/python/tests/test_skill_taint_gate.py +1 -10
  312. package/python/tests/test_skills.py +2 -18
  313. package/python/tests/test_skills_fetch.py +282 -0
  314. package/python/tests/test_stats_and_events.py +2 -5
  315. package/python/tests/test_streaming.py +2 -7
  316. package/python/tests/test_supervisor_pipeline.py +4 -5
  317. package/python/tests/test_supervisor_triage.py +4 -10
  318. package/python/tests/test_taint.py +2 -7
  319. package/python/tests/test_task_stream.py +1 -12
  320. package/python/tests/test_thinking_sse.py +0 -1
  321. package/python/tests/test_tool_center.py +1 -17
  322. package/python/tests/test_tool_parallel.py +2 -2
  323. package/python/tests/test_tool_params.py +1 -5
  324. package/python/tests/test_tool_use.py +0 -13
  325. package/python/tests/test_toplevel_concurrency.py +3 -4
  326. package/python/tests/test_tracing.py +7 -41
  327. package/python/tests/test_truth_crystallizer.py +4 -6
  328. package/python/tests/test_truth_flow.py +2 -7
  329. package/python/tests/test_update_check.py +95 -0
  330. package/python/tests/test_verify_evidence.py +8 -21
  331. package/python/tests/test_version_sync.py +35 -6
  332. package/python/tests/test_web_trigger.py +0 -17
  333. package/python/tools/check_faiss_type.py +0 -1
  334. package/python/tools/check_log.ps1 +0 -8
  335. package/python/tools/mypy_baseline.txt +12 -4
  336. package/python/tools/mypy_ratchet.py +52 -6
  337. package/python/tools/pack.py +0 -5
  338. package/python/tools/release_check.py +7 -7
  339. package/python/tools/restart_foxclaw.ps1 +5 -8
  340. package/python/tools/shared_write_audit.py +1 -15
  341. package/python/tools/size_check.py +1 -1
  342. package/python/tools/strip_comments.py +228 -0
  343. package/python/frontend/v3/assets/index-BD7VPbMV.js +0 -33
  344. package/python/frontend/v3/assets/index-CAvnYWGH.css +0 -1
@@ -1,4 +1,3 @@
1
- /* 对话与输入区状态:模式 / 附件 / 图片 / 摄入任务 / 消息流 / SSE */
2
1
  import { reactive } from 'vue'
3
2
  import { API, delJSON, getJSON, getRaw, postForm, postFormRaw, postJSON } from '../api.js'
4
3
  import { loadSessions, state as app } from './app.js'
@@ -14,12 +13,9 @@ export const chat = reactive({
14
13
  ingest: null, // {name,pct,status,ku,msg}
15
14
  toast: '',
16
15
 
17
- /* 对话 */
18
16
  messages: [], // [{role,content,thinking,evidence,error,ts,streaming,stage,plan}]
19
17
  sessionId: null,
20
18
  streamState: 'idle', // idle | streaming | done | error
21
- /* 错误落在具体那条消息的 m.error 上(界面上能看到 + 能点重试),
22
- 这里不再留一个没人读的 lastError */
23
19
  })
24
20
 
25
21
  let toastTimer = 0
@@ -35,7 +31,6 @@ export function setMode(m) {
35
31
  localStorage.setItem(MODE_KEY, m)
36
32
  }
37
33
 
38
- /* ── 附件:POST /api/upload → {id,name,size,mime,url,text} ── */
39
34
  export async function attachFile(file) {
40
35
  if (!file) return
41
36
  if (file.size > MAX_MB * 1048576) return say(`${file.name} 超过 ${MAX_MB}MB`)
@@ -50,7 +45,6 @@ export async function attachFile(file) {
50
45
  }
51
46
  }
52
47
 
53
- /* ── 图片:本地转 dataURL,不落盘 ── */
54
48
  export function attachImage(file) {
55
49
  if (!file) return
56
50
  if (!file.type.startsWith('image/')) return say('不是图片文件')
@@ -67,8 +61,6 @@ export function dropImage(i) {
67
61
  chat.images.splice(i, 1)
68
62
  }
69
63
 
70
- /* ── 摄入知识库:POST /knowledge/ingest/file/async → 轮询 /knowledge/ingest/jobs/{id}
71
- 注意路径无 /api 前缀:vendor/hkc 的 knowledge router 是根路径挂载的。 ── */
72
64
  export async function ingestFile(file, collection = '') {
73
65
  if (!file) return
74
66
  if (chat.ingest) return say('等当前文件摄入完成再传下一个')
@@ -90,7 +82,6 @@ export async function ingestFolder(files) {
90
82
  const list = [...files].filter(Boolean)
91
83
  for (const f of list) {
92
84
  await ingestFile(f)
93
- /* ingestFile 内部已串行守卫:等当前 job 结束再投下一个 */
94
85
  while (chat.ingest && chat.ingest.status !== 'error') {
95
86
  if (chat.ingest.status === 'done') break
96
87
  await new Promise((r) => setTimeout(r, 600))
@@ -123,8 +114,6 @@ async function pollIngest(jobId) {
123
114
  say('摄入超时,后台可能仍在跑')
124
115
  }
125
116
 
126
- /* ══════════ 会话 ══════════ */
127
-
128
117
  const STAGE_CN = {
129
118
  perceive: '感知', recall: '召回', meta_check: '自检', schedule: '排程',
130
119
  route: '路由', plan: '规划', dispatch: '分发', act: '执行',
@@ -150,7 +139,6 @@ function adoptSession(id) {
150
139
  localStorage.setItem(SID_KEY, id)
151
140
  }
152
141
 
153
- /* 启动时恢复上次会话(后端 sessions 落盘,thinking/evidence 不落盘) */
154
142
  export async function bootChat() {
155
143
  const saved = localStorage.getItem(SID_KEY)
156
144
  if (saved) await loadSession(saved, { quiet: true })
@@ -173,14 +161,11 @@ export async function loadSession(id, { quiet = false } = {}) {
173
161
  }
174
162
  }
175
163
 
176
- /* 组件间的一次性信号:斜杠命令要调 ToolMenu 里的文件选择,又不能硬耦合。
177
- (/设置 不再走这里 —— 它现在直接切到设置面板,见 ChatDock 的命令表) */
178
164
  export const ui = reactive({ ingestTick: 0 })
179
165
  export function requestIngest() {
180
166
  ui.ingestTick += 1
181
167
  }
182
168
 
183
- /* 纯本地消息(/帮助 之类),不经过后端 */
184
169
  export function pushLocal(content) {
185
170
  chat.messages.push({
186
171
  role: 'assistant', content, ts: Date.now(),
@@ -188,7 +173,6 @@ export function pushLocal(content) {
188
173
  })
189
174
  }
190
175
 
191
- /* 认知搜索(HSR):POST /api/search/query,结果作为一张证据卡挂在消息流里 */
192
176
  export async function runSearch(rawQuery) {
193
177
  const query = String(rawQuery || '').trim()
194
178
  if (!query) return say('用法:/搜索 关键词')
@@ -205,7 +189,6 @@ export async function runSearch(rawQuery) {
205
189
  const msg = chat.messages[chat.messages.length - 1]
206
190
 
207
191
  try {
208
- /* internal_only=true:只查 HMR 记忆 + HKC 知识 + Agent 态势,不联网 —— 联网分支实测返回空图 */
209
192
  const d = await postJSON('/search/query', { query, agent_id: 'supervisor', internal_only: true })
210
193
  const nodes = (d.graph && d.graph.nodes) || []
211
194
  msg.search = {
@@ -242,7 +225,6 @@ export async function newSession() {
242
225
  }
243
226
  }
244
227
 
245
- /* 改标题:后端 rename 会把空串兜回「新会话」,这里先挡掉空提交,避免误清标题 */
246
228
  export async function renameSession(id, title) {
247
229
  const t = String(title || '').trim().slice(0, 60)
248
230
  if (!id || !t) return
@@ -255,8 +237,6 @@ export async function renameSession(id, title) {
255
237
  }
256
238
  }
257
239
 
258
- /* 删会话。删的是当前会话时落回列表里的下一条;一条不剩就新开一个 ——
259
- 否则界面会停在一个已经不存在的 sessionId 上,下一条消息直接 404。 */
260
240
  export async function deleteSession(id) {
261
241
  if (!id) return
262
242
  try {
@@ -271,7 +251,6 @@ export async function deleteSession(id) {
271
251
  else await newSession()
272
252
  }
273
253
 
274
- /* 重发:把这条回复对应的提问找回来,截断到它之前再投一次(附件/图片一起还原) */
275
254
  export async function retry(msg) {
276
255
  if (chat.streamState === 'streaming') return say('正在生成,先点停止')
277
256
  const i = chat.messages.indexOf(msg)
@@ -301,28 +280,20 @@ async function ensureSession() {
301
280
  adoptSession(saved)
302
281
  return saved
303
282
  } catch {
304
- /* 后端已无此会话 → 落到下面新建 */
305
283
  }
306
284
  }
307
285
  return newSession()
308
286
  }
309
287
 
310
- /* ══════════ 发送 / 流式 ══════════ */
311
-
312
288
  let ctrl = null
313
- /* 每次 send 领一个代号。切会话 / 新建会话时把代号推进,在跑的那一路回来发现
314
- 代号变了就不再碰全局状态 —— 否则它会把新会话的 streamState 覆盖掉、还把 ctrl
315
- 清空,导致新流停不下来,两路 token 同时往不同消息里写。 */
316
289
  let gen = 0
317
290
 
318
- /* 掐断在跑的流:切会话、新建会话、重试前都先调一次 */
319
291
  function cutStream() {
320
292
  gen += 1
321
293
  if (ctrl) {
322
294
  try {
323
295
  ctrl.abort()
324
296
  } catch {
325
- /* 已经收尾了 */
326
297
  }
327
298
  ctrl = null
328
299
  }
@@ -351,7 +322,6 @@ export async function send(rawText) {
351
322
  const attachments = chat.attachments.map((a) => ({
352
323
  name: a.name, size: a.size, mime: a.mime, url: a.url, text: a.text || '',
353
324
  }))
354
- /* 后端只用最近 12 条拼上下文,与旧前端保持一致 */
355
325
  const history = chat.messages
356
326
  .filter((m) => m.content && m.role && !m.error)
357
327
  .slice(-12)
@@ -359,15 +329,12 @@ export async function send(rawText) {
359
329
 
360
330
  chat.messages.push({
361
331
  role: 'user', content: text, ts: Date.now(), attachments, streaming: false, thinking: '',
362
- /* 存一份图片快照:重试时 send() 从 chat.images 取图,不带上就丢图了 */
363
332
  images: chat.images.map((im) => ({ ...im })),
364
333
  })
365
334
  chat.messages.push({
366
335
  role: 'assistant', content: '', thinking: '', evidence: [], error: '', notice: '',
367
336
  ts: Date.now(), streaming: true, stage: '', plan: null,
368
337
  })
369
- /* 必须拿回数组里的响应式代理:直接改 push 进去的原始对象不会触发重渲染,
370
- 表现就是气泡永远停在「···」而内容其实早到了 */
371
338
  const reply = chat.messages[chat.messages.length - 1]
372
339
  chat.attachments = []
373
340
  chat.images = []
@@ -412,7 +379,6 @@ export async function send(rawText) {
412
379
  }
413
380
 
414
381
  function applyEvent(msg, name, ev) {
415
- /* 命名事件与 JSON 键双判据:后端明确要求两者都认 */
416
382
  if (name === 'thinking' || ev.thinking) {
417
383
  msg.thinking += ev.thinking || ''
418
384
  return
@@ -1,4 +1,3 @@
1
- /* 模型选择:全部走 /api/llm/*(llm_admin.py),切换后服务端立即生效,无需重启。 */
2
1
  import { reactive } from 'vue'
3
2
  import { delJSON, getJSON, postJSON, putJSON } from '../api.js'
4
3
 
@@ -28,7 +27,6 @@ export async function loadModels(force = false) {
28
27
  }
29
28
  }
30
29
 
31
- /* 当前 pill 上显示的名字与色点 */
32
30
  export function currentLabel() {
33
31
  const c = model.current
34
32
  if (!c) return { name: 'Auto', color: '#7e93b8', sub: '跟随 .env 默认' }
@@ -49,9 +47,6 @@ export async function selectModel({ source, provider = null, name = null }) {
49
47
  return r
50
48
  }
51
49
 
52
- /* 设置面板里的模型清单:auto / 预设 / 自定义摊平成同一形状。
53
- active 的判定必须和上面的 currentLabel 一致 —— 两处各写一套,切换后 pill 和
54
- 列表就会各说各的(这类"同一状态两套判定"是回归温床)。 */
55
50
  export function modelOptions() {
56
51
  const c = model.current
57
52
  const out = [{
@@ -81,13 +76,10 @@ export async function addCustom(payload) {
81
76
  await loadModels(true)
82
77
  }
83
78
 
84
- /* 连通性测试:后端发一个 "hi" 走真实客户端,失败时 **不抛** 而是返回 {ok:false,error}
85
- —— 那正是要显示给用户看的东西,别当异常吞掉。 */
86
79
  export async function testModel(payload) {
87
80
  return postJSON('/llm/test', payload)
88
81
  }
89
82
 
90
- /* 单个自定义模型详情:api_key 永不出网,只回 has_key(编辑表单里留空即保留原值) */
91
83
  export async function getCustom(name) {
92
84
  return getJSON(`/llm/custom/${encodeURIComponent(name)}`)
93
85
  }
@@ -1,6 +1,3 @@
1
- /* 左栏菜单 8 项的数据层。
2
- 一项一个 loader,内部每个端点单独 .catch —— 某个子系统挂了只让对应区块空着,
3
- 不让整个面板变「后端未连接」。组件只负责渲染,不各自写 fetch。 */
4
1
  import { reactive } from 'vue'
5
2
  import { getJSON, getRaw, delJSON, patchJSON, postJSON } from '../api.js'
6
3
  import { openDoc } from './app.js'
@@ -15,15 +12,10 @@ export const panels = reactive({
15
12
  usage: { state: 'idle', tokens: null, gateway: {}, metrics: null, slow: [] },
16
13
  knowledge: {
17
14
  state: 'idle', stats: {}, index: {}, sources: [], abilities: [],
18
- /* 最近录入的知识单元:右栏只读前 10 条,面板看全量 */
19
15
  recent: [], recentTotal: 0,
20
- /* 录入是同步 LLM 抽取,可能几十秒 —— 状态提到 store 里,
21
- 切到别的面板再回来时不会以为「没提交过」 */
22
16
  ingest: 'idle', ingestMsg: '', ingestErr: '',
23
17
  },
24
18
  memory: { state: 'idle', stats: {}, recent: [], prefs: [] },
25
- /* SM-2 复习:stats 是全局账本,queue 是「今天这一轮要过的卡」。
26
- session 放 store 是因为复习到一半点开文档再回来,不能让进度归零。 */
27
19
  review: {
28
20
  state: 'idle',
29
21
  stats: { cards: 0, learned: 0, fresh: 0, due: 0, avg_mastery: 0, load7: {}, risk: [] },
@@ -36,7 +28,6 @@ export const panels = reactive({
36
28
  })
37
29
 
38
30
  const LOADERS = {
39
- /* 活动 = 事件总线(系统发生了什么) + 请求链路(哪次调用慢) + 思考链健康度 */
40
31
  async activity(p) {
41
32
  const [bus, traces, thought] = await Promise.all([
42
33
  safe(getJSON('/bus/history?limit=40')),
@@ -49,7 +40,6 @@ const LOADERS = {
49
40
  return !!(bus || traces || thought)
50
41
  },
51
42
 
52
- /* 任务 = 调度器记账 + 进程生命周期(后端把每个任务建模成进程) */
53
43
  async tasks(p) {
54
44
  const [sched, proc] = await Promise.all([
55
45
  safe(getJSON('/scheduler/stats')),
@@ -61,7 +51,6 @@ const LOADERS = {
61
51
  return !!(sched || proc)
62
52
  },
63
53
 
64
- /* 代理 = /api/status(全部 Agent 的 harness + 思考链) + 系统信息 */
65
54
  async agents(p) {
66
55
  const [all, info] = await Promise.all([
67
56
  safe(getJSON('/status')),
@@ -72,7 +61,6 @@ const LOADERS = {
72
61
  return !!(all || info)
73
62
  },
74
63
 
75
- /* 技能 = 内置/HTTP/MCP 技能表 + 指令技能(SKILL.md) + 熔断器 */
76
64
  async tools(p) {
77
65
  const [sk, md, br] = await Promise.all([
78
66
  safe(getJSON('/ahs/skills')),
@@ -85,7 +73,6 @@ const LOADERS = {
85
73
  return !!(sk || md || br)
86
74
  },
87
75
 
88
- /* 使用情况 = token 计量 + 网关配额 + 端点延迟(p95 最慢的几条) */
89
76
  async usage(p) {
90
77
  const [tk, gw, mt] = await Promise.all([
91
78
  safe(getJSON('/tokens')),
@@ -102,8 +89,6 @@ const LOADERS = {
102
89
  return !!(tk || gw || mt)
103
90
  },
104
91
 
105
- /* 知识库 = HKC 根路径 /stats 与 /knowledge/sources,加 Foxclaw 侧能力清单
106
- 与最近录入的 KU(右栏和面板共用这一份) */
107
92
  async knowledge(p) {
108
93
  const [st, src, ab, rc] = await Promise.all([
109
94
  safe(getRaw('/stats')),
@@ -120,8 +105,6 @@ const LOADERS = {
120
105
  return !!(st || src || ab || rc)
121
106
  },
122
107
 
123
- /* 复习 = SM-2 账本 + 今日队列。会话进行中只更新账本,不动队列 ——
124
- 否则右栏刷新一次就把当前卡片换掉了。 */
125
108
  async review(p) {
126
109
  const [st, q] = await Promise.all([
127
110
  safe(getJSON('/review/stats')),
@@ -137,7 +120,6 @@ const LOADERS = {
137
120
  return !!(st || q)
138
121
  },
139
122
 
140
- /* 记忆中心 = HMR 统计 + 最近记忆 + 用户偏好 */
141
123
  async memory(p) {
142
124
  const [st, rc, pf] = await Promise.all([
143
125
  safe(getJSON('/memory/stats')),
@@ -154,7 +136,6 @@ const LOADERS = {
154
136
  export async function loadPanel(id, force = false) {
155
137
  const p = panels[id]
156
138
  if (!p || !LOADERS[id]) return
157
- /* 已有数据就不重拉:切换菜单来回点不重复打后端;要新数据显式刷新 */
158
139
  if (!force && p.state !== 'idle' && p.state !== 'error') return
159
140
  p.state = 'loading'
160
141
  let ok = false
@@ -164,18 +145,11 @@ export async function loadPanel(id, force = false) {
164
145
 
165
146
  export const refreshPanel = (id) => loadPanel(id, true)
166
147
 
167
- /* ── 面板内的写操作(都是真实端点,不是本地假删除) ── */
168
-
169
- /* 指令技能启停:PATCH /ahs/md-skills/{id} → 全量重拉一次保证和服务端一致 */
170
148
  export async function toggleMdSkill(id, enabled) {
171
149
  await patchJSON(`/ahs/md-skills/${encodeURIComponent(id)}`, { enabled })
172
150
  await refreshPanel('tools')
173
151
  }
174
152
 
175
- /* 录入一段短知识:POST /knowledge/ingest → KDE 抽取成 KU → KEE 演化。
176
- 同步 LLM 抽取,可能几十秒,所以状态挂在 store 上而不是组件里。
177
- 成功后**静默重拉**:走 refreshPanel 会把 state 置回 loading,整面板闪骨架,
178
- 而这里只想要新数据。 */
179
153
  export async function ingestKnowledge({ text, title = '', domain = '' }) {
180
154
  const p = panels.knowledge
181
155
  const body = (text || '').trim()
@@ -197,8 +171,6 @@ export async function ingestKnowledge({ text, title = '', domain = '' }) {
197
171
  const n = d?.ku_count ?? 0
198
172
  p.ingestMsg = n
199
173
  ? `已抽取 ${n} 条知识单元${counts ? ` · ${counts}` : ''}`
200
- /* 走到这里说明 LLM 调用是成功的(全失败会 502 进 catch),只是这段文字里
201
- 没抽出 Concept/Fact/Claim/Entity。别提示"没配模型"误导用户去改 key。 */
202
174
  : '模型没从这段文字里抽出知识条目 —— 试试写得更具体(谁 / 是什么 / 为什么)'
203
175
  try { await LOADERS.knowledge(p); p.state = 'ok' } catch {}
204
176
  return d
@@ -209,9 +181,6 @@ export async function ingestKnowledge({ text, title = '', domain = '' }) {
209
181
  }
210
182
  }
211
183
 
212
- /* ── SM-2 复习会话 ── */
213
-
214
- /* 开一轮:队列空了就先拉一次。会话状态在 store 里,点开文档再回来不丢进度。 */
215
184
  export async function startReview() {
216
185
  const p = panels.review
217
186
  if (!p.queue.length) await loadPanel('review', true)
@@ -226,9 +195,6 @@ export function revealCard() {
226
195
  panels.review.revealed = true
227
196
  }
228
197
 
229
- /* 评分 → 服务端按 SM-2 算下一次间隔 → 翻到下一张。
230
- 四档对应 SM-2 的 0/3/4/5:0 完全忘记(重置)、3 勉强、4 记住、5 轻松。
231
- 只更新账本不动队列 —— 队列是这一轮的现场。 */
232
198
  export async function gradeCard(grade) {
233
199
  const p = panels.review
234
200
  const card = p.queue[p.index]
@@ -244,13 +210,11 @@ export async function gradeCard(grade) {
244
210
  return d
245
211
  }
246
212
 
247
- /* 删除一条误存的偏好:DELETE /preferences/{id} */
248
213
  export async function dropPreference(id) {
249
214
  await delJSON(`/preferences/${encodeURIComponent(id)}`)
250
215
  await refreshPanel('memory')
251
216
  }
252
217
 
253
- /* 技能 / KU 正文 → 中间舞台。kind 决定皮肤:code 走 CLI 黑底,text 走排版正文 */
254
218
  export async function openMdSkill(id) {
255
219
  const d = await getJSON(`/ahs/md-skills/${encodeURIComponent(id)}`)
256
220
  openDoc({
@@ -264,8 +228,6 @@ export async function openMdSkill(id) {
264
228
  })
265
229
  }
266
230
 
267
- /* extra 里的业务字段逐类型不同(Fact 有 statement、Evidence 有 source、Entity 有 aliases),
268
- 按类型硬编码会漏;这里统一按「有值就列出来」处理,任何 KU 打开都有内容可读。 */
269
231
  const KU_FIELDS = [
270
232
  ['statement', '陈述'],
271
233
  ['definition', '定义'],
@@ -289,8 +251,6 @@ const kuVal = (v) => {
289
251
  return v === 0 || v === '' || v == null ? '' : String(v)
290
252
  }
291
253
 
292
- /* 单个 KU 的正文 → 中间舞台。走 HKC 根路径 /knowledge/ku/{id}
293
- (那条路径带 source_text,列表/图谱的响应为了瘦身把它剔掉了) */
294
254
  export async function openKu(id) {
295
255
  const d = await getRaw(`/knowledge/ku/${encodeURIComponent(id)}`)
296
256
  const extra = d.extra || {}
@@ -298,7 +258,6 @@ export async function openKu(id) {
298
258
  const rows = KU_FIELDS
299
259
  .map(([k, label]) => [label, kuVal(extra[k])])
300
260
  .filter(([, v]) => v)
301
- /* statement 已经在标题下一行重复过一次,正文里不再复读 */
302
261
  const body = rows.filter(([, v]) => v !== d.summary && v !== d.name)
303
262
 
304
263
  const parts = []
@@ -0,0 +1,31 @@
1
+ import { reactive } from 'vue'
2
+ import { getJSON, putJSON } from '../api.js'
3
+
4
+ export const profile = reactive({
5
+ nickname: '',
6
+ loaded: false,
7
+ saving: false,
8
+ })
9
+
10
+ export async function loadProfile(force = false) {
11
+ if (profile.loaded && !force) return profile
12
+ try {
13
+ const d = await getJSON('/profile')
14
+ profile.nickname = d.nickname || ''
15
+ profile.loaded = true
16
+ } catch {
17
+ }
18
+ return profile
19
+ }
20
+
21
+ export async function saveNickname(nick) {
22
+ profile.saving = true
23
+ try {
24
+ const d = await putJSON('/profile', { nickname: nick || '' })
25
+ profile.nickname = d.nickname || ''
26
+ profile.loaded = true
27
+ return profile.nickname
28
+ } finally {
29
+ profile.saving = false
30
+ }
31
+ }
@@ -0,0 +1,25 @@
1
+ import { reactive } from 'vue'
2
+ import { getJSON } from '../api.js'
3
+
4
+ export const system = reactive({
5
+ version: '',
6
+ update: null, // { enabled, current, latest, update_available, checked_at, error }
7
+ loaded: false,
8
+ })
9
+
10
+ let inflight = null
11
+
12
+ export function loadSystemInfo(force = false) {
13
+ if (system.loaded && !force) return Promise.resolve(system)
14
+ if (inflight) return inflight
15
+ inflight = getJSON('/system/info')
16
+ .then((d) => {
17
+ system.version = d.version || ''
18
+ system.update = d.update || null
19
+ system.loaded = true
20
+ return system
21
+ })
22
+ .catch(() => system) // 拿不到就维持旧值:顶栏不显示版本,不显示更新
23
+ .finally(() => { inflight = null })
24
+ return inflight
25
+ }
@@ -3,8 +3,6 @@ import { defineConfig } from 'vite'
3
3
  import vue from '@vitejs/plugin-vue'
4
4
  import { fileURLToPath, URL } from 'node:url'
5
5
 
6
- /* 设置面板底部的版本行照 OpenClaw 写成 git@<sha> · <N 天前>。
7
- 构建时抓一次 git 信息;没有 git(打包机 / 压缩包)就退回 dev,不让构建失败。 */
8
6
  function gitInfo() {
9
7
  try {
10
8
  const sha = execSync('git rev-parse --short HEAD', { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim()
@@ -15,9 +13,6 @@ function gitInfo() {
15
13
  }
16
14
  }
17
15
 
18
- /* 产物直接写进 frontend/v3/,后端 (StaticFiles(directory=frontend, html=True)) 零改动:
19
- /v3/ -> frontend/v3/index.html
20
- base 必须是 '/v3/',否则 assets 会打到站点根。 */
21
16
  export default defineConfig({
22
17
  base: '/v3/',
23
18
  plugins: [vue()],
@@ -34,12 +29,10 @@ export default defineConfig({
34
29
  },
35
30
  server: {
36
31
  port: 5173,
37
- /* dev 时把 API 与 WS 透到本地后端,前端代码里一律用相对路径 /api */
38
32
  proxy: {
39
33
  '/api': { target: 'http://127.0.0.1:8000', changeOrigin: true },
40
34
  '/ws': { target: 'ws://127.0.0.1:8000', ws: true },
41
35
  '/planet': { target: 'http://127.0.0.1:8000', changeOrigin: true },
42
- /* /knowledge/* 无 /api 前缀:HKC 自带 router 由后端根路径挂载 */
43
36
  '/knowledge': { target: 'http://127.0.0.1:8000', changeOrigin: true },
44
37
  },
45
38
  },
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "foxclaw"
7
- version = "0.1.2"
7
+ version = "0.1.3"
8
8
  description = "Foxclaw - a personal agent with memory, built on the HMR memory runtime"
9
9
  requires-python = ">=3.11"
10
10
 
@@ -134,12 +134,12 @@ python_version = "3.11"
134
134
  ignore_missing_imports = true
135
135
  check_untyped_defs = true
136
136
  # 渐进式:mypy 存量错误用棘轮门管理(tools/mypy_ratchet.py + tools/mypy_baseline.txt)。
137
- # 2026-11 实测 673 errors in 90 files,已冻结:CI 中错误数一旦增加即失败,
137
+ # 2026-11 实测 152 errors in 45 files,已冻结:CI 中错误数一旦增加即失败,
138
138
  # 下降后用 `python tools/mypy_ratchet.py --update` 调低基线。只降不升。
139
139
 
140
140
  [tool.pytest.ini_options]
141
141
  testpaths = ["tests"]
142
- # S2 迁移完成:全部 76 个测试文件均已迁移为 pytest(无顶层 import 副作用,可安全收集)。
142
+ # S2 迁移完成:全部测试文件均已迁移为 pytest(无顶层 import 副作用,可安全收集)。
143
143
  # 注意:网关/内置MCP/流式限流等少数测试依赖模块级单例(FOXCLAW_GATEWAY、FOXCLAW_MCP_SERVER、
144
144
  # _STREAM_LIMITER 均在 import 时按 env 固化),单进程 `pytest tests/` 会让这些单例被首个
145
145
  # import 定死、相互污染。故全量执行统一走 tests/run_all.py(每个文件独立子进程
@@ -214,6 +214,7 @@ python_files = [
214
214
  "test_plan_visible.py",
215
215
  "test_planner.py",
216
216
  "test_policy_gate.py",
217
+ "test_profile.py",
217
218
  "test_reasoner.py",
218
219
  "test_release_check.py",
219
220
  "test_resume_checkpoint.py",
@@ -229,6 +230,7 @@ python_files = [
229
230
  "test_secrets.py",
230
231
  "test_skill_taint_gate.py",
231
232
  "test_skills.py",
233
+ "test_skills_fetch.py",
232
234
  "test_stats_and_events.py",
233
235
  "test_streaming.py",
234
236
  "test_supervisor_pipeline.py",
@@ -246,6 +248,7 @@ python_files = [
246
248
  "test_tracing.py",
247
249
  "test_truth_crystallizer.py",
248
250
  "test_truth_flow.py",
251
+ "test_update_check.py",
249
252
  "test_url_policy.py",
250
253
  "test_version_sync.py",
251
254
  "test_web_trigger.py",