foxclaw 0.1.0 → 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 (514) hide show
  1. package/README.md +54 -29
  2. package/bin/foxclaw.cjs +51 -0
  3. package/index.js +4 -10
  4. package/package.json +46 -38
  5. package/python/.dockerignore +35 -0
  6. package/python/.env.example +173 -0
  7. package/python/.gitattributes +46 -0
  8. package/python/.github/workflows/ci.yml +167 -0
  9. package/python/.github/workflows/release.yml +183 -0
  10. package/python/CHANGELOG.md +57 -0
  11. package/python/CHANGELOG_CN.md +57 -0
  12. package/python/Dockerfile +64 -0
  13. package/python/LICENSE +21 -0
  14. package/python/MANIFEST.in +14 -0
  15. package/python/README.md +201 -0
  16. package/python/README_CN.md +336 -0
  17. package/python/bench/bm25_audit.py +186 -0
  18. package/python/bench/bm25_regression.py +177 -0
  19. package/python/bench/bm25_stress.py +155 -0
  20. package/python/bench/cd_audit.py +215 -0
  21. package/python/bench/chaos.py +140 -0
  22. package/python/bench/concurrency.py +103 -0
  23. package/python/bench/e2e_real_models.py +94 -0
  24. package/python/bench/llm_retry_test.py +241 -0
  25. package/python/bench/load_test.py +193 -0
  26. package/python/bench/vector_ivf_upgrade.py +128 -0
  27. package/python/docs/CHANNELS.md +195 -0
  28. package/python/docs/GOVERNANCE.md +164 -0
  29. package/python/docs/RELEASE.md +110 -0
  30. package/python/docs/RUN.md +75 -0
  31. package/python/docs/RUN_CN.md +121 -0
  32. package/python/docs//351/205/215/347/275/256/346/214/207/345/215/227.md +152 -0
  33. package/python/evals/__init__.py +0 -0
  34. package/python/evals/governance/README.md +61 -0
  35. package/python/evals/governance/__init__.py +0 -0
  36. package/python/evals/governance/cases.py +115 -0
  37. package/python/evals/governance/compare_embeddings.py +94 -0
  38. package/python/evals/governance/convergence.svg +11 -0
  39. package/python/evals/governance/report.json +371 -0
  40. package/python/evals/governance/run_evals.py +368 -0
  41. package/python/examples/governance_middleware_demo.py +72 -0
  42. package/python/examples/langgraph_governance_demo.py +104 -0
  43. package/python/examples/sample_itinerary.csv +6 -0
  44. package/python/examples/sample_knowledge.csv +9 -0
  45. package/python/examples/sample_transactions.csv +14 -0
  46. package/python/foxclaw/__init__.py +408 -0
  47. package/python/foxclaw/agents/__init__.py +12 -0
  48. package/python/foxclaw/agents/agents.py +35 -0
  49. package/python/foxclaw/agents/base.py +794 -0
  50. package/python/foxclaw/agents/impl/__init__.py +1 -0
  51. package/python/foxclaw/agents/impl/_helpers.py +70 -0
  52. package/python/foxclaw/agents/impl/finance.py +231 -0
  53. package/python/foxclaw/agents/impl/office.py +350 -0
  54. package/python/foxclaw/agents/impl/supervisor.py +592 -0
  55. package/python/foxclaw/agents/mixins/_context.py +128 -0
  56. package/python/foxclaw/agents/mixins/augment.py +143 -0
  57. package/python/foxclaw/agents/mixins/llm.py +67 -0
  58. package/python/foxclaw/agents/mixins/memory.py +41 -0
  59. package/python/foxclaw/agents/mixins/preference.py +131 -0
  60. package/python/foxclaw/agents/mixins/prompt.py +71 -0
  61. package/python/foxclaw/agents/mixins/skillbox.py +58 -0
  62. package/python/foxclaw/agents/mixins/tool_exec.py +417 -0
  63. package/python/foxclaw/api/__init__.py +224 -0
  64. package/python/foxclaw/api/_state.py +43 -0
  65. package/python/foxclaw/api/bootstrap.py +96 -0
  66. package/python/foxclaw/api/middleware.py +294 -0
  67. package/python/foxclaw/api/routes/ahs.py +404 -0
  68. package/python/foxclaw/api/routes/attachments.py +116 -0
  69. package/python/foxclaw/api/routes/browser.py +35 -0
  70. package/python/foxclaw/api/routes/domain.py +306 -0
  71. package/python/foxclaw/api/routes/knowledge.py +145 -0
  72. package/python/foxclaw/api/routes/llm_admin.py +449 -0
  73. package/python/foxclaw/api/routes/memory.py +105 -0
  74. package/python/foxclaw/api/routes/orchestration.py +39 -0
  75. package/python/foxclaw/api/routes/recovery.py +44 -0
  76. package/python/foxclaw/api/routes/review.py +266 -0
  77. package/python/foxclaw/api/routes/search.py +33 -0
  78. package/python/foxclaw/api/routes/system.py +311 -0
  79. package/python/foxclaw/api/routes/task.py +263 -0
  80. package/python/foxclaw/api/routes/ws.py +64 -0
  81. package/python/foxclaw/api/spine.py +52 -0
  82. package/python/foxclaw/browser/__init__.py +13 -0
  83. package/python/foxclaw/browser/action/__init__.py +1 -0
  84. package/python/foxclaw/browser/action/action_executor.py +50 -0
  85. package/python/foxclaw/browser/action/action_types.py +44 -0
  86. package/python/foxclaw/browser/action/action_verifier.py +68 -0
  87. package/python/foxclaw/browser/action/url_policy.py +143 -0
  88. package/python/foxclaw/browser/adapter/__init__.py +1 -0
  89. package/python/foxclaw/browser/adapter/base_adapter.py +23 -0
  90. package/python/foxclaw/browser/adapter/web_adapter.py +46 -0
  91. package/python/foxclaw/browser/driver/__init__.py +1 -0
  92. package/python/foxclaw/browser/driver/base_driver.py +61 -0
  93. package/python/foxclaw/browser/driver/playwright_driver.py +170 -0
  94. package/python/foxclaw/browser/perception/__init__.py +1 -0
  95. package/python/foxclaw/browser/perception/dom_extractor.py +42 -0
  96. package/python/foxclaw/browser/perception/element_indexer.py +56 -0
  97. package/python/foxclaw/browser/perception/semantic_reducer.py +33 -0
  98. package/python/foxclaw/browser/perception/snapshot.py +29 -0
  99. package/python/foxclaw/browser/service.py +144 -0
  100. package/python/foxclaw/browser/session/__init__.py +1 -0
  101. package/python/foxclaw/browser/session/session_manager.py +57 -0
  102. package/python/foxclaw/capability/__init__.py +12 -0
  103. package/python/foxclaw/capability/embedding_service.py +65 -0
  104. package/python/foxclaw/channels/__init__.py +138 -0
  105. package/python/foxclaw/channels/discord.py +175 -0
  106. package/python/foxclaw/channels/dispatcher.py +179 -0
  107. package/python/foxclaw/channels/feishu.py +215 -0
  108. package/python/foxclaw/channels/openclaw_bridge.py +151 -0
  109. package/python/foxclaw/channels/signing.py +187 -0
  110. package/python/foxclaw/channels/telegram.py +120 -0
  111. package/python/foxclaw/channels/weixin.py +215 -0
  112. package/python/foxclaw/cli.py +183 -0
  113. package/python/foxclaw/cognitive/__init__.py +4 -0
  114. package/python/foxclaw/cognitive/reasoner.py +81 -0
  115. package/python/foxclaw/cognitive/state.py +141 -0
  116. package/python/foxclaw/core/__init__.py +9 -0
  117. package/python/foxclaw/core/audit_chain.py +131 -0
  118. package/python/foxclaw/core/audit_sink.py +100 -0
  119. package/python/foxclaw/core/compaction.py +265 -0
  120. package/python/foxclaw/core/config.py +65 -0
  121. package/python/foxclaw/core/confirm_nonce.py +151 -0
  122. package/python/foxclaw/core/dispatch.py +27 -0
  123. package/python/foxclaw/core/envfile.py +48 -0
  124. package/python/foxclaw/core/failure_policy.py +142 -0
  125. package/python/foxclaw/core/gateway.py +81 -0
  126. package/python/foxclaw/core/governance_audit.py +171 -0
  127. package/python/foxclaw/core/idempotency.py +282 -0
  128. package/python/foxclaw/core/injection_guard.py +202 -0
  129. package/python/foxclaw/core/memory_adapter.py +489 -0
  130. package/python/foxclaw/core/metrics.py +88 -0
  131. package/python/foxclaw/core/model_router.py +985 -0
  132. package/python/foxclaw/core/paths.py +103 -0
  133. package/python/foxclaw/core/recovery.py +349 -0
  134. package/python/foxclaw/core/scheduler.py +141 -0
  135. package/python/foxclaw/core/secrets.py +131 -0
  136. package/python/foxclaw/core/sessions.py +155 -0
  137. package/python/foxclaw/core/settings.py +414 -0
  138. package/python/foxclaw/core/shared_write.py +186 -0
  139. package/python/foxclaw/core/steering_queue.py +154 -0
  140. package/python/foxclaw/core/system_bus.py +84 -0
  141. package/python/foxclaw/core/thought_chain.py +316 -0
  142. package/python/foxclaw/core/token_meter.py +231 -0
  143. package/python/foxclaw/core/tools.py +164 -0
  144. package/python/foxclaw/core/tracing.py +375 -0
  145. package/python/foxclaw/core/truth_pipeline.py +110 -0
  146. package/python/foxclaw/core/update_check.py +149 -0
  147. package/python/foxclaw/core/vec_recall_adapter.py +477 -0
  148. package/python/foxclaw/core/verify.py +173 -0
  149. package/python/foxclaw/core/web_search.py +218 -0
  150. package/python/foxclaw/finance/__init__.py +15 -0
  151. package/python/foxclaw/finance/evidence.py +149 -0
  152. package/python/foxclaw/finance/fx.py +98 -0
  153. package/python/foxclaw/finance/graph.py +179 -0
  154. package/python/foxclaw/finance/models.py +146 -0
  155. package/python/foxclaw/finance/nlparse.py +515 -0
  156. package/python/foxclaw/finance/policy.py +301 -0
  157. package/python/foxclaw/finance/reasoner.py +121 -0
  158. package/python/foxclaw/finance/reasoning.py +319 -0
  159. package/python/foxclaw/finance/reconcile.py +175 -0
  160. package/python/foxclaw/finance/runtime.py +500 -0
  161. package/python/foxclaw/governance/__init__.py +24 -0
  162. package/python/foxclaw/governance/middleware.py +176 -0
  163. package/python/foxclaw/harness/__init__.py +17 -0
  164. package/python/foxclaw/harness/_base.py +66 -0
  165. package/python/foxclaw/harness/_policy.py +340 -0
  166. package/python/foxclaw/harness/drift.py +77 -0
  167. package/python/foxclaw/harness/event_bus.py +28 -0
  168. package/python/foxclaw/harness/harness.py +358 -0
  169. package/python/foxclaw/harness/loop_detection.py +145 -0
  170. package/python/foxclaw/itinerary/__init__.py +10 -0
  171. package/python/foxclaw/itinerary/amap_client.py +114 -0
  172. package/python/foxclaw/itinerary/models.py +80 -0
  173. package/python/foxclaw/itinerary/reasoner.py +96 -0
  174. package/python/foxclaw/itinerary/reasoning.py +168 -0
  175. package/python/foxclaw/itinerary/runtime.py +144 -0
  176. package/python/foxclaw/kernel/__init__.py +13 -0
  177. package/python/foxclaw/kernel/capabilities.py +72 -0
  178. package/python/foxclaw/kernel/policy_gate.py +108 -0
  179. package/python/foxclaw/kernel/process_manager.py +186 -0
  180. package/python/foxclaw/kernel/scheduler.py +125 -0
  181. package/python/foxclaw/kernel/sentinel.py +443 -0
  182. package/python/foxclaw/kernel/sentinel_client.py +243 -0
  183. package/python/foxclaw/kernel/spine.py +97 -0
  184. package/python/foxclaw/knowledge/__init__.py +360 -0
  185. package/python/foxclaw/knowledge/truth_crystallizer.py +89 -0
  186. package/python/foxclaw/learning/__init__.py +12 -0
  187. package/python/foxclaw/learning/knowledge_graph.py +144 -0
  188. package/python/foxclaw/learning/models.py +93 -0
  189. package/python/foxclaw/learning/reasoner.py +67 -0
  190. package/python/foxclaw/learning/runtime.py +351 -0
  191. package/python/foxclaw/learning/spaced_repetition.py +91 -0
  192. package/python/foxclaw/mcp_server.py +188 -0
  193. package/python/foxclaw/orchestration/__init__.py +167 -0
  194. package/python/foxclaw/pipeline/__init__.py +23 -0
  195. package/python/foxclaw/pipeline/cognitive_pipeline.py +429 -0
  196. package/python/foxclaw/pipeline/stage_meta.py +21 -0
  197. package/python/foxclaw/pipeline/supervisor_stages.py +201 -0
  198. package/python/foxclaw/planning/__init__.py +17 -0
  199. package/python/foxclaw/planning/llm_planner.py +232 -0
  200. package/python/foxclaw/planning/planner.py +94 -0
  201. package/python/foxclaw/search/__init__.py +24 -0
  202. package/python/foxclaw/search/agent_port.py +190 -0
  203. package/python/foxclaw/search/evidence.py +109 -0
  204. package/python/foxclaw/search/external_search.py +50 -0
  205. package/python/foxclaw/search/hkc_read_port.py +60 -0
  206. package/python/foxclaw/search/internal_search.py +71 -0
  207. package/python/foxclaw/search/models.py +127 -0
  208. package/python/foxclaw/search/planner.py +44 -0
  209. package/python/foxclaw/search/retriever.py +39 -0
  210. package/python/foxclaw/search/runtime.py +127 -0
  211. package/python/foxclaw/search/strategy.py +44 -0
  212. package/python/foxclaw/skills/__init__.py +559 -0
  213. package/python/foxclaw/skills/archive.py +111 -0
  214. package/python/foxclaw/skills/fetch.py +226 -0
  215. package/python/foxclaw/skills/hooks_spec.py +69 -0
  216. package/python/foxclaw/skills/install_cmd.py +216 -0
  217. package/python/foxclaw/skills/lifecycle.py +252 -0
  218. package/python/foxclaw/skills/markdown_skill.py +175 -0
  219. package/python/foxclaw/skills/markdown_store.py +39 -0
  220. package/python/foxclaw/skills/mcp_client.py +184 -0
  221. package/python/foxclaw/skills/mcp_store.py +40 -0
  222. package/python/foxclaw/skills/permission.py +145 -0
  223. package/python/foxclaw/skills/pipeline.py +354 -0
  224. package/python/foxclaw/skills/policy.py +74 -0
  225. package/python/foxclaw/skills/review.py +72 -0
  226. package/python/foxclaw/skills/store.py +57 -0
  227. package/python/frontend/assets/core_bg.jpg +0 -0
  228. package/python/frontend/deck/auth.js +25 -0
  229. package/python/frontend/deck/chat_model_picker.js +483 -0
  230. package/python/frontend/deck/domain.js +276 -0
  231. package/python/frontend/deck/main.js +1806 -0
  232. package/python/frontend/deck/markdown.js +44 -0
  233. package/python/frontend/deck/settings.js +307 -0
  234. package/python/frontend/deck/state.js +5 -0
  235. package/python/frontend/deck/util.js +4 -0
  236. package/python/frontend/deck/visuals.js +190 -0
  237. package/python/frontend/deck.css +855 -0
  238. package/python/frontend/deck.html +686 -0
  239. package/python/frontend/deck_v2.html +341 -0
  240. package/python/frontend/planet/index.html +266 -0
  241. package/python/frontend/planet/planet.css +579 -0
  242. package/python/frontend/planet/planet.js +1436 -0
  243. package/python/frontend/planet/vendor/three.core.min.js +6 -0
  244. package/python/frontend/planet/vendor/three.module.min.js +6 -0
  245. package/python/frontend/v3/assets/index-CQSBdxk4.js +34 -0
  246. package/python/frontend/v3/assets/index-D5nIsjms.css +1 -0
  247. package/python/frontend/v3/index.html +15 -0
  248. package/python/frontend/widget_runtime.js +252 -0
  249. package/python/frontend/widgets.js +639 -0
  250. package/python/frontend_src/index.html +14 -0
  251. package/python/frontend_src/package-lock.json +1376 -0
  252. package/python/frontend_src/package.json +19 -0
  253. package/python/frontend_src/src/App.vue +58 -0
  254. package/python/frontend_src/src/api.js +82 -0
  255. package/python/frontend_src/src/components/ChatDock.vue +365 -0
  256. package/python/frontend_src/src/components/ComposerMenu.vue +75 -0
  257. package/python/frontend_src/src/components/DocViewer.vue +162 -0
  258. package/python/frontend_src/src/components/Inspector.vue +235 -0
  259. package/python/frontend_src/src/components/LeftRail.vue +415 -0
  260. package/python/frontend_src/src/components/MenuPopover.vue +128 -0
  261. package/python/frontend_src/src/components/MessageStream.vue +389 -0
  262. package/python/frontend_src/src/components/ModelPicker.vue +350 -0
  263. package/python/frontend_src/src/components/QuickIngest.vue +112 -0
  264. package/python/frontend_src/src/components/Stage.vue +272 -0
  265. package/python/frontend_src/src/components/ToolMenu.vue +141 -0
  266. package/python/frontend_src/src/components/TopBar.vue +118 -0
  267. package/python/frontend_src/src/components/panels/ActivityPanel.vue +82 -0
  268. package/python/frontend_src/src/components/panels/AgentsPanel.vue +83 -0
  269. package/python/frontend_src/src/components/panels/KnowledgePanel.vue +425 -0
  270. package/python/frontend_src/src/components/panels/MemoryPanel.vue +117 -0
  271. package/python/frontend_src/src/components/panels/PanelBox.vue +50 -0
  272. package/python/frontend_src/src/components/panels/ReviewPanel.vue +292 -0
  273. package/python/frontend_src/src/components/panels/SettingsPanel.vue +358 -0
  274. package/python/frontend_src/src/components/panels/TasksPanel.vue +73 -0
  275. package/python/frontend_src/src/components/panels/ToolsPanel.vue +746 -0
  276. package/python/frontend_src/src/components/panels/UsagePanel.vue +105 -0
  277. package/python/frontend_src/src/lib/fmt.js +44 -0
  278. package/python/frontend_src/src/lib/i18n.js +53 -0
  279. package/python/frontend_src/src/lib/locales/en.js +173 -0
  280. package/python/frontend_src/src/lib/locales/zh.js +174 -0
  281. package/python/frontend_src/src/lib/md.js +190 -0
  282. package/python/frontend_src/src/main.js +9 -0
  283. package/python/frontend_src/src/stores/app.js +91 -0
  284. package/python/frontend_src/src/stores/chat.js +450 -0
  285. package/python/frontend_src/src/stores/model.js +96 -0
  286. package/python/frontend_src/src/stores/panels.js +289 -0
  287. package/python/frontend_src/src/stores/profile.js +31 -0
  288. package/python/frontend_src/src/stores/system.js +25 -0
  289. package/python/frontend_src/src/styles/base.css +138 -0
  290. package/python/frontend_src/src/styles/panel.css +117 -0
  291. package/python/frontend_src/src/styles/tokens.css +78 -0
  292. package/python/frontend_src/vite.config.js +39 -0
  293. package/python/pyproject.toml +268 -0
  294. package/python/requirements.txt +311 -0
  295. package/python/skills/README.md +123 -0
  296. package/python/skills/execution-contract/SKILL.md +30 -0
  297. package/python/skills/general-assistant/SKILL.md +34 -0
  298. package/python/skills/planner/SKILL.md +33 -0
  299. package/python/skills/schedule-itinerary/SKILL.md +35 -0
  300. package/python/skills/skill-composition/SKILL.md +31 -0
  301. package/python/skills/skill-guard/SKILL.md +67 -0
  302. package/python/skills/skill-memory/SKILL.md +50 -0
  303. package/python/skills/skill-router/SKILL.md +35 -0
  304. package/python/tests/conftest.py +54 -0
  305. package/python/tests/run_all.py +200 -0
  306. package/python/tests/test_agent_lifecycle.py +326 -0
  307. package/python/tests/test_ahs_p2.py +393 -0
  308. package/python/tests/test_anthropic_tools.py +192 -0
  309. package/python/tests/test_api.py +97 -0
  310. package/python/tests/test_api_auth.py +79 -0
  311. package/python/tests/test_api_host_guard.py +69 -0
  312. package/python/tests/test_attachments.py +151 -0
  313. package/python/tests/test_audit_chain.py +116 -0
  314. package/python/tests/test_audit_sink.py +130 -0
  315. package/python/tests/test_browser.py +149 -0
  316. package/python/tests/test_browser_request_guard.py +180 -0
  317. package/python/tests/test_capabilities.py +152 -0
  318. package/python/tests/test_channel_signing.py +185 -0
  319. package/python/tests/test_channel_trust.py +109 -0
  320. package/python/tests/test_channels.py +174 -0
  321. package/python/tests/test_cli.py +46 -0
  322. package/python/tests/test_compaction_toolpair.py +119 -0
  323. package/python/tests/test_config_layering.py +61 -0
  324. package/python/tests/test_confirm_nonce.py +186 -0
  325. package/python/tests/test_context_compaction_wiring.py +124 -0
  326. package/python/tests/test_dispatch.py +89 -0
  327. package/python/tests/test_domain_evals.py +334 -0
  328. package/python/tests/test_domain_import.py +72 -0
  329. package/python/tests/test_domain_reasoners.py +134 -0
  330. package/python/tests/test_e2e.py +161 -0
  331. package/python/tests/test_emb_cache.py +97 -0
  332. package/python/tests/test_embedding_singleton.py +87 -0
  333. package/python/tests/test_envfile.py +83 -0
  334. package/python/tests/test_evals_smoke.py +90 -0
  335. package/python/tests/test_event_spine.py +174 -0
  336. package/python/tests/test_evidence_semantic.py +88 -0
  337. package/python/tests/test_evidence_sse.py +94 -0
  338. package/python/tests/test_file_ingest.py +135 -0
  339. package/python/tests/test_finance.py +144 -0
  340. package/python/tests/test_finance_ledger.py +245 -0
  341. package/python/tests/test_finance_persist.py +174 -0
  342. package/python/tests/test_gateway.py +125 -0
  343. package/python/tests/test_governance.py +421 -0
  344. package/python/tests/test_governance_audit.py +324 -0
  345. package/python/tests/test_governance_middleware.py +137 -0
  346. package/python/tests/test_hkc.py +268 -0
  347. package/python/tests/test_hkc_index_build_manager.py +306 -0
  348. package/python/tests/test_hkc_manifest_reuse.py +294 -0
  349. package/python/tests/test_hkc_search_event_sync.py +482 -0
  350. package/python/tests/test_import_path_guard.py +155 -0
  351. package/python/tests/test_injection_guard.py +193 -0
  352. package/python/tests/test_integration.py +117 -0
  353. package/python/tests/test_itinerary.py +100 -0
  354. package/python/tests/test_kee_semantic.py +84 -0
  355. package/python/tests/test_kernel.py +212 -0
  356. package/python/tests/test_learning.py +101 -0
  357. package/python/tests/test_llm_admin.py +145 -0
  358. package/python/tests/test_llm_planner.py +344 -0
  359. package/python/tests/test_markdown_skills.py +62 -0
  360. package/python/tests/test_markdown_skills_openclaw.py +66 -0
  361. package/python/tests/test_mcp_connectors.py +97 -0
  362. package/python/tests/test_mcp_guardian_discovery.py +87 -0
  363. package/python/tests/test_mcp_no_memory.py +43 -0
  364. package/python/tests/test_mcp_policy_gate.py +76 -0
  365. package/python/tests/test_mcp_server.py +92 -0
  366. package/python/tests/test_memory_recall.py +92 -0
  367. package/python/tests/test_metrics.py +58 -0
  368. package/python/tests/test_multi_chain.py +90 -0
  369. package/python/tests/test_multimodal.py +122 -0
  370. package/python/tests/test_negotiation.py +136 -0
  371. package/python/tests/test_orchestration.py +109 -0
  372. package/python/tests/test_orchestration_decoupled.py +103 -0
  373. package/python/tests/test_p3_p5_hardening.py +324 -0
  374. package/python/tests/test_parallel_dispatch.py +207 -0
  375. package/python/tests/test_pipeline.py +492 -0
  376. package/python/tests/test_plan_visible.py +86 -0
  377. package/python/tests/test_planner.py +88 -0
  378. package/python/tests/test_policy_gate.py +108 -0
  379. package/python/tests/test_profile.py +67 -0
  380. package/python/tests/test_readme_claims.py +163 -0
  381. package/python/tests/test_reasoner.py +170 -0
  382. package/python/tests/test_release_check.py +252 -0
  383. package/python/tests/test_resume_checkpoint.py +148 -0
  384. package/python/tests/test_routing.py +85 -0
  385. package/python/tests/test_scheduler.py +138 -0
  386. package/python/tests/test_search.py +194 -0
  387. package/python/tests/test_secrets.py +153 -0
  388. package/python/tests/test_semantic.py +69 -0
  389. package/python/tests/test_sessions.py +90 -0
  390. package/python/tests/test_settings.py +265 -0
  391. package/python/tests/test_shadow_learning.py +290 -0
  392. package/python/tests/test_shared_write.py +200 -0
  393. package/python/tests/test_skill_taint_gate.py +145 -0
  394. package/python/tests/test_skills.py +117 -0
  395. package/python/tests/test_skills_fetch.py +282 -0
  396. package/python/tests/test_stats_and_events.py +162 -0
  397. package/python/tests/test_streaming.py +55 -0
  398. package/python/tests/test_supervisor_pipeline.py +176 -0
  399. package/python/tests/test_supervisor_triage.py +102 -0
  400. package/python/tests/test_taint.py +112 -0
  401. package/python/tests/test_task_stream.py +74 -0
  402. package/python/tests/test_thinking_sse.py +66 -0
  403. package/python/tests/test_thinking_stream.py +76 -0
  404. package/python/tests/test_tool_center.py +113 -0
  405. package/python/tests/test_tool_parallel.py +113 -0
  406. package/python/tests/test_tool_params.py +99 -0
  407. package/python/tests/test_tool_use.py +229 -0
  408. package/python/tests/test_toplevel_concurrency.py +116 -0
  409. package/python/tests/test_tracing.py +256 -0
  410. package/python/tests/test_truth_crystallizer.py +125 -0
  411. package/python/tests/test_truth_flow.py +88 -0
  412. package/python/tests/test_update_check.py +95 -0
  413. package/python/tests/test_url_policy.py +53 -0
  414. package/python/tests/test_verify_evidence.py +212 -0
  415. package/python/tests/test_version_sync.py +100 -0
  416. package/python/tests/test_web_trigger.py +82 -0
  417. package/python/tools/check_faiss_type.py +30 -0
  418. package/python/tools/check_log.ps1 +38 -0
  419. package/python/tools/ivf_status.py +72 -0
  420. package/python/tools/mypy_baseline.txt +13 -0
  421. package/python/tools/mypy_ratchet.py +143 -0
  422. package/python/tools/pack.py +173 -0
  423. package/python/tools/release_check.py +349 -0
  424. package/python/tools/restart_foxclaw.ps1 +71 -0
  425. package/python/tools/shared_write_audit.py +190 -0
  426. package/python/tools/size_baseline.txt +28 -0
  427. package/python/tools/size_check.py +102 -0
  428. package/python/tools/strip_comments.py +228 -0
  429. package/python/tools/verify_env.bat +2 -0
  430. package/python/tools/verify_env.py +25 -0
  431. package/python/vendor/HMR_LICENSE +37 -0
  432. package/python/vendor/HMR_README.md +65 -0
  433. package/python/vendor/hkc/LICENSE +37 -0
  434. package/python/vendor/hkc/hkc_ace/__init__.py +0 -0
  435. package/python/vendor/hkc/hkc_ace/ace.py +457 -0
  436. package/python/vendor/hkc/hkc_ace/skill_taxonomy.json +465 -0
  437. package/python/vendor/hkc/hkc_api/__init__.py +0 -0
  438. package/python/vendor/hkc/hkc_api/container.py +416 -0
  439. package/python/vendor/hkc/hkc_api/ingest_jobs.py +103 -0
  440. package/python/vendor/hkc/hkc_api/main.py +157 -0
  441. package/python/vendor/hkc/hkc_api/routes/__init__.py +0 -0
  442. package/python/vendor/hkc/hkc_api/routes/ability.py +151 -0
  443. package/python/vendor/hkc/hkc_api/routes/config.py +51 -0
  444. package/python/vendor/hkc/hkc_api/routes/knowledge.py +630 -0
  445. package/python/vendor/hkc/hkc_api/routes/search.py +88 -0
  446. package/python/vendor/hkc/hkc_api/schemas.py +153 -0
  447. package/python/vendor/hkc/hkc_api/synthesis.py +179 -0
  448. package/python/vendor/hkc/hkc_core/__init__.py +0 -0
  449. package/python/vendor/hkc/hkc_core/graph/__init__.py +0 -0
  450. package/python/vendor/hkc/hkc_core/graph/base.py +188 -0
  451. package/python/vendor/hkc/hkc_core/graph/sqlite_store.py +789 -0
  452. package/python/vendor/hkc/hkc_core/models/__init__.py +0 -0
  453. package/python/vendor/hkc/hkc_core/models/enums.py +65 -0
  454. package/python/vendor/hkc/hkc_core/models/ku.py +307 -0
  455. package/python/vendor/hkc/hkc_core/utils/__init__.py +0 -0
  456. package/python/vendor/hkc/hkc_core/utils/id_gen.py +113 -0
  457. package/python/vendor/hkc/hkc_crystallizer/__init__.py +44 -0
  458. package/python/vendor/hkc/hkc_crystallizer/adapters.py +94 -0
  459. package/python/vendor/hkc/hkc_crystallizer/candidate.py +145 -0
  460. package/python/vendor/hkc/hkc_crystallizer/crystallizer.py +179 -0
  461. package/python/vendor/hkc/hkc_crystallizer/ingress.py +90 -0
  462. package/python/vendor/hkc/hkc_kde/__init__.py +0 -0
  463. package/python/vendor/hkc/hkc_kde/chunker.py +197 -0
  464. package/python/vendor/hkc/hkc_kde/extractor.py +623 -0
  465. package/python/vendor/hkc/hkc_kde/kde.py +298 -0
  466. package/python/vendor/hkc/hkc_kde/loaders/__init__.py +0 -0
  467. package/python/vendor/hkc/hkc_kde/loaders/ebook_loader.py +153 -0
  468. package/python/vendor/hkc/hkc_kde/loaders/office_loader.py +194 -0
  469. package/python/vendor/hkc/hkc_kde/loaders/pdf_loader.py +162 -0
  470. package/python/vendor/hkc/hkc_kde/loaders/text_loader.py +157 -0
  471. package/python/vendor/hkc/hkc_kde/loaders/web_loader.py +91 -0
  472. package/python/vendor/hkc/hkc_kde/models.py +74 -0
  473. package/python/vendor/hkc/hkc_kde/packager.py +329 -0
  474. package/python/vendor/hkc/hkc_kde/relation_disc.py +151 -0
  475. package/python/vendor/hkc/hkc_kee/__init__.py +0 -0
  476. package/python/vendor/hkc/hkc_kee/dedup.py +227 -0
  477. package/python/vendor/hkc/hkc_kee/fingerprint.py +106 -0
  478. package/python/vendor/hkc/hkc_kee/kee.py +541 -0
  479. package/python/vendor/hkc/hkc_kep/__init__.py +0 -0
  480. package/python/vendor/hkc/hkc_kep/event_bus.py +205 -0
  481. package/python/vendor/hkc/hkc_sdk/__init__.py +63 -0
  482. package/python/vendor/hkc/hkc_sdk/base.py +151 -0
  483. package/python/vendor/hkc/hkc_sdk/direct_client.py +153 -0
  484. package/python/vendor/hkc/hkc_sdk/exceptions.py +39 -0
  485. package/python/vendor/hkc/hkc_sdk/http_client.py +166 -0
  486. package/python/vendor/hkc/hkc_sdk/models.py +171 -0
  487. package/python/vendor/hkc/hkc_search/__init__.py +0 -0
  488. package/python/vendor/hkc/hkc_search/bm25.py +325 -0
  489. package/python/vendor/hkc/hkc_search/embedding_backends.py +374 -0
  490. package/python/vendor/hkc/hkc_search/graph_search.py +132 -0
  491. package/python/vendor/hkc/hkc_search/hybrid.py +331 -0
  492. package/python/vendor/hkc/hkc_search/index_build_manager.py +378 -0
  493. package/python/vendor/hkc/hkc_search/vector_search.py +484 -0
  494. package/python/vendor/hmr/__init__.py +0 -0
  495. package/python/vendor/hmr/core/__init__.py +0 -0
  496. package/python/vendor/hmr/core/hmr.py +684 -0
  497. package/python/vendor/hmr/core/models.py +310 -0
  498. package/python/vendor/hmr/engines/__init__.py +0 -0
  499. package/python/vendor/hmr/engines/evolution.py +710 -0
  500. package/python/vendor/hmr/engines/jit_compiler.py +472 -0
  501. package/python/vendor/hmr/engines/lifecycle.py +264 -0
  502. package/python/vendor/hmr/engines/policy.py +625 -0
  503. package/python/vendor/hmr/engines/recall.py +260 -0
  504. package/python/vendor/hmr/engines/runtime_state.py +158 -0
  505. package/python/vendor/hmr/engines/scheduler.py +323 -0
  506. package/python/vendor/hmr/engines/semantic.py +150 -0
  507. package/python/vendor/hmr/engines/temporal.py +261 -0
  508. package/python/vendor/hmr/engines/thought_chain.py +635 -0
  509. package/python/vendor/hmr/graph/__init__.py +0 -0
  510. package/python/vendor/hmr/graph/cwg.py +338 -0
  511. package/python/vendor/hmr/graph/memory_graph.py +530 -0
  512. package/python/vendor/hmr/storage/__init__.py +0 -0
  513. package/python/vendor/hmr/storage/memory_fs.py +300 -0
  514. package/python/vendor/hmr/storage/vector_store.py +520 -0
@@ -0,0 +1,276 @@
1
+ import { escapeHtml } from './util.js?v=2.9';
2
+ import { API, _lastKernelData } from './state.js';
3
+
4
+ let AMAP_JS_KEY = ""; // 运行时从后端注入,勿硬编码
5
+ let AMAP_JS_SCODE = ""; // 运行时从后端注入,勿硬编码
6
+ export async function fetchAMapConfig(){
7
+ try{
8
+ const c=await(await fetch(`${API}/config/amap`)).json();
9
+ AMAP_JS_KEY=c.js_key||""; AMAP_JS_SCODE=c.js_scode||"";
10
+ }catch(e){}
11
+ }
12
+ let _amapLoaded=false, _amapLoading=false, _amapMap=null;
13
+ export function loadAMap(){
14
+ return new Promise((resolve,reject)=>{
15
+ if(_amapLoaded)return resolve(window.AMap);
16
+ if(!AMAP_JS_KEY)return reject('no-key');
17
+ if(_amapLoading){const t=setInterval(()=>{if(_amapLoaded){clearInterval(t);resolve(window.AMap);}},200);return;}
18
+ _amapLoading=true;
19
+ if(AMAP_JS_SCODE){ window._AMapSecurityConfig={securityJsCode:AMAP_JS_SCODE}; }
20
+ const s=document.createElement('script');
21
+ s.src=`https://webapi.amap.com/maps?v=2.0&key=${AMAP_JS_KEY}`;
22
+ s.onload=()=>{_amapLoaded=true;resolve(window.AMap);};
23
+ s.onerror=()=>reject('load-fail');
24
+ document.head.appendChild(s);
25
+ });
26
+ }
27
+
28
+ export function kpSet(title,tag,html){
29
+ const t=document.getElementById('kpTitle'); if(t)t.textContent=title;
30
+ const g=document.getElementById('kpTag'); if(g)g.textContent=tag;
31
+ const b=document.getElementById('kpBody'); if(b)b.innerHTML=html;
32
+ }
33
+
34
+ export function renderFinance(d){
35
+ let h='<div class="kp-add" onclick="openEntry(\'finance\')">+ 录入交易</div>'
36
+ +'<div class="kp-add" onclick="importDomainFile(\'finance\')">📁 导入文件</div>';
37
+ const bs=d.budget_status||[];
38
+ if(bs.length){h+='<div class="kp-sec"><div class="h">预算状态</div>';
39
+ bs.forEach(b=>{const pct=Math.min(b.usage_ratio*100,120);
40
+ const col=b.is_over?'var(--amber)':'var(--green)';
41
+ h+=`<div class="kp-bud"><div class="top"><b>${escapeHtml(b.category)}</b><span class="${b.is_over?'over':''}">${b.spent.toFixed(0)}/${b.monthly_limit.toFixed(0)}</span></div>
42
+ <div class="bar"><i style="width:${pct}%;background:${col}"></i></div></div>`;});
43
+ h+='</div>';}
44
+ const an=d.anomalies||[];
45
+ if(an.length){h+='<div class="kp-sec"><div class="h">异常消费</div>';
46
+ an.forEach(a=>{h+=`<div class="kp-chip"><span class="ico">⚠</span><div class="tx"><b>${escapeHtml(a.entity)} ${escapeHtml(a.amount)}</b><span>${escapeHtml(a.reason)}</span></div></div>`;});
47
+ h+='</div>';}
48
+ const sc=d.subscription_creep||{};
49
+ if(sc.subscription_count){h+=`<div class="kp-sec"><div class="h">订阅</div><div class="kp-metric"><span class="lab">订阅数量</span><span class="val">${sc.subscription_count}</span></div><div class="kp-metric"><span class="lab">月度总额</span><span class="val">${sc.monthly_total}</span></div></div>`;}
50
+ const gv=d.gatekeeper_verdicts||[];
51
+ if(gv.length){h+='<div class="kp-sec"><div class="h">守门人裁决</div>';
52
+ gv.forEach(v=>{const cls=v.severity==='critical'?'crit':v.severity==='warn'?'warn':'info';
53
+ h+=`<div class="kp-chip ${cls}"><span class="ico">⬢</span><div class="tx"><b>${v.action}</b><span>${v.message}</span></div></div>`;});
54
+ h+='</div>';}
55
+ return h||'<div class="kp-empty">暂无财务数据 · 先导入交易</div>';
56
+ }
57
+
58
+ export function renderLearning(d){
59
+ let h='<div class="kp-add" onclick="openEntry(\'office\')">+ 写入知识点</div>'
60
+ +'<div class="kp-add" onclick="document.getElementById(\'cmdAttach\')?.click()">📄 导入文件</div>'
61
+ +'<div class="kp-add" onclick="document.getElementById(\'cmdFolder\')?.click()">📁 导入文件夹</div>';
62
+ h+='<div class="kp-tiprow">导入的文档去哪了?<span class="infotip" tabindex="0">i<span class="infotip-pop">📡「导入文件/文件夹」的文档存入<b>知识星球(HKC)</b>并抽取成知识;本页显示的是<b>学习知识点/掌握度</b>。<span class="infotip-link" onclick="document.getElementById(\'planetLaunch\')?.click()">→ 去星球查看已摄入的知识</span></span></span></div>';
63
+ h+=`<div class="kp-sec"><div class="h">学习概况</div>
64
+ <div class="kp-metric"><span class="lab">知识点</span><span class="val">${d.total_items||0}</span></div>
65
+ <div class="kp-metric"><span class="lab">平均掌握度</span><span class="val">${((d.avg_mastery||0)*100).toFixed(0)}%</span></div>
66
+ <div class="kp-metric"><span class="lab">今日待复习</span><span class="val">${d.due_today||0}</span></div>
67
+ <div class="kp-metric"><span class="lab">知识簇</span><span class="val">${d.graph?.clusters||0}</span></div></div>`;
68
+ const tm=d.topic_mastery||{};
69
+ if(Object.keys(tm).length){h+='<div class="kp-sec"><div class="h">主题掌握度</div>';
70
+ Object.entries(tm).forEach(([t,m])=>{h+=`<div class="kp-row" style="gap:10px"><span style="width:64px;color:var(--ink-dim)">${t}</span><div class="mastery-bar"><i style="width:${m*100}%"></i></div><span style="font-family:Orbitron;font-size:10px;width:32px;text-align:right">${(m*100).toFixed(0)}%</span></div>`;});
71
+ h+='</div>';}
72
+ const fr=d.forgetting_risk||[];
73
+ if(fr.length){h+=`<div class="kp-sec"><div class="h">遗忘风险</div><div class="kp-chip warn"><span class="ico">◷</span><div class="tx"><b>${fr.length} 个知识点高风险</b><span>建议优先复习</span></div></div></div>`;}
74
+ return h;
75
+ }
76
+
77
+ export function renderItinerary(d){
78
+ let h='<div class="kp-add" onclick="openEntry(\'admin\')">+ 录入行程</div>'
79
+ +'<div class="kp-add" onclick="importDomainFile(\'admin\')">📁 导入文件</div>';
80
+ h+=`<div class="kp-sec"><div class="h">行程地图</div>
81
+ <div id="amapBox" style="height:160px;border-radius:10px;overflow:hidden;border:1px solid var(--glass-brd);position:relative;background:radial-gradient(circle at 50% 50%,rgba(255,157,0,.08),rgba(8,12,28,.5))">
82
+ <div id="amapHint" style="position:absolute;inset:0;display:grid;place-items:center;text-align:center;font-size:11px;color:var(--ink-faint);padding:10px">加载地图中…</div>
83
+ </div></div>`;
84
+ h+=itinRouteHTML(d);
85
+ setTimeout(()=>drawAMap(d.map_data||[]),60);
86
+ return h||'<div class="kp-empty">暂无行程 · 先导入行程点</div>';
87
+ }
88
+
89
+ export function itinRouteHTML(d){
90
+ let h='';
91
+ const opt=d.optimized_route||{};
92
+ if(opt.order_names){h+=`<div class="kp-sec"><div class="h">最优路线 (${opt.method})</div>`;
93
+ opt.order_names.forEach((n,i)=>{h+=`<div class="kp-route"><span class="seq">${i+1}</span><span>${n}</span></div>`;});
94
+ h+=`<div class="kp-metric" style="margin-top:8px"><span class="lab">总距离</span><span class="val">${opt.total_km} km</span></div><div class="kp-metric"><span class="lab">总通勤</span><span class="val">${opt.total_min} 分</span></div></div>`;}
95
+ const cf=d.conflicts||[];
96
+ if(cf.length){h+='<div class="kp-sec"><div class="h">冲突 / 可达性</div>';
97
+ cf.forEach(c=>{h+=`<div class="kp-chip crit"><span class="ico">✕</span><div class="tx"><b>${c.type==='unreachable'?'赶不及':'时间冲突'}</b><span>${c.reason}</span></div></div>`;});
98
+ h+='</div>';}
99
+ return h;
100
+ }
101
+
102
+ export function itinSideHTML(d){
103
+ let h='<div class="kp-add" onclick="openEntry(\'admin\')">+ 录入行程</div>'
104
+ +'<div class="kp-add" onclick="importDomainFile(\'admin\')">📁 导入文件</div>';
105
+ const body=itinRouteHTML(d);
106
+ return h + (body || '<div style="text-align:left;color:var(--ink-faint);font-size:11px;padding:8px 0;line-height:1.8">搜索地点<br>加入行程</div>');
107
+ }
108
+
109
+ export function drawAMap(mapData){
110
+ const box=document.getElementById('amapBox'), hint=document.getElementById('amapHint');
111
+ if(!box)return;
112
+ const pois=mapData.filter(x=>x.type==='poi');
113
+ const routes=mapData.filter(x=>x.type==='route');
114
+ if(!AMAP_JS_KEY){
115
+ box.innerHTML=simpleMapSVG(pois,routes);
116
+ return;
117
+ }
118
+ loadAMap().then(AMap=>{
119
+ box.innerHTML='';
120
+ const center=pois.length?pois[0].lnglat:[116.40,39.90];
121
+ _amapMap=new AMap.Map(box,{zoom:11,center,viewMode:'2D'});
122
+ const pts=[];
123
+ pois.forEach((p,i)=>{
124
+ const mk=new AMap.Marker({position:p.lnglat,map:_amapMap,
125
+ label:{content:`${i+1}.${p.text}`,direction:'top'}});
126
+ pts.push(p.lnglat);
127
+ });
128
+ routes.forEach(r=>{
129
+ new AMap.Polyline({path:[r.start,r.end],map:_amapMap,
130
+ strokeColor:'#ff9d00',strokeWeight:4,strokeOpacity:.85});
131
+ });
132
+ if(pts.length)_amapMap.setFitView();
133
+ }).catch(()=>{ box.innerHTML=simpleMapSVG(pois,routes); });
134
+ }
135
+
136
+ export function simpleMapSVG(pois,routes){
137
+ if(!pois.length)return '<div style="display:grid;place-items:center;height:100%;font-size:11px;color:var(--ink-faint)">暂无坐标 · 配置高德 JSAPI Key 后显示真地图</div>';
138
+ const lngs=pois.map(p=>p.lnglat[0]),lats=pois.map(p=>p.lnglat[1]);
139
+ const minx=Math.min(...lngs),maxx=Math.max(...lngs),miny=Math.min(...lats),maxy=Math.max(...lats);
140
+ const W=240,H=150,pad=24;
141
+ const sx=v=>pad+((v-minx)/((maxx-minx)||1))*(W-2*pad);
142
+ const sy=v=>H-pad-((v-miny)/((maxy-miny)||1))*(H-2*pad);
143
+ let s=`<svg viewBox="0 0 ${W} ${H}" style="width:100%;height:100%">`;
144
+ routes.forEach(r=>{s+=`<line x1="${sx(r.start[0])}" y1="${sy(r.start[1])}" x2="${sx(r.end[0])}" y2="${sy(r.end[1])}" stroke="#ff9d00" stroke-width="2" stroke-opacity=".6" stroke-dasharray="4 3"/>`;});
145
+ pois.forEach((p,i)=>{const x=sx(p.lnglat[0]),y=sy(p.lnglat[1]);
146
+ s+=`<circle cx="${x}" cy="${y}" r="6" fill="#ff9d00" fill-opacity=".25" stroke="#ff9d00" stroke-width="1.5"/>`;
147
+ s+=`<text x="${x}" y="${y+3}" font-size="8" fill="#fff" text-anchor="middle" font-family="Orbitron">${i+1}</text>`;
148
+ s+=`<text x="${x}" y="${y-9}" font-size="7" fill="#7e93b8" text-anchor="middle">${p.text}</text>`;});
149
+ s+='</svg>';
150
+ return s+`<div style="position:absolute;bottom:4px;right:6px;font-size:8px;color:var(--ink-faint)">坐标示意 · 配 JSAPI Key 看真地图</div>`;
151
+ }
152
+
153
+ export function renderSituation(d){
154
+ let h='';
155
+ const f=d.finance||{},l=d.learning||{},i=d.itinerary||{};
156
+ h+=`<div class="kp-sec"><div class="h">驾驶舱视图</div>
157
+ <div class="kp-metric"><span class="lab">💰 财务交易</span><span class="val">${f.transactions||0}</span></div>
158
+ <div class="kp-metric"><span class="lab">📚 待复习</span><span class="val">${l.due_today||0}</span></div>
159
+ <div class="kp-metric"><span class="lab">📍 行程冲突</span><span class="val">${i.conflicts||0}</span></div></div>`;
160
+ const al=d.alerts||[];
161
+ if(al.length){h+='<div class="kp-sec"><div class="h">跨域告警</div>';
162
+ al.forEach(a=>{const cls=a.severity==='critical'?'crit':a.severity==='warn'?'warn':'info';
163
+ h+=`<div class="kp-chip ${cls}"><span class="ico">▲</span><div class="tx"><b>${escapeHtml(a.domain)}</b><span>${escapeHtml(a.msg)}</span></div></div>`;});
164
+ h+='</div>';}
165
+ else h+='<div class="kp-empty">暂无跨域告警 · 系统平稳</div>';
166
+ return h;
167
+ }
168
+
169
+ let _ovMapRef=null; // 全屏地图引用,供搜索使用
170
+ export function amapPlaceUrl(name,lng,lat){
171
+ return `https://www.amap.com/search?query=${encodeURIComponent(name)}&center=${lng},${lat}&zoom=16`;
172
+ }
173
+ export function drawAMapInto(boxId,mapData){
174
+ const box=document.getElementById(boxId); if(!box)return;
175
+ const pois=mapData.filter(x=>x.type==='poi');
176
+ const routes=mapData.filter(x=>x.type==='route');
177
+ if(!AMAP_JS_KEY){ box.innerHTML=simpleMapSVG(pois,routes); return; }
178
+ loadAMap().then(AMap=>{
179
+ box.innerHTML='';
180
+ const center=pois.length?pois[0].lnglat:[116.40,39.90];
181
+ const map=new AMap.Map(box,{zoom:12,center,viewMode:'2D'});
182
+ _ovMapRef=map;
183
+ AMap.plugin(['AMap.ToolBar','AMap.Scale','AMap.MapType'],()=>{
184
+ map.addControl(new AMap.ToolBar({position:{top:'90px',right:'20px'}}));
185
+ map.addControl(new AMap.Scale());
186
+ map.addControl(new AMap.MapType({
187
+ defaultType:0, // 0=标准 1=卫星
188
+ showTraffic:false, // 路况开关
189
+ showRoad:false, // 卫星图上叠加路网
190
+ }));
191
+ });
192
+ const pts=[];
193
+ pois.forEach((p,i)=>{
194
+ const mk=new AMap.Marker({position:p.lnglat,map,label:{content:`${i+1}.${p.text}`,direction:'top'}});
195
+ mk.on('click',()=>{
196
+ const info=new AMap.InfoWindow({
197
+ content:`<div style="padding:8px 6px;font-size:13px;min-width:160px">
198
+ <b style="font-size:14px">${p.text}</b><br>
199
+ <span style="color:#666;font-size:11px">${p.remark||''}</span><br>
200
+ <a href="${amapPlaceUrl(p.text,p.lnglat[0],p.lnglat[1])}" target="_blank"
201
+ style="display:inline-block;margin-top:8px;padding:5px 12px;background:#3478f6;color:#fff;border-radius:6px;font-size:12px;text-decoration:none">
202
+ 在高德查看详情 ↗</a></div>`,
203
+ offset:new AMap.Pixel(0,-30)});
204
+ info.open(map,p.lnglat);
205
+ });
206
+ pts.push(p.lnglat);
207
+ });
208
+ routes.forEach(r=>{new AMap.Polyline({path:[r.start,r.end],map,strokeColor:'#ff9d00',strokeWeight:5,strokeOpacity:.85,showDir:true});});
209
+ if(pts.length)map.setFitView();
210
+ }).catch(()=>{box.innerHTML=simpleMapSVG(pois,routes);});
211
+ }
212
+
213
+ let _searchMarker=null;
214
+ export function initMapSearch(){
215
+ const inp=document.getElementById('mapSearchInput');
216
+ const resBox=document.getElementById('mapSearchResults');
217
+ if(!inp||!AMAP_JS_KEY)return;
218
+ loadAMap().then(AMap=>{
219
+ AMap.plugin(['AMap.AutoComplete'],()=>{
220
+ const auto=new AMap.AutoComplete({city:'全国'});
221
+ let timer=null;
222
+ inp.addEventListener('input',()=>{
223
+ clearTimeout(timer);
224
+ const kw=inp.value.trim();
225
+ if(!kw){resBox.innerHTML='';return;}
226
+ timer=setTimeout(()=>{
227
+ auto.search(kw,(status,result)=>{
228
+ if(status==='complete'&&result.tips){
229
+ resBox.innerHTML=result.tips.filter(t=>t.location).slice(0,8).map(t=>
230
+ `<div class="msr-item" data-lng="${escapeHtml(t.location.lng)}" data-lat="${escapeHtml(t.location.lat)}" data-name="${escapeHtml(t.name)}" data-addr="${escapeHtml((t.district||'')+(t.address||''))}">
231
+ <b>${escapeHtml(t.name)}</b><span>${escapeHtml(t.district||'')} ${escapeHtml(t.address||'')}</span></div>`).join('');
232
+ bindSearchResults();
233
+ }
234
+ });
235
+ },300);
236
+ });
237
+ });
238
+ });
239
+ }
240
+ export function bindSearchResults(){
241
+ document.querySelectorAll('.msr-item').forEach(it=>{
242
+ it.addEventListener('click',()=>{
243
+ const lng=parseFloat(it.dataset.lng),lat=parseFloat(it.dataset.lat),name=it.dataset.name,addr=it.dataset.addr;
244
+ if(_ovMapRef&&window.AMap){
245
+ _ovMapRef.setZoomAndCenter(15,[lng,lat]);
246
+ if(_searchMarker)_ovMapRef.remove(_searchMarker);
247
+ _searchMarker=new AMap.Marker({position:[lng,lat],map:_ovMapRef,
248
+ label:{content:name,direction:'top'}});
249
+ const info=new AMap.InfoWindow({
250
+ content:`<div style="padding:6px 4px;font-size:13px;min-width:170px"><b>${name}</b><br><span style="color:#666;font-size:11px">${addr}</span><br>
251
+ <div style="display:flex;gap:6px;margin-top:8px">
252
+ <button id="addWpBtn" style="padding:6px 12px;background:#ff9d00;border:0;border-radius:6px;color:#fff;cursor:pointer;font-size:12px">+ 加入行程</button>
253
+ <a href="${amapPlaceUrl(name,lng,lat)}" target="_blank" style="padding:6px 12px;background:#3478f6;border-radius:6px;color:#fff;font-size:12px;text-decoration:none">详情 ↗</a>
254
+ </div></div>`,
255
+ offset:new AMap.Pixel(0,-30)});
256
+ info.open(_ovMapRef,[lng,lat]);
257
+ setTimeout(()=>{const b=document.getElementById('addWpBtn');
258
+ if(b)b.onclick=()=>addWaypointFromSearch(name,addr,lng,lat);},100);
259
+ }
260
+ document.getElementById('mapSearchResults').innerHTML='';
261
+ document.getElementById('mapSearchInput').value=name;
262
+ });
263
+ });
264
+ }
265
+ export async function addWaypointFromSearch(name,addr,lng,lat){
266
+ try{
267
+ await fetch(`${API}/itinerary/import`,{method:'POST',headers:{'Content-Type':'application/json'},
268
+ body:JSON.stringify({rows:[{name,address:addr,lng,lat,start_time:null,duration_min:0,city:''}]})});
269
+ const d=await(await fetch(`${API}/itinerary/plan`)).json();
270
+ _lastKernelData.admin=d;
271
+ drawAMapInto('ovMap',d.map_data||[]);
272
+ const side=document.querySelector('.ov-side');
273
+ if(side)side.innerHTML=itinSideHTML(d);
274
+ kpSet('行程规划','Ops',renderItinerary(d)); // 同步主面板
275
+ }catch(e){}
276
+ }