@agentunion/kite 1.5.0 → 1.6.0

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 (573) hide show
  1. package/.claude/skills/kite/checklists/feature-checklist.md +496 -0
  2. package/.claude/skills/kite/references/event-patterns.md +180 -0
  3. package/.claude/skills/kite/references/health-check.md +202 -0
  4. package/.claude/skills/kite/references/http-service.md +199 -0
  5. package/.claude/skills/kite/references/module-md-spec.md +172 -0
  6. package/.claude/skills/kite/references/multi-connection.md +147 -0
  7. package/.claude/skills/kite/references/rpc-patterns.md +199 -0
  8. package/.claude/skills/kite/references/shutdown-sequence.md +146 -0
  9. package/.claude/skills/kite/references/stdin-protocol.md +147 -0
  10. package/.claude/skills/kite/references/test-center-integration.md +178 -0
  11. package/.claude/skills/kite/references/ws-lifecycle.md +301 -0
  12. package/.claude/skills/kite/skill.md +272 -0
  13. package/.claude/skills/kite/templates/go/README.md +20 -0
  14. package/.claude/skills/kite/templates/node/entry.js +134 -0
  15. package/.claude/skills/kite/templates/node/module.md +16 -0
  16. package/.claude/skills/kite/templates/node/server.js +351 -0
  17. package/.claude/skills/kite/templates/node/server_http.js +90 -0
  18. package/.claude/skills/kite/templates/python/entry.py +425 -0
  19. package/.claude/skills/kite/templates/python/module.md +26 -0
  20. package/.claude/skills/kite/templates/python/server.py +447 -0
  21. package/.claude/skills/kite/templates/python/server_http.py +433 -0
  22. package/cli.js +38 -4
  23. package/core/env_checker.py +96 -0
  24. package/docs/05-/347/237/255/344/277/241/350/256/244/350/257/201/344/270/216/347/224/250/346/210/267/344/277/241/346/201/257/346/216/245/345/217/243/346/226/207/346/241/243.md +507 -0
  25. package/docs/ACP/345/215/217/350/256/256/345/205/274/345/256/271/346/226/271/346/241/210.md +138 -0
  26. package/docs/CI/344/270/216AI/350/207/252/345/212/250/345/214/226/346/265/213/350/257/225/346/226/271/346/241/210.md +75 -0
  27. package/docs/CLI/345/274/200/345/217/221/350/256/241/345/210/222.md +595 -0
  28. package/docs/ClaudeCode/350/277/234/347/250/213/345/215/217/344/275/234/347/263/273/347/273/237-/346/212/200/346/234/257/350/257/204/344/274/260.md +535 -0
  29. package/docs/ClaudeCode/350/277/234/347/250/213/345/215/217/344/275/234/347/263/273/347/273/237/350/256/276/350/256/241.md +631 -0
  30. package/docs/Evol-App/344/275/277/347/224/250KernelClient/346/224/271/351/200/240/345/256/214/346/210/220.md +342 -0
  31. package/docs/Evol/346/216/247/345/210/266/345/217/260/346/217/222/344/273/266/345/214/226/346/236/266/346/236/204/346/246/202/350/246/201.md +604 -0
  32. package/docs/Evol/346/216/247/345/210/266/345/217/260/346/217/222/344/273/266/345/214/226/346/236/266/346/236/204/350/256/276/350/256/241.md +1708 -0
  33. package/docs/Evol/346/250/241/345/235/227/350/256/276/350/256/241/346/226/271/346/241/210.md +1154 -0
  34. package/docs/Evol/351/241/265/351/235/242/346/217/222/344/273/266/345/214/226-Evol/346/250/241/345/235/227/345/256/236/346/226/275/346/214/207/345/215/227.md +403 -0
  35. package/docs/Evol/351/241/265/351/235/242/346/217/222/344/273/266/345/214/226-/345/244/226/351/203/250/346/250/241/345/235/227/346/216/245/345/205/245/346/214/207/345/215/227.md +468 -0
  36. package/docs/HTTP-RPC/350/277/201/347/247/273/345/210/260WebSocket/350/256/241/345/210/222.md +318 -0
  37. package/docs/INDEX.md +388 -0
  38. package/docs/KITE_DOCS_GUIDE.md +33 -0
  39. package/docs/Kernel-Client-Kite-Token/346/224/257/346/214/201/345/256/236/346/226/275/345/256/214/346/210/220.md +330 -0
  40. package/docs/Kernel/344/270/273/345/212/250Ping/346/234/272/345/210/266-/346/255/243/347/241/256/345/256/236/347/216/260.md +235 -0
  41. package/docs/Kernel/344/270/273/345/212/250Ping/346/234/272/345/210/266/345/256/236/346/226/275/346/200/273/347/273/223.md +204 -0
  42. package/docs/Kite/345/256/211/350/243/205/351/227/256/351/242/230/350/247/243/345/206/263/346/226/271/346/241/210.md +362 -0
  43. package/docs/Kite/346/216/247/345/210/266/345/217/260/346/217/222/344/273/266/345/214/226/346/236/266/346/236/204/350/256/276/350/256/241-/347/273/210/346/236/201/347/233/256/346/240/207.md +721 -0
  44. package/docs/Kite/346/216/247/345/210/266/345/217/260/347/273/237/344/270/200WebSocket/346/224/271/351/200/240/346/226/271/346/241/210.md +821 -0
  45. package/docs/Kite/346/241/206/346/236/266/350/256/276/350/256/241/01-/346/241/206/346/236/266/345/256/232/344/275/215.md +12 -0
  46. package/docs/Kite/346/241/206/346/236/266/350/256/276/350/256/241/02-/346/240/270/345/277/203/346/246/202/345/277/265.md +341 -0
  47. package/docs/Kite/346/241/206/346/236/266/350/256/276/350/256/241/03-/347/263/273/347/273/237/346/236/266/346/236/204.md +257 -0
  48. package/docs/Kite/346/241/206/346/236/266/350/256/276/350/256/241/04-/346/250/241/345/235/227/350/247/204/350/214/203.md +263 -0
  49. package/docs/Kite/346/241/206/346/236/266/350/256/276/350/256/241/05-/346/240/270/345/277/203/346/265/201/347/250/213-/346/226/260/347/211/210.md +267 -0
  50. package/docs/Kite/346/241/206/346/236/266/350/256/276/350/256/241/05-/346/240/270/345/277/203/346/265/201/347/250/213.md +149 -0
  51. package/docs/Kite/346/241/206/346/236/266/350/256/276/350/256/241/06-/347/233/256/345/275/225/347/273/223/346/236/204.md +231 -0
  52. package/docs/Kite/346/241/206/346/236/266/350/256/276/350/256/241/07-/346/225/260/346/215/256/346/250/241/345/236/213.md +68 -0
  53. package/docs/Kite/346/241/206/346/236/266/350/256/276/350/256/241/08-/346/211/251/345/261/225/346/200/247.md +34 -0
  54. package/docs/Kite/346/241/206/346/236/266/350/256/276/350/256/241/09-/344/270/216/345/205/267/344/275/223/345/272/224/347/224/250/347/232/204/345/205/263/347/263/273.md +22 -0
  55. package/docs/Kite/346/241/206/346/236/266/350/256/276/350/256/241/README.md +46 -0
  56. package/docs/Kite/347/263/273/347/273/237/345/220/257/345/212/250/346/265/201/347/250/213.md +567 -0
  57. package/docs/Launcher/345/220/257/345/212/250/345/231/250/346/226/207/346/241/243.md +745 -0
  58. package/docs/Polyglot/350/277/220/350/241/214/346/227/266/344/270/216Clawdbot/345/205/274/345/256/271/346/200/247/350/256/276/350/256/241.md +321 -0
  59. package/docs/Redis/344/270/216/346/250/241/345/235/227/345/244/232/345/256/236/344/276/213/346/226/271/346/241/210.md +438 -0
  60. package/docs/Relay-Kite-Token/350/256/244/350/257/201/345/256/236/346/226/275/345/256/214/346/210/220.md +178 -0
  61. package/docs/Relay-Token/346/235/203/351/231/220/351/205/215/347/275/256/351/252/214/350/257/201.md +113 -0
  62. package/docs/Watchdog/345/201/245/345/272/267/346/243/200/346/237/245/344/270/216WebSocket-Ping/346/234/272/345/210/266/345/210/206/346/236/220.md +367 -0
  63. package/docs/Watchdog/350/265/204/346/272/220/347/233/221/346/216/247/347/255/226/347/225/245.md +92 -0
  64. package/docs/WebSocket/346/216/245/346/224/266/345/276/252/347/216/257/346/255/273/351/224/201/351/230/262/350/214/203/350/247/204/350/214/203.md +357 -0
  65. package/docs/WebSocket/350/277/236/346/216/245/351/237/247/346/200/247/344/270/216/351/207/215/350/277/236/346/234/272/345/210/266/345/256/214/346/225/264/346/226/271/346/241/210.md +531 -0
  66. package/docs/WebSocket/350/277/236/346/216/245/351/237/247/346/200/247/346/226/271/346/241/210.md +169 -0
  67. package/docs/WebSocket/351/207/215/350/277/236/346/234/272/345/210/266/346/265/213/350/257/225/346/212/245/345/221/212.md +169 -0
  68. package/docs/WebSocket/351/207/215/350/277/236/351/200/200/351/201/277/346/234/272/345/210/266/346/226/271/346/241/210.md +394 -0
  69. package/docs/Web/346/250/241/345/235/227/344/270/216Evol/346/250/241/345/235/227/351/207/215/346/236/204/345/210/206/346/236/220.md +521 -0
  70. package/docs/audit-api-guide.md +68 -0
  71. package/docs/audit-module-design.md +315 -0
  72. package/docs/audit-module-implementation-summary.md +149 -0
  73. package/docs/llm-context-design.md +52 -0
  74. package/docs/llm-test-enhancement-plan.md +970 -0
  75. package/docs/logs-api-guide.md +42 -0
  76. package/docs/npm/345/214/205Python/347/216/257/345/242/203/347/256/241/347/220/206/346/226/271/346/241/210.md +302 -0
  77. package/docs/npm/345/217/221/345/270/203/344/270/216CLI/344/275/277/347/224/250/346/214/207/345/215/227.md +245 -0
  78. package/docs/stdio/344/270/216/347/253/257/345/217/243/345/217/221/347/216/260/351/207/215/346/236/204.md +480 -0
  79. package/docs/web/346/250/241/345/235/227/344/270/255/350/275/254/346/234/215/345/212/241/350/256/276/350/256/241/346/226/271/346/241/210.md +449 -0
  80. package/docs//344/272/213/344/273/266/345/244/204/347/220/206/346/234/272/345/210/266.md +388 -0
  81. package/docs//344/272/213/344/273/266/345/244/204/347/220/206/350/247/204/350/214/203.md +113 -0
  82. package/docs//344/272/213/344/273/266/350/256/242/351/230/205/351/200/232/351/205/215/347/254/246/350/247/204/350/214/203.md +256 -0
  83. package/docs//344/272/213/344/273/266/351/230/237/345/210/227/345/274/271/346/200/247/347/256/241/347/220/206.md +449 -0
  84. package/docs//344/272/244/344/272/222/345/274/217/347/273/210/347/253/257/346/216/247/345/210/266/346/226/271/346/241/210.md +301 -0
  85. package/docs//344/273/243/347/220/206/345/220/257/345/212/250/345/231/250/344/270/216/345/256/271/345/231/250/345/214/226.md +140 -0
  86. package/docs//344/273/243/347/240/201/347/273/237/350/256/241/345/267/245/345/205/267/344/275/277/347/224/250/350/257/264/346/230/216.md +217 -0
  87. package/docs//344/274/230/351/233/205/351/200/200/345/207/272/350/247/204/350/214/203.md +362 -0
  88. package/docs//344/276/235/350/265/226/347/256/241/347/220/206/350/257/264/346/230/216.md +141 -0
  89. package/docs//344/277/256/345/244/215/346/235/203/351/231/220/351/227/256/351/242/230-evol-RPC/346/235/203/351/231/220.md +268 -0
  90. package/docs//345/210/240/351/231/244kernel-client-example/345/256/214/346/210/220.md +309 -0
  91. package/docs//345/210/240/351/231/244ws-management/345/256/214/346/210/220.md +418 -0
  92. package/docs//345/220/257/345/212/250/344/274/230/345/214/226/346/226/271/346/241/210.md +522 -0
  93. package/docs//345/220/257/345/212/250/344/276/235/350/265/226/344/270/216/346/216/222/345/272/217.md +105 -0
  94. package/docs//345/256/211/350/243/205/350/204/232/346/234/254/345/274/200/345/217/221/346/226/207/346/241/243.md +643 -0
  95. package/docs//345/256/214/346/225/264/345/220/257/345/212/250/346/265/201/347/250/213/350/256/276/350/256/241.md +452 -0
  96. package/docs//345/256/236/347/216/260/350/247/204/345/210/222.md +195 -0
  97. package/docs//345/277/203/350/267/263/346/234/272/345/210/266/351/207/215/346/236/204/346/200/273/347/273/223.md +166 -0
  98. package/docs//346/217/241/346/211/213/350/256/244/350/257/201/346/226/271/346/241/210-/345/256/211/345/205/250/345/256/241/346/237/245.md +176 -0
  99. package/docs//346/217/241/346/211/213/350/256/244/350/257/201/346/226/271/346/241/210.md +908 -0
  100. package/docs//346/226/207/346/241/243/346/233/264/346/226/260/346/270/205/345/215/225.md +83 -0
  101. package/docs//346/227/245/345/277/227/344/270/216/345/274/202/345/270/270/345/244/204/347/220/206/350/247/204/350/214/203.md +829 -0
  102. package/docs//346/227/245/345/277/227/350/260/203/350/257/225/345/256/236/346/210/230/346/214/207/345/215/227.md +25 -0
  103. package/docs//346/236/266/346/236/204/345/200/237/351/211/264/346/214/207/345/215/227.md +977 -0
  104. package/docs//346/236/266/346/236/204/346/224/271/351/200/240-/345/256/214/346/210/220/346/200/273/347/273/223.md +440 -0
  105. package/docs//346/236/266/346/236/204/347/216/260/347/212/266/344/270/216/347/273/210/346/236/201/347/233/256/346/240/207/345/257/271/346/257/224/345/210/206/346/236/220.md +508 -0
  106. package/docs//346/250/241/345/235/227/345/244/232/350/277/236/346/216/245/346/216/247/345/210/266/347/255/226/347/225/245.md +220 -0
  107. package/docs//346/250/241/345/235/227/345/256/211/350/243/205/346/234/272/345/210/266/350/256/276/350/256/241.md +500 -0
  108. package/docs//346/250/241/345/235/227/345/274/200/345/217/221/346/214/207/345/215/227.md +1824 -0
  109. package/docs//346/250/241/345/235/227/347/203/255/346/233/264/346/226/260.md +89 -0
  110. package/docs//346/250/241/345/235/227/350/277/234/347/250/213/351/203/250/347/275/262/345/274/200/345/217/221/350/247/204/350/214/203.md +460 -0
  111. package/docs//346/250/241/345/235/227/351/200/200/345/207/272/346/234/272/345/210/266/345/256/214/346/225/264/346/226/271/346/241/210.md +303 -0
  112. package/docs//346/250/241/345/235/227/351/205/215/347/275/256/345/212/240/350/275/275/344/270/216/347/203/255/351/207/215/350/275/275/350/247/204/350/214/203.md +369 -0
  113. package/docs//346/265/213/350/257/225/344/270/255/345/277/203/346/267/273/345/212/240/346/250/241/345/235/227/346/265/213/350/257/225/346/214/207/345/215/227.md +147 -0
  114. package/docs//347/211/210/346/234/254/351/224/201/345/256/232/347/216/257/345/242/203/347/256/241/347/220/206/346/226/271/346/241/210.md +331 -0
  115. package/docs//347/216/257/345/242/203/345/217/230/351/207/217/344/270/216/350/277/220/350/241/214/346/227/266/347/233/256/345/275/225/350/256/276/350/256/241.md +499 -0
  116. package/docs//347/216/257/345/242/203/347/256/241/347/220/206/345/256/214/346/225/264/346/226/271/346/241/210.md +334 -0
  117. package/docs//350/231/232/346/213/237/346/250/241/345/235/227/344/270/255/350/275/254/346/234/215/345/212/241/345/256/214/346/225/264/350/256/276/350/256/241.md +1496 -0
  118. package/docs//350/231/232/346/213/237/347/216/257/345/242/203/345/267/245/344/275/234/345/216/237/347/220/206.md +163 -0
  119. package/docs//350/256/241/345/210/222/347/256/241/347/220/206/345/231/250/344/275/277/347/224/250/346/214/207/345/215/227.md +196 -0
  120. package/docs//350/256/244/350/257/201/346/250/241/345/235/227/344/270/216Gateway/350/256/276/350/256/241/346/226/271/346/241/210.md +765 -0
  121. package/docs//350/277/234/347/250/213/346/250/241/345/235/227/350/256/276/350/256/241-/346/227/247/347/211/210.md +1117 -0
  122. package/docs//350/277/234/347/250/213/346/250/241/345/235/227/350/256/276/350/256/241.md +451 -0
  123. package/docs//351/207/215/346/236/204/346/234/272/345/210/266/346/270/205/345/215/225.md +192 -0
  124. package/docs//351/223/276/350/267/257/350/277/275/350/270/252/346/226/271/346/241/210.md +242 -0
  125. package/docs//351/231/215/347/272/247/347/255/226/347/225/245/350/256/276/350/256/241/346/226/271/346/241/210.md +618 -0
  126. package/extensions/agents/assistant/entry.py +113 -14
  127. package/extensions/agents/assistant/module.md +27 -22
  128. package/extensions/agents/assistant/server.py +291 -105
  129. package/extensions/channels/acp_channel/entry.py +114 -16
  130. package/extensions/channels/acp_channel/module.md +4 -0
  131. package/extensions/channels/acp_channel/server.py +396 -105
  132. package/extensions/channels/phone_channel/__init__.py +1 -0
  133. package/extensions/channels/phone_channel/entry.py +503 -0
  134. package/extensions/channels/phone_channel/module.md +31 -0
  135. package/extensions/channels/phone_channel/server.py +686 -0
  136. package/extensions/event_hub_bench/entry.py +55 -12
  137. package/extensions/event_hub_bench/module.md +27 -27
  138. package/extensions/services/audit/README.md +134 -0
  139. package/extensions/services/audit/collector.py +73 -0
  140. package/extensions/services/audit/entry.py +444 -0
  141. package/extensions/services/audit/module.md +66 -0
  142. package/extensions/services/audit/query_audit.py +111 -0
  143. package/extensions/services/audit/routes/__init__.py +1 -0
  144. package/extensions/services/audit/routes/routes_audit.py +113 -0
  145. package/extensions/services/audit/schemas/__init__.py +5 -0
  146. package/extensions/services/audit/schemas/audit_event.py +92 -0
  147. package/extensions/services/audit/server.py +542 -0
  148. package/extensions/services/audit/storage.py +95 -0
  149. package/extensions/services/auth/entry.py +1054 -0
  150. package/extensions/services/auth/module.md +31 -0
  151. package/extensions/services/auth/token_store.py +185 -0
  152. package/extensions/services/auth/verifiers/evol_account.py +101 -0
  153. package/extensions/services/auth/verifiers/kite_token.py +38 -0
  154. package/extensions/services/auth/verifiers/pairing_code.py +71 -0
  155. package/extensions/services/backup/entry.py +494 -197
  156. package/extensions/services/backup/module.md +4 -2
  157. package/extensions/services/dataclaw/api/__init__.py +0 -0
  158. package/extensions/services/dataclaw/api/admin.py +367 -0
  159. package/extensions/services/dataclaw/api/copyright.py +175 -0
  160. package/extensions/services/dataclaw/api/credits.py +177 -0
  161. package/extensions/services/dataclaw/api/data.py +179 -0
  162. package/extensions/services/dataclaw/api/demands.py +269 -0
  163. package/extensions/services/dataclaw/api/feeds.py +262 -0
  164. package/extensions/services/dataclaw/api/identity.py +505 -0
  165. package/extensions/services/dataclaw/api/notifications.py +104 -0
  166. package/extensions/services/dataclaw/api/reviews.py +138 -0
  167. package/extensions/services/dataclaw/api/search.py +153 -0
  168. package/extensions/services/dataclaw/api/subscriptions.py +157 -0
  169. package/extensions/services/dataclaw/config.json5 +96 -0
  170. package/extensions/services/dataclaw/core/__init__.py +0 -0
  171. package/extensions/services/dataclaw/core/auth.py +95 -0
  172. package/extensions/services/dataclaw/core/config.py +50 -0
  173. package/extensions/services/dataclaw/core/database.py +70 -0
  174. package/extensions/services/dataclaw/entry.py +416 -0
  175. package/extensions/services/dataclaw/gofeed/351/241/271/347/233/256/346/211/200/346/234/211/346/235/203/350/275/254/347/247/273/346/265/201/347/250/213/350/257/264/346/230/216.md +309 -0
  176. package/extensions/services/dataclaw/migrate.py +283 -0
  177. package/extensions/services/dataclaw/models/__init__.py +0 -0
  178. package/extensions/services/dataclaw/module.md +49 -0
  179. package/extensions/services/dataclaw/requirements.txt +18 -0
  180. package/extensions/services/dataclaw/server.py +759 -0
  181. package/extensions/services/dataclaw/services/__init__.py +0 -0
  182. package/extensions/services/dataclaw/services/agent_service.py +132 -0
  183. package/extensions/services/dataclaw/services/credit_service.py +235 -0
  184. package/extensions/services/dataclaw/services/email_service.py +140 -0
  185. package/extensions/services/dataclaw/services/feed_service.py +259 -0
  186. package/extensions/services/dataclaw/services/notification_service.py +209 -0
  187. package/extensions/services/dataclaw/services/oauth_service.py +275 -0
  188. package/extensions/services/dataclaw/services/pricing.py +102 -0
  189. package/extensions/services/dataclaw/services/quality.py +79 -0
  190. package/extensions/services/dataclaw/services/reputation.py +142 -0
  191. package/extensions/services/dataclaw/services/sms_service.py +174 -0
  192. package/extensions/services/dataclaw/static/css/common.css +853 -0
  193. package/extensions/services/dataclaw/static/css/themes/blue.css +42 -0
  194. package/extensions/services/dataclaw/static/css/themes/dark.css +42 -0
  195. package/extensions/services/dataclaw/static/css/themes/light.css +35 -0
  196. package/extensions/services/dataclaw/static/js/api.js +103 -0
  197. package/extensions/services/dataclaw/static/js/common.js +321 -0
  198. package/extensions/services/dataclaw/static/js/i18n.js +95 -0
  199. package/extensions/services/dataclaw/static/js/pages/admin.js +152 -0
  200. package/extensions/services/dataclaw/static/js/pages/dashboard.js +82 -0
  201. package/extensions/services/dataclaw/static/js/pages/feed-detail.js +180 -0
  202. package/extensions/services/dataclaw/static/js/pages/feed-manage.js +158 -0
  203. package/extensions/services/dataclaw/static/js/theme.js +46 -0
  204. package/extensions/services/dataclaw/static/locales/en-US.json +464 -0
  205. package/extensions/services/dataclaw/static/locales/ja-JP.json +464 -0
  206. package/extensions/services/dataclaw/static/locales/zh-CN.json +464 -0
  207. package/extensions/services/dataclaw/templates/admin/index.html +90 -0
  208. package/extensions/services/dataclaw/templates/base.html +136 -0
  209. package/extensions/services/dataclaw/templates/credits/balance.html +106 -0
  210. package/extensions/services/dataclaw/templates/credits/deposit.html +164 -0
  211. package/extensions/services/dataclaw/templates/credits/history.html +90 -0
  212. package/extensions/services/dataclaw/templates/dashboard.html +52 -0
  213. package/extensions/services/dataclaw/templates/demands/create.html +78 -0
  214. package/extensions/services/dataclaw/templates/demands/detail.html +136 -0
  215. package/extensions/services/dataclaw/templates/demands/list.html +94 -0
  216. package/extensions/services/dataclaw/templates/feeds/create.html +95 -0
  217. package/extensions/services/dataclaw/templates/feeds/detail.html +110 -0
  218. package/extensions/services/dataclaw/templates/feeds/list.html +110 -0
  219. package/extensions/services/dataclaw/templates/feeds/manage.html +88 -0
  220. package/extensions/services/dataclaw/templates/index.html +185 -0
  221. package/extensions/services/dataclaw/templates/login.html +246 -0
  222. package/extensions/services/dataclaw/templates/register.html +164 -0
  223. package/extensions/services/dataclaw/templates/settings/notifications.html +96 -0
  224. package/extensions/services/dataclaw/templates/settings/profile.html +167 -0
  225. package/extensions/services/dataclaw/templates/subscriptions/list.html +64 -0
  226. package/extensions/services/dataclaw/tests/__init__.py +0 -0
  227. package/extensions/services/dataclaw/tests/conftest.py +68 -0
  228. package/extensions/services/dataclaw/tests/integration/__init__.py +0 -0
  229. package/extensions/services/dataclaw/tests/integration/test_workflows.py +239 -0
  230. package/extensions/services/dataclaw/tests/unit/__init__.py +0 -0
  231. package/extensions/services/dataclaw/tests/unit/test_admin.py +70 -0
  232. package/extensions/services/dataclaw/tests/unit/test_copyright.py +63 -0
  233. package/extensions/services/dataclaw/tests/unit/test_credits.py +80 -0
  234. package/extensions/services/dataclaw/tests/unit/test_data.py +98 -0
  235. package/extensions/services/dataclaw/tests/unit/test_demands.py +106 -0
  236. package/extensions/services/dataclaw/tests/unit/test_feeds.py +98 -0
  237. package/extensions/services/dataclaw/tests/unit/test_identity.py +88 -0
  238. package/extensions/services/dataclaw/tests/unit/test_notifications.py +36 -0
  239. package/extensions/services/dataclaw/tests/unit/test_reviews.py +68 -0
  240. package/extensions/services/dataclaw/tests/unit/test_search.py +64 -0
  241. package/extensions/services/dataclaw/tests/unit/test_subscriptions.py +65 -0
  242. package/extensions/services/dataclaw/tests/unit/test_system.py +106 -0
  243. package/extensions/services/dataclaw/utils/__init__.py +0 -0
  244. package/extensions/services/dataclaw/utils/crypto.py +38 -0
  245. package/extensions/services/dataclaw/utils/id_generator.py +52 -0
  246. package/extensions/services/dataclaw/ws/__init__.py +0 -0
  247. package/extensions/services/dataclaw/ws/handler.py +163 -0
  248. package/extensions/services/dataclaw//345/215/217/350/256/2561-/351/241/271/347/233/256/346/235/241/344/273/266/346/216/210/346/235/203/344/270/216/350/202/241/346/235/203/345/257/271/344/273/267/345/215/217/350/256/256.md +243 -0
  249. package/extensions/services/dataclaw//345/215/217/350/256/2562-/351/241/271/347/233/256/350/264/255/344/271/260/346/235/203/344/270/216/345/244/226/345/214/205/345/247/224/346/211/230/345/274/200/345/217/221/345/215/217/350/256/256.md +434 -0
  250. package/extensions/services/evol/__init__.py +1 -0
  251. package/extensions/services/evol/async_http.py +551 -0
  252. package/extensions/services/evol/auth_manager.py +602 -443
  253. package/extensions/services/evol/config.json5 +16 -0
  254. package/extensions/services/evol/entry.py +568 -406
  255. package/extensions/services/evol/evol_api.py +969 -173
  256. package/extensions/services/evol/mfa_totp.py +77 -0
  257. package/extensions/services/evol/module.md +150 -32
  258. package/extensions/services/evol/nonce_pool.py +113 -0
  259. package/extensions/services/evol/oauth_manager.py +223 -0
  260. package/extensions/services/evol/pairing.py +3 -2
  261. package/extensions/services/evol/pairing_codes.jsonl +1 -0
  262. package/extensions/services/evol/relay.py +1031 -682
  263. package/extensions/services/evol/relay_config.json5 +85 -67
  264. package/extensions/services/evol/routes/routes_llm.py +231 -0
  265. package/extensions/services/evol/routes/routes_rpc.py +90 -89
  266. package/extensions/services/evol/routes/routes_test.py +11 -4
  267. package/extensions/services/evol/server.py +2426 -875
  268. package/extensions/services/evol/static/assets/CommissionView-Cs_ys6Gm.js +1 -0
  269. package/extensions/services/evol/static/assets/CommissionView-DACet_Oo.css +1 -0
  270. package/extensions/services/evol/static/assets/IframePage-DbO11U9G.js +1 -0
  271. package/extensions/services/evol/static/assets/IframePage-c572lT8i.css +1 -0
  272. package/extensions/services/evol/static/assets/TeamDetailView-DULrGD7k.css +1 -0
  273. package/extensions/services/evol/static/assets/TeamDetailView-gy_MBEqG.js +139 -0
  274. package/extensions/services/evol/static/assets/element-plus-Bd7pZkkM.js +63 -0
  275. package/extensions/services/evol/static/assets/index-CmMONKzG.css +1 -0
  276. package/extensions/services/evol/static/assets/index-D44bBe__.js +2 -0
  277. package/extensions/services/evol/static/assets/vue-vendor-DtF-__I4.js +29 -0
  278. package/extensions/services/evol/static/index.html +16 -781
  279. package/extensions/services/evol/static/logo.png +0 -0
  280. package/extensions/services/evol/stats_manager.py +243 -240
  281. package/extensions/services/evol/web/README.md +89 -0
  282. package/extensions/services/evol/web/build.bat +44 -0
  283. package/extensions/services/evol/web/index.html +13 -0
  284. package/extensions/services/evol/web/package-lock.json +1718 -0
  285. package/extensions/services/evol/web/package.json +26 -0
  286. package/extensions/services/evol/web/public/logo.png +0 -0
  287. package/extensions/services/evol/web/src/App.vue +7 -0
  288. package/extensions/services/evol/web/src/components/layout/AppHeader.vue +202 -0
  289. package/extensions/services/evol/web/src/components/layout/AppLayout.vue +61 -0
  290. package/extensions/services/evol/web/src/components/layout/AppSidebar.vue +115 -0
  291. package/extensions/services/evol/web/src/components/login/LoginPage.vue +271 -0
  292. package/extensions/services/evol/web/src/components/team/AddMemberModal.vue +181 -0
  293. package/extensions/services/evol/web/src/components/team/GroupTreeNode.vue +156 -0
  294. package/extensions/services/evol/web/src/components/team/TeamAlertConfig.vue +221 -0
  295. package/extensions/services/evol/web/src/components/team/TeamBillModal.vue +165 -0
  296. package/extensions/services/evol/web/src/components/team/TeamMembersAndGroups.vue +499 -0
  297. package/extensions/services/evol/web/src/components/team/TeamStatsPanel.vue +907 -0
  298. package/extensions/services/evol/web/src/components/team/TreeNode.vue +331 -0
  299. package/extensions/services/evol/web/src/components/team/stats/StatsExportProgress.vue +44 -0
  300. package/extensions/services/evol/web/src/components/team/stats/StatsHeader.vue +89 -0
  301. package/extensions/services/evol/web/src/components/team/stats/StatsMemberDetail.vue +415 -0
  302. package/extensions/services/evol/web/src/components/team/stats/StatsSummary.vue +42 -0
  303. package/extensions/services/evol/web/src/components/team/stats/helpers.ts +195 -0
  304. package/extensions/services/evol/web/src/components/team/stats/stats.css +741 -0
  305. package/extensions/services/evol/web/src/components/team/stats/useStatsApi.ts +114 -0
  306. package/extensions/services/evol/web/src/components/team/stats/useStatsCharts.ts +242 -0
  307. package/extensions/services/evol/web/src/components/team/stats/useStatsExport.ts +232 -0
  308. package/extensions/services/evol/web/src/composables/useFormatters.ts +42 -0
  309. package/extensions/services/evol/web/src/composables/useTheme.ts +52 -0
  310. package/extensions/services/evol/web/src/env.d.ts +7 -0
  311. package/extensions/services/evol/web/src/i18n/en.ts +361 -0
  312. package/extensions/services/evol/web/src/i18n/index.ts +36 -0
  313. package/extensions/services/evol/web/src/i18n/zh.ts +379 -0
  314. package/extensions/services/evol/web/src/main.ts +21 -0
  315. package/extensions/services/evol/web/src/router/index.ts +81 -0
  316. package/extensions/services/evol/web/src/services/kernel-client.ts +406 -0
  317. package/extensions/services/evol/web/src/stores/auth.ts +189 -0
  318. package/extensions/services/evol/web/src/stores/connection.ts +134 -0
  319. package/extensions/services/evol/web/src/stores/pages.ts +79 -0
  320. package/extensions/services/evol/web/src/styles/base.css +213 -0
  321. package/extensions/services/evol/web/src/styles/variables.css +138 -0
  322. package/extensions/services/evol/web/src/types/rpc.ts +35 -0
  323. package/extensions/services/evol/web/src/types/token.ts +87 -0
  324. package/extensions/services/evol/web/src/views/AccountView.vue +1532 -0
  325. package/extensions/services/evol/web/src/views/AiServiceView.vue +219 -0
  326. package/extensions/services/evol/web/src/views/CommissionView.vue +1220 -0
  327. package/extensions/services/evol/web/src/views/CreditsView.vue +131 -0
  328. package/extensions/services/evol/web/src/views/EndpointView.vue +163 -0
  329. package/extensions/services/evol/web/src/views/IframePage.vue +120 -0
  330. package/extensions/services/evol/web/src/views/TeamDetailView.vue +473 -0
  331. package/extensions/services/evol/web/src/views/TeamView.vue +332 -0
  332. package/extensions/services/evol/web/tsconfig.json +31 -0
  333. package/extensions/services/evol/web/tsconfig.node.json +10 -0
  334. package/extensions/services/evol/web/vite.config.ts +49 -0
  335. package/extensions/services/evolmem/__init__.py +0 -0
  336. package/extensions/services/evolmem/entry.py +387 -0
  337. package/extensions/services/evolmem/hooks/__init__.py +0 -0
  338. package/extensions/services/evolmem/hooks/assistant_stop.py +228 -0
  339. package/extensions/services/evolmem/hooks/common.py +76 -0
  340. package/extensions/services/evolmem/hooks/pre_tool_use.py +56 -0
  341. package/extensions/services/evolmem/hooks/session_end.py +133 -0
  342. package/extensions/services/evolmem/hooks/session_start.py +229 -0
  343. package/extensions/services/evolmem/hooks/user_prompt.py +122 -0
  344. package/extensions/services/evolmem/module.md +48 -0
  345. package/extensions/services/evolmem/prompts/00-server-info.md +28 -0
  346. package/extensions/services/evolmem/prompts/01-behavior.md +46 -0
  347. package/extensions/services/evolmem/prompts/02-summary-format.md +112 -0
  348. package/extensions/services/evolmem/prompts/03-file-query.md +92 -0
  349. package/extensions/services/evolmem/prompts/04-topic-stats.md +11 -0
  350. package/extensions/services/evolmem/prompts/05-recent-topics.md +84 -0
  351. package/extensions/services/evolmem/scripts/__init__.py +0 -0
  352. package/extensions/services/evolmem/scripts/extract_keywords.py +40 -0
  353. package/extensions/services/evolmem/scripts/search_topics.py +91 -0
  354. package/extensions/services/evolmem/server.py +641 -0
  355. package/extensions/services/gateway/entry.py +964 -0
  356. package/extensions/services/gateway/module.md +29 -0
  357. package/extensions/services/gateway/nonce_pool.py +65 -0
  358. package/extensions/services/gateway/relay.py +133 -0
  359. package/extensions/services/gateway/ws_server.py +285 -0
  360. package/extensions/services/kite_console/auth_manager.py +603 -0
  361. package/extensions/services/kite_console/config.json5 +19 -0
  362. package/extensions/services/kite_console/config_loader.py +117 -0
  363. package/extensions/services/kite_console/entry.py +528 -0
  364. package/extensions/services/kite_console/evol_api.py +179 -0
  365. package/extensions/services/kite_console/evol_config.json5 +29 -0
  366. package/extensions/services/kite_console/mfa_totp.py +77 -0
  367. package/extensions/services/kite_console/migrate_tokens.py +122 -0
  368. package/extensions/services/kite_console/module.md +37 -0
  369. package/extensions/services/kite_console/nonce_pool.py +113 -0
  370. package/extensions/services/kite_console/oauth_manager.py +223 -0
  371. package/extensions/services/kite_console/pairing.py +280 -0
  372. package/extensions/services/kite_console/pairing_codes.jsonl +2 -0
  373. package/extensions/services/kite_console/relay.py +1350 -0
  374. package/extensions/services/kite_console/relay_config.json5 +96 -0
  375. package/extensions/services/kite_console/routes/__init__.py +1 -0
  376. package/extensions/services/kite_console/routes/routes_llm.py +231 -0
  377. package/extensions/services/kite_console/routes/routes_proxy.py +115 -0
  378. package/extensions/services/kite_console/routes/routes_rpc.py +89 -0
  379. package/extensions/services/kite_console/routes/routes_test.py +68 -0
  380. package/extensions/services/kite_console/server.py +1742 -0
  381. package/extensions/services/{evol → kite_console}/static/css/style.css +656 -2
  382. package/extensions/services/kite_console/static/index.html +1524 -0
  383. package/extensions/services/{evol → kite_console}/static/js/dialog.js +11 -4
  384. package/extensions/services/kite_console/static/js/evol-app.js +7740 -0
  385. package/extensions/services/{evol/static/js/evol-app.js → kite_console/static/js/evol-app.js.backup} +2777 -1949
  386. package/extensions/services/kite_console/static/js/kernel-client.js +560 -0
  387. package/extensions/services/{evol/static/js/kernel-client.js → kite_console/static/js/kernel-client.js.backup} +41 -3
  388. package/extensions/services/{evol → kite_console}/static/js/registry-tests.js +7 -0
  389. package/extensions/services/kite_console/static/js/tests/ARCHITECTURE.md +67 -0
  390. package/extensions/services/kite_console/static/js/tests/README.md +140 -0
  391. package/extensions/services/kite_console/static/js/tests/index.js +161 -0
  392. package/extensions/services/kite_console/static/js/tests/integration/auth.js +120 -0
  393. package/extensions/services/kite_console/static/js/tests/integration/channel-interaction.js +188 -0
  394. package/extensions/services/kite_console/static/js/tests/integration/elastic-connection.js +115 -0
  395. package/extensions/services/kite_console/static/js/tests/integration/full-workflow.js +43 -0
  396. package/extensions/services/kite_console/static/js/tests/integration/multi-instance.js +304 -0
  397. package/extensions/services/kite_console/static/js/tests/integration/nested-rpc.js +266 -0
  398. package/extensions/services/kite_console/static/js/tests/integration/pingpong.js +25 -0
  399. package/extensions/services/kite_console/static/js/tests/integration/redis.js +227 -0
  400. package/extensions/services/kite_console/static/js/tests/integration/registry-core.js +52 -0
  401. package/extensions/services/kite_console/static/js/tests/integration/remote-deploy.js +85 -0
  402. package/extensions/services/kite_console/static/js/tests/integration/require-init.js +96 -0
  403. package/extensions/services/kite_console/static/js/tests/integration/scaling-control.js +193 -0
  404. package/extensions/services/kite_console/static/js/tests/integration/trace.js +109 -0
  405. package/extensions/services/kite_console/static/js/tests/modules/acp_channel.js +339 -0
  406. package/extensions/services/kite_console/static/js/tests/modules/auth.js +96 -0
  407. package/extensions/services/kite_console/static/js/tests/modules/backup.js +49 -0
  408. package/extensions/services/kite_console/static/js/tests/modules/gateway.js +41 -0
  409. package/extensions/services/kite_console/static/js/tests/modules/kernel.js +90 -0
  410. package/extensions/services/kite_console/static/js/tests/modules/launcher.js +75 -0
  411. package/extensions/services/kite_console/static/js/tests/modules/multi_instance.js +129 -0
  412. package/extensions/services/kite_console/static/js/tests/modules/phone_channel.js +364 -0
  413. package/extensions/services/kite_console/static/js/tests/modules/redis.js +178 -0
  414. package/extensions/services/kite_console/static/js/tests/modules/watchdog.js +60 -0
  415. package/extensions/services/kite_console/static/js/tests/modules/web.js +70 -0
  416. package/extensions/services/kite_console/static/js/tests/test-runner.js +123 -0
  417. package/extensions/services/kite_console/static/js/virtual-list.js +200 -0
  418. package/extensions/services/kite_console/static/test_kernel_client_token.html +352 -0
  419. package/extensions/services/kite_console/stats_manager.py +247 -0
  420. package/extensions/services/logs/README.md +215 -0
  421. package/extensions/services/logs/api_logger.py +37 -0
  422. package/extensions/services/logs/baseline.py +121 -0
  423. package/extensions/services/logs/cleaner.py +76 -0
  424. package/extensions/services/logs/entry.py +449 -0
  425. package/extensions/services/logs/formatter.py +129 -0
  426. package/extensions/services/logs/module.md +38 -0
  427. package/extensions/services/logs/quick_diagnostic.py +128 -0
  428. package/extensions/services/logs/routes/__init__.py +1 -0
  429. package/extensions/services/logs/routes/routes_logs.py +218 -0
  430. package/extensions/services/logs/routes/routes_logs.py.backup +173 -0
  431. package/extensions/services/logs/scanner.py +100 -0
  432. package/extensions/services/logs/searcher.py +263 -0
  433. package/extensions/services/logs/server.py +553 -0
  434. package/extensions/services/logs.zip +0 -0
  435. package/extensions/services/model_service/config.json5 +30 -0
  436. package/extensions/services/model_service/entry.py +620 -171
  437. package/extensions/services/model_service/module.md +11 -2
  438. package/extensions/services/proxy/__init__.py +0 -0
  439. package/extensions/services/proxy/aid_manager.py +419 -0
  440. package/extensions/services/proxy/auth_bridge.py +182 -0
  441. package/extensions/services/proxy/config_store.py +79 -0
  442. package/extensions/services/proxy/entry.py +528 -0
  443. package/extensions/services/proxy/evol/presenter/agentIdPresenter.py +2 -2
  444. package/extensions/services/proxy/evol/presenter/apikeyPresenter.py +18 -28
  445. package/extensions/services/proxy/evol/presenter/configPresenter.py +80 -1127
  446. package/extensions/services/proxy/evol/presenter/userPresenter.py +71 -477
  447. package/extensions/services/proxy/evol/server/claude_proxy_async.py +11 -7
  448. package/extensions/services/proxy/module.md +151 -0
  449. package/extensions/services/proxy/server.py +952 -271
  450. package/extensions/services/redis/ALIGNMENT_CHECKLIST.md +121 -0
  451. package/extensions/services/redis/ALIGNMENT_STATUS.md +548 -0
  452. package/extensions/services/redis/config.json5 +8 -0
  453. package/extensions/services/redis/entry.py +1509 -0
  454. package/extensions/services/redis/entry.py.backup +405 -0
  455. package/extensions/services/redis/module.md +48 -0
  456. package/extensions/services/redis/redis_builtin.py +332 -0
  457. package/extensions/services/redis/redis_external.py +164 -0
  458. package/extensions/services/testUi/entry.py +446 -0
  459. package/extensions/services/testUi/module.md +18 -0
  460. package/extensions/services/testUi/ui/cards.html +131 -0
  461. package/extensions/services/testUi/ui/index.html +22 -0
  462. package/extensions/services/testUi/ui/particles.html +143 -0
  463. package/extensions/services/watchdog/entry.py +1258 -793
  464. package/extensions/services/watchdog/module.md +2 -0
  465. package/extensions/services/watchdog/monitor.py +465 -87
  466. package/extensions/services/web/auth_manager.py +602 -0
  467. package/extensions/services/web/config.json5 +11 -0
  468. package/extensions/services/web/entry.py +598 -478
  469. package/extensions/services/web/mfa_totp.py +77 -0
  470. package/extensions/services/web/module.md +16 -13
  471. package/extensions/services/web/nonce_pool.py +113 -0
  472. package/extensions/services/web/oauth_manager.py +223 -0
  473. package/extensions/services/web/pairing.py +3 -2
  474. package/extensions/services/web/pairing_codes.jsonl +1 -0
  475. package/extensions/services/web/relay.py +442 -63
  476. package/extensions/services/web/relay_config.json5 +1 -2
  477. package/extensions/services/web/routes/routes_rpc.py +6 -6
  478. package/extensions/services/web/server.py +360 -173
  479. package/extensions/services/web/static/index.html +1752 -1738
  480. package/extensions/services/web/static/js/app.js +32 -0
  481. package/extensions/services/web/static/js/kernel-client.js +48 -9
  482. package/extensions/services/web/vendor/bluetooth/audio.py +1 -1
  483. package/extensions/services/web/vendor/config.py +2 -2
  484. package/extensions/services/web/vendor/storage/identity.py +1 -1
  485. package/kernel/entry.py +77 -23
  486. package/kernel/event_hub.py +1122 -74
  487. package/kernel/module.md +2 -1
  488. package/kernel/registry_store.py +208 -11
  489. package/kernel/rpc_router.py +1400 -491
  490. package/kernel/server.py +1021 -134
  491. package/kite_cli/builders/__init__.py +4 -0
  492. package/kite_cli/builders/base.py +67 -0
  493. package/kite_cli/builders/custom.py +31 -0
  494. package/kite_cli/builders/detector.py +56 -0
  495. package/kite_cli/builders/go.py +34 -0
  496. package/kite_cli/builders/gradle.py +41 -0
  497. package/kite_cli/builders/maven.py +36 -0
  498. package/kite_cli/builders/npm.py +44 -0
  499. package/kite_cli/builders/python.py +37 -0
  500. package/kite_cli/commands/BUILD_GUIDE.md +109 -0
  501. package/kite_cli/commands/build.py +142 -0
  502. package/kite_cli/commands/check.py +60 -0
  503. package/kite_cli/commands/config.py +156 -0
  504. package/kite_cli/commands/deps.py +58 -0
  505. package/kite_cli/commands/deps_install.py +7 -7
  506. package/kite_cli/commands/disable.py +162 -0
  507. package/kite_cli/commands/enable.py +162 -0
  508. package/kite_cli/commands/export.py +96 -0
  509. package/kite_cli/commands/import_cmd.py +110 -0
  510. package/kite_cli/commands/install.py +50 -23
  511. package/kite_cli/commands/install_skill.py +107 -0
  512. package/kite_cli/commands/list.py +128 -31
  513. package/kite_cli/commands/outdated.py +202 -0
  514. package/kite_cli/commands/search.py +33 -17
  515. package/kite_cli/commands/update.py +115 -2
  516. package/kite_cli/commands/venv_setup.py +6 -6
  517. package/kite_cli/commands/why.py +48 -0
  518. package/kite_cli/core/config_manager.py +145 -0
  519. package/kite_cli/core/downloader.py +32 -2
  520. package/kite_cli/main.py +151 -5
  521. package/kite_cli/utils/colors.py +153 -0
  522. package/kite_cli/utils/dependency_graph.py +209 -0
  523. package/kite_cli/utils/process.py +55 -0
  524. package/kite_cli/utils/progress.py +207 -0
  525. package/kite_cli/utils/table.py +101 -0
  526. package/launcher/count_lines.py +192 -43
  527. package/launcher/entry.py +4543 -2802
  528. package/launcher/logging_setup.py +54 -1
  529. package/launcher/module.md +32 -6
  530. package/launcher/module_scanner.py +93 -20
  531. package/launcher/process_manager.py +355 -76
  532. package/main.py +6 -0
  533. package/package.json +4 -1
  534. package/requirements.txt +41 -38
  535. package/scripts/auto-fix-deps.py +128 -0
  536. package/scripts/env-manager.js +25 -2
  537. package/scripts/final-test.js +78 -0
  538. package/scripts/setup-python-env.js +700 -191
  539. package/scripts/test-alluser.js +48 -0
  540. package/scripts/test-different-version.js +86 -0
  541. package/scripts/test-direct.js +63 -0
  542. package/scripts/test-extract-installer.js +28 -0
  543. package/scripts/test-install-log.js +54 -0
  544. package/scripts/test-installer.js +39 -0
  545. package/scripts/test-integration.js +250 -0
  546. package/scripts/test-real-install.js +210 -0
  547. package/scripts/test-targetdir.js +49 -0
  548. package/scripts/test-venv-real.js +47 -0
  549. package/scripts/test-venv-simple.js +57 -0
  550. package/scripts/test-wait.js +49 -0
  551. package/scripts/test-with-log.js +63 -0
  552. package/extensions/services/evol/config.yaml +0 -149
  553. package/extensions/services/evol/routes/routes_management_ws.py +0 -127
  554. package/extensions/services/evol/static/index_evol.html +0 -14
  555. package/extensions/services/evol/static/js/app.js +0 -6304
  556. package/extensions/services/evol/static/js/auth.js +0 -326
  557. package/extensions/services/evol/static/js/evol-app-fixed.js +0 -50
  558. package/extensions/services/evol/static/js/evol-app.js.bak +0 -1800
  559. package/extensions/services/evol/static/js/kernel-client-example.js +0 -228
  560. package/extensions/services/evol/static/js/main.js +0 -141
  561. package/extensions/services/evol/static/js/stats.js +0 -217
  562. package/extensions/services/evol/static/js/token-manager.js +0 -175
  563. package/extensions/services/proxy/CHANGELOG_20260308.md +0 -258
  564. package/extensions/services/proxy/_fix_prints.py +0 -133
  565. package/extensions/services/proxy/_fix_prints2.py +0 -87
  566. package/extensions/services/proxy/console_auth.py +0 -109
  567. package/extensions/services/proxy/logs/websocket.log +0 -260
  568. package/extensions/services/proxy/main.py +0 -240
  569. package/extensions/services/proxy/requirements.txt +0 -13
  570. package/extensions/services/web/config.yaml +0 -149
  571. /package/extensions/services/{evol → kite_console}/static/pairing.html +0 -0
  572. /package/extensions/services/{evol → kite_console}/static/test_registry.html +0 -0
  573. /package/extensions/services/{evol → kite_console}/static/test_relay.html +0 -0
@@ -1,1800 +0,0 @@
1
- // Evol App - Main Application Logic
2
-
3
- class EvolApp {
4
- constructor() {
5
- // 优先从 Cookie 恢复 kiteToken(防止 Ctrl+F5 清除 localStorage)
6
- this.kiteToken = this._getKiteToken();
7
- this.userInfo = null;
8
- this.ws = null;
9
- this.wsConnected = false;
10
- this.currentPage = 'account';
11
- this.deviceInfo = this._getDeviceInfo();
12
- this.statsRefreshTimer = null;
13
- this.moduleActionPending = new Map(); // 模块操作防抖
14
- this.currentModuleName = null; // 当前查看的模块名
15
-
16
- // 事件日志相关
17
- this.eventLogs = []; // 存储所有事件日志 {timestamp, module, event, data, raw}
18
- this.consoleExpanded = false; // 控制台是否展开
19
- this.eventSubscribed = false; // 是否已订阅全部事件
20
- this.knownModules = new Set(); // 已知的模块列表
21
- this.knownEvents = new Set(); // 已知的事件类型
22
- }
23
-
24
- _getKiteToken() {
25
- // 1. 先从 localStorage 读取
26
- let token = localStorage.getItem('kiteToken');
27
- if (token) return token;
28
-
29
- // 2. 如果 localStorage 没有,尝试从 Cookie 恢复
30
- token = this._getCookie('kiteToken');
31
- if (token) {
32
- // 恢复到 localStorage
33
- localStorage.setItem('kiteToken', token);
34
- console.log('Restored kiteToken from cookie');
35
- return token;
36
- }
37
-
38
- return null;
39
- }
40
-
41
- _getCookie(name) {
42
- const value = `; ${document.cookie}`;
43
- const parts = value.split(`; ${name}=`);
44
- if (parts.length === 2) return parts.pop().split(';').shift();
45
- return null;
46
- }
47
-
48
- _setCookie(name, value, days = 30) {
49
- const expires = new Date(Date.now() + days * 864e5).toUTCString();
50
- document.cookie = `${name}=${value}; expires=${expires}; path=/; SameSite=Strict`;
51
- }
52
-
53
- _saveKiteToken(token) {
54
- // 同时保存到 localStorage 和 Cookie
55
- localStorage.setItem('kiteToken', token);
56
- this._setCookie('kiteToken', token, 30);
57
- }
58
-
59
- _clearKiteToken() {
60
- // 同时清除 localStorage 和 Cookie
61
- localStorage.removeItem('kiteToken');
62
- this._setCookie('kiteToken', '', -1);
63
- }
64
-
65
- _getDeviceInfo() {
66
- // 生成或获取持久化的设备 ID
67
- let deviceId = localStorage.getItem('deviceId');
68
- if (!deviceId) {
69
- deviceId = 'device_' + this._randomString(16) + '_' + Date.now();
70
- localStorage.setItem('deviceId', deviceId);
71
- }
72
-
73
- // 检测设备类型和名称
74
- const ua = navigator.userAgent;
75
- let deviceType = 'Desktop';
76
- let osName = 'Unknown OS';
77
-
78
- if (/Android/i.test(ua)) {
79
- deviceType = 'Mobile';
80
- osName = 'Android';
81
- } else if (/iPhone|iPad|iPod/i.test(ua)) {
82
- deviceType = 'Mobile';
83
- osName = 'iOS';
84
- } else if (/Windows/i.test(ua)) {
85
- osName = 'Windows';
86
- } else if (/Mac/i.test(ua)) {
87
- osName = 'macOS';
88
- } else if (/Linux/i.test(ua)) {
89
- osName = 'Linux';
90
- }
91
-
92
- let browserName = 'Unknown Browser';
93
- if (/Chrome/i.test(ua) && !/Edge/i.test(ua)) {
94
- browserName = 'Chrome';
95
- } else if (/Firefox/i.test(ua)) {
96
- browserName = 'Firefox';
97
- } else if (/Safari/i.test(ua) && !/Chrome/i.test(ua)) {
98
- browserName = 'Safari';
99
- } else if (/Edge/i.test(ua)) {
100
- browserName = 'Edge';
101
- }
102
-
103
- return {
104
- deviceId: deviceId,
105
- deviceName: `${browserName} on ${osName}`,
106
- deviceType: deviceType,
107
- browser: browserName,
108
- os: osName,
109
- userAgent: ua
110
- };
111
- }
112
-
113
- _randomString(length) {
114
- const chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
115
- let result = '';
116
- for (let i = 0; i < length; i++) {
117
- result += chars.charAt(Math.floor(Math.random() * chars.length));
118
- }
119
- return result;
120
- }
121
-
122
- async init() {
123
- if (this.kiteToken) {
124
- // 有 kiteToken,立即显示主界面和占位信息
125
- this.showMainApp();
126
- this.showUserInfoPlaceholder();
127
-
128
- // 异步加载 Evol 账户信息(不阻塞,失败不影响主界面)
129
- this.loadUserInfo().catch(err => {
130
- console.warn('Failed to load Evol user info:', err);
131
- // evolToken 失效,显示提示但不影响 Kite 功能
132
- this.showEvolTokenWarning();
133
- });
134
- } else {
135
- // 没有 kiteToken,显示登录页
136
- this.showLoginPage();
137
- }
138
- }
139
-
140
- showUserInfoPlaceholder() {
141
- // 立即显示占位信息,避免延迟
142
- const loginBtn = document.getElementById('login-btn');
143
- const userInfoArea = document.getElementById('user-info-area');
144
-
145
- if (loginBtn) loginBtn.classList.add('hidden');
146
- if (userInfoArea) {
147
- userInfoArea.classList.remove('hidden');
148
- userInfoArea.style.display = 'flex';
149
-
150
- // 显示加载中占位
151
- const userNameEl = userInfoArea.querySelector('.user-name');
152
- const creditsEl = userInfoArea.querySelector('.user-credits');
153
- if (userNameEl) userNameEl.textContent = '加载中...';
154
- if (creditsEl) creditsEl.textContent = '';
155
- }
156
- }
157
-
158
- showLoginPage() {
159
- // 移除 has-token 类,触发 CSS 切换
160
- document.documentElement.classList.remove('has-token');
161
- document.getElementById('login-page').classList.remove('hidden');
162
- document.getElementById('main-app').classList.add('hidden');
163
- }
164
-
165
- showMainApp() {
166
- // 添加 has-token 类,触发 CSS 切换
167
- document.documentElement.classList.add('has-token');
168
- document.getElementById('login-page').classList.add('hidden');
169
- document.getElementById('main-app').classList.remove('hidden');
170
- this.initMainApp();
171
- }
172
-
173
- async loadUserInfo() {
174
- try {
175
- const res = await fetch('/api/get_user_info', {
176
- method: 'POST',
177
- headers: { 'Content-Type': 'application/json' },
178
- body: JSON.stringify({ kiteToken: this.kiteToken })
179
- });
180
- const data = await res.json();
181
-
182
- if (data.success) {
183
- this.userInfo = data.data;
184
- this.updateUserInfoDisplay();
185
- // 更新账户信息页面
186
- this.loadAccountInfo();
187
- } else if (data.code === 'INVALID_KITE_TOKEN') {
188
- // kiteToken 失效,需要重新配对
189
- console.warn('kiteToken invalid, need re-pairing');
190
- this._clearKiteToken();
191
- this.kiteToken = null;
192
- this.showLoginPage();
193
- throw new Error('KITE_TOKEN_INVALID');
194
- } else {
195
- // evolToken 失效或其他错误,不影响 Kite 功能
196
- throw new Error(data.message || 'EVOL_TOKEN_INVALID');
197
- }
198
- } catch (err) {
199
- console.error('Load user info failed:', err);
200
- throw err;
201
- }
202
- }
203
-
204
- updateUserInfoDisplay() {
205
- // 更新右上角用户信息显示
206
- if (this.userInfo) {
207
- const userInfo = this.userInfo.userInfo || this.userInfo;
208
- const accountInfo = this.userInfo.accountInfo || {};
209
-
210
- // 显示用户信息区域
211
- const loginBtn = document.getElementById('login-btn');
212
- const userInfoArea = document.getElementById('user-info-area');
213
-
214
- if (loginBtn) loginBtn.classList.add('hidden');
215
- if (userInfoArea) {
216
- userInfoArea.classList.remove('hidden');
217
- userInfoArea.style.display = 'flex';
218
-
219
- // 更新用户名
220
- const userNameEl = userInfoArea.querySelector('.user-name');
221
- if (userNameEl) {
222
- userNameEl.textContent = userInfo.nickName || userInfo.userName || '未知用户';
223
- }
224
-
225
- // 更新积分
226
- const creditsEl = userInfoArea.querySelector('.user-credits');
227
- if (creditsEl) {
228
- creditsEl.textContent = `积分: ${accountInfo.credits || 0}`;
229
- }
230
- }
231
- }
232
- }
233
-
234
- showEvolTokenWarning() {
235
- // 右上角显示 Evol 未登录状态
236
- const loginBtn = document.getElementById('login-btn');
237
- const userInfoArea = document.getElementById('user-info-area');
238
-
239
- if (loginBtn) {
240
- loginBtn.classList.remove('hidden');
241
- loginBtn.style.display = 'inline';
242
- loginBtn.textContent = '⚠️ 未登录 Evol';
243
- loginBtn.style.color = '#ff9800';
244
- loginBtn.style.fontWeight = '500';
245
- }
246
- if (userInfoArea) {
247
- userInfoArea.classList.add('hidden');
248
- userInfoArea.style.display = 'none';
249
- }
250
-
251
- // 绑定右上角登录按钮点击事件
252
- if (loginBtn) {
253
- loginBtn.onclick = (e) => {
254
- e.preventDefault();
255
- this.logout();
256
- };
257
- }
258
- }
259
-
260
- async sendSMS(phone) {
261
- const res = await fetch('/api/send_sms', {
262
- method: 'POST',
263
- headers: { 'Content-Type': 'application/json' },
264
- body: JSON.stringify({ phone })
265
- });
266
- return await res.json();
267
- }
268
-
269
- async login(phone, code) {
270
- const res = await fetch('/api/verify_sms', {
271
- method: 'POST',
272
- headers: { 'Content-Type': 'application/json' },
273
- body: JSON.stringify({ phone, code, deviceInfo: this.deviceInfo })
274
- });
275
- const data = await res.json();
276
-
277
- if (data.success) {
278
- this.kiteToken = data.kiteToken;
279
- this.userInfo = data.data;
280
- this._saveKiteToken(this.kiteToken);
281
- this.showMainApp();
282
- // 登录成功后立即更新用户信息显示
283
- this.updateUserInfoDisplay();
284
- // 更新账户信息页面
285
- this.updateAccountPage();
286
- }
287
-
288
- return data;
289
- }
290
-
291
- async logout() {
292
- try {
293
- await fetch('/api/logout', {
294
- method: 'POST',
295
- headers: { 'Content-Type': 'application/json' },
296
- body: JSON.stringify({ kiteToken: this.kiteToken })
297
- });
298
- } catch (err) {}
299
-
300
- this._clearKiteToken();
301
- location.reload();
302
- }
303
-
304
- initMainApp() {
305
- // 初始化 Kernel 客户端和导航
306
- this.wsRetryCount = 0;
307
- this.wsMaxRetries = 6;
308
- this.wsRetryDelay = 1000; // 初始延迟 1 秒
309
- this.wsGaveUp = false;
310
- this.initKernelClient();
311
- this.loadAccountInfo();
312
- this.setupNavigation();
313
-
314
- // 监听页面可见性变化,页面重新可见时如果已放弃则重新连接
315
- document.addEventListener('visibilitychange', () => {
316
- if (!document.hidden && this.wsGaveUp) {
317
- console.log('[Evol] Page visible again, retrying connection');
318
- this.wsGaveUp = false;
319
- this.wsRetryCount = 0;
320
- this.wsRetryDelay = 1000;
321
- this.initKernelClient();
322
- }
323
- });
324
- }
325
-
326
- updateWsIndicator(status, text, color) {
327
- const indicator = document.getElementById('ws-indicator');
328
- if (indicator) {
329
- indicator.innerHTML = `${status} ${text}`;
330
- indicator.style.color = color;
331
- }
332
- }
333
-
334
- initKernelClient() {
335
- // 如果已放弃,不再重试(除非用户主动触发)
336
- if (this.wsGaveUp) {
337
- return;
338
- }
339
-
340
- const proto = location.protocol === 'https:' ? 'wss:' : 'ws:';
341
- const url = `${proto}//${location.host}/ws/management`;
342
-
343
- console.log('[Evol] Connecting to', url, `(attempt ${this.wsRetryCount + 1}/${this.wsMaxRetries})`);
344
-
345
- // 显示连接中状态
346
- if (this.wsRetryCount === 0) {
347
- this.updateWsIndicator('◐', '连接中...', '#ff9800');
348
- } else {
349
- this.updateWsIndicator('◐', `重连中... (${this.wsRetryCount}/${this.wsMaxRetries})`, '#ff9800');
350
- }
351
-
352
- this.ws = new WebSocket(url);
353
-
354
- this.ws.onopen = () => {
355
- console.log('[Evol] WebSocket connected');
356
- this.wsConnected = true;
357
- this.wsRetryCount = 0;
358
- this.wsRetryDelay = 1000;
359
- this.updateWsIndicator('●', 'Kite 已连接', '#27ae60');
360
- };
361
-
362
- this.ws.onerror = (error) => {
363
- console.error('[Evol] WebSocket error:', error);
364
- };
365
-
366
- this.ws.onclose = () => {
367
- console.log('[Evol] WebSocket closed');
368
- this.wsConnected = false;
369
-
370
- // 检查是否已达到最大重试次数
371
- if (this.wsRetryCount >= this.wsMaxRetries) {
372
- console.log('[Evol] Max retries reached, giving up');
373
- this.wsGaveUp = true;
374
- this.updateWsIndicator('✕', '已断开', '#e74c3c');
375
- return;
376
- }
377
-
378
- // 指数退避重试
379
- this.wsRetryCount++;
380
- const delay = Math.min(this.wsRetryDelay * Math.pow(2, this.wsRetryCount - 1), 30000);
381
- console.log(`[Evol] Retrying in ${delay}ms...`);
382
-
383
- setTimeout(() => this.initKernelClient(), delay);
384
- };
385
-
386
- this.ws.onmessage = (event) => {
387
- try {
388
- const msg = JSON.parse(event.data);
389
-
390
- // 处理事件通知
391
- if (msg.type === 'event' && msg.event) {
392
- // 如果控制台展开,添加到事件日志
393
- if (this.consoleExpanded) {
394
- this.addEventLog(msg.event, msg.data || {});
395
- }
396
-
397
- // 刷新模块列表(仅针对 module.* 事件)
398
- if (msg.event.startsWith('module.') && this.currentPage === 'modules') {
399
- this.loadModules();
400
- }
401
- }
402
- } catch (e) {
403
- console.error('[Evol] Message parse error:', e);
404
- }
405
- };
406
- }
407
-
408
- async callRpc(method, params = {}) {
409
- try {
410
- const res = await fetch(`/api/rpc/${method}`, {
411
- method: 'POST',
412
- headers: { 'Content-Type': 'application/json' },
413
- body: JSON.stringify(params)
414
- });
415
-
416
- if (!res.ok) {
417
- const error = await res.json();
418
- throw new Error(error.detail || `HTTP ${res.status}`);
419
- }
420
-
421
- return await res.json();
422
- } catch (err) {
423
- console.error(`[Evol] RPC ${method} failed:`, err);
424
- throw err;
425
- }
426
- }
427
-
428
- setupNavigation() {
429
- const navItems = document.querySelectorAll('.nav-item');
430
- const pages = document.querySelectorAll('.page');
431
-
432
- navItems.forEach(item => {
433
- item.addEventListener('click', () => {
434
- const pageName = item.dataset.page;
435
- this.currentPage = pageName;
436
-
437
- navItems.forEach(i => i.classList.remove('active'));
438
- pages.forEach(p => p.classList.remove('active'));
439
-
440
- item.classList.add('active');
441
- document.getElementById('page-' + pageName).classList.add('active');
442
-
443
- if (pageName === 'modules') this.loadModules();
444
- else if (pageName === 'credits') this.loadCreditsStats();
445
- else if (pageName === 'tokens') this.loadTokens();
446
- });
447
- });
448
-
449
- document.getElementById('sidebar-toggle').addEventListener('click', () => {
450
- document.getElementById('sidebar').classList.toggle('collapsed');
451
- });
452
- }
453
-
454
- loadAccountInfo() {
455
- // 如果 userInfo 还没加载,显示加载中
456
- if (!this.userInfo) {
457
- const accountInfoEl = document.getElementById('account-info');
458
- if (accountInfoEl) {
459
- accountInfoEl.innerHTML = '<div style="padding:20px;text-align:center;color:#999;">加载中...</div>';
460
- }
461
- return;
462
- }
463
-
464
- const ui = this.userInfo.userInfo || {};
465
- const ai = this.userInfo.accountInfo || {};
466
- const ti = this.userInfo.teamInfo || {};
467
- const gi = this.userInfo.gatewayInfo || {};
468
-
469
- // 格式化 VIP 过期时间
470
- const formatDate = (dateStr) => {
471
- if (!dateStr) return '-';
472
- const date = new Date(dateStr);
473
- return date.toLocaleDateString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit' });
474
- };
475
-
476
- // 积分包汇总
477
- const pkg = ai.creditsPackageSummary || {};
478
- const packageInfo = pkg.totalPackageCount > 0
479
- ? `共 ${pkg.totalPackageCount} 个积分包`
480
- : '无积分包';
481
-
482
- const html = `
483
- <div style="display:grid;grid-template-columns:repeat(2,1fr);gap:20px;">
484
- <!-- 基本信息 -->
485
- <div style="background:#f9f9f9;padding:16px;border-radius:6px;">
486
- <h3 style="margin:0 0 12px 0;font-size:14px;font-weight:600;color:#666;">基本信息</h3>
487
- <table style="width:100%;border-collapse:collapse;font-size:13px;">
488
- <tr><td style="padding:8px 0;color:#666;">手机号</td><td style="padding:8px 0;font-weight:500;">${ui.phone || '-'}</td></tr>
489
- <tr><td style="padding:8px 0;color:#666;">昵称</td><td style="padding:8px 0;font-weight:500;">${ui.nickName || '-'}</td></tr>
490
- <tr><td style="padding:8px 0;color:#666;">用户ID</td><td style="padding:8px 0;font-weight:500;">${ui.userId || '-'}</td></tr>
491
- <tr><td style="padding:8px 0;color:#666;">AID</td><td style="padding:8px 0;font-family:monospace;font-size:11px;">${ui.aid || '-'}</td></tr>
492
- </table>
493
- </div>
494
-
495
- <!-- 积分信息 -->
496
- <div style="background:#f9f9f9;padding:16px;border-radius:6px;">
497
- <h3 style="margin:0 0 12px 0;font-size:14px;font-weight:600;color:#666;">积分信息</h3>
498
- <table style="width:100%;border-collapse:collapse;font-size:13px;">
499
- <tr><td style="padding:8px 0;color:#666;">当前积分</td><td style="padding:8px 0;font-weight:600;color:#27ae60;font-size:16px;">${ai.credits || 0}</td></tr>
500
- <tr><td style="padding:8px 0;color:#666;">积分上限</td><td style="padding:8px 0;font-weight:500;">${ai.creditsLimit || 0}</td></tr>
501
- <tr><td style="padding:8px 0;color:#666;">恢复速率</td><td style="padding:8px 0;font-weight:500;">${ai.creditsRecoveryRate || 0} / 小时</td></tr>
502
- <tr><td style="padding:8px 0;color:#666;">积分包</td><td style="padding:8px 0;font-weight:500;">${packageInfo}</td></tr>
503
- </table>
504
- </div>
505
-
506
- <!-- VIP 信息 -->
507
- <div style="background:#f9f9f9;padding:16px;border-radius:6px;">
508
- <h3 style="margin:0 0 12px 0;font-size:14px;font-weight:600;color:#666;">VIP 信息</h3>
509
- <table style="width:100%;border-collapse:collapse;font-size:13px;">
510
- <tr><td style="padding:8px 0;color:#666;">VIP 类型</td><td style="padding:8px 0;font-weight:500;">${ai.vipTypeName || 'Unknown'}</td></tr>
511
- <tr><td style="padding:8px 0;color:#666;">过期时间</td><td style="padding:8px 0;font-weight:500;">${formatDate(ai.vipExpireTime)}</td></tr>
512
- <tr><td style="padding:8px 0;color:#666;">剩余天数</td><td style="padding:8px 0;font-weight:600;color:#ff9800;">${ai.vipRemainingDays || 0} 天</td></tr>
513
- <tr><td style="padding:8px 0;color:#666;">账户余额</td><td style="padding:8px 0;font-weight:500;">¥ ${(ai.balance || 0).toFixed(2)}</td></tr>
514
- </table>
515
- </div>
516
-
517
- <!-- 团队信息 -->
518
- <div style="background:#f9f9f9;padding:16px;border-radius:6px;">
519
- <h3 style="margin:0 0 12px 0;font-size:14px;font-weight:600;color:#666;">团队信息</h3>
520
- <table style="width:100%;border-collapse:collapse;font-size:13px;">
521
- <tr><td style="padding:8px 0;color:#666;">当前团队</td><td style="padding:8px 0;font-weight:500;">${ti.currentTeamName || '-'}</td></tr>
522
- <tr><td style="padding:8px 0;color:#666;">团队角色</td><td style="padding:8px 0;font-weight:500;">${ti.currentTeamRole === '1' ? '管理员' : '成员'}</td></tr>
523
- <tr><td style="padding:8px 0;color:#666;">团队数量</td><td style="padding:8px 0;font-weight:500;">${(ti.teams || []).length} 个</td></tr>
524
- </table>
525
- </div>
526
-
527
- <!-- 网关信息 -->
528
- <div style="background:#f9f9f9;padding:16px;border-radius:6px;grid-column:1/-1;">
529
- <h3 style="margin:0 0 12px 0;font-size:14px;font-weight:600;color:#666;">网关信息</h3>
530
- <table style="width:100%;border-collapse:collapse;font-size:13px;">
531
- <tr><td style="padding:8px 0;color:#666;width:120px;">网关名称</td><td style="padding:8px 0;font-weight:500;">${gi.gatewayName || '-'}</td></tr>
532
- <tr><td style="padding:8px 0;color:#666;">模型地址</td><td style="padding:8px 0;font-family:monospace;font-size:11px;">${gi.modelBaseUrl || '-'}</td></tr>
533
- <tr><td style="padding:8px 0;color:#666;">API Key</td><td style="padding:8px 0;"><code style="background:#fff;padding:4px 8px;border-radius:4px;font-size:11px;">${gi.apiKey || '未获取'}</code></td></tr>
534
- </table>
535
- </div>
536
- </div>
537
- `;
538
- document.getElementById('account-info').innerHTML = html;
539
- }
540
-
541
- async loadCreditsStats() {
542
- try {
543
- const res = await fetch('/api/get_credits_stats', {
544
- method: 'POST',
545
- headers: { 'Content-Type': 'application/json' },
546
- body: JSON.stringify({ kiteToken: this.kiteToken, period: 'day' })
547
- });
548
- const data = await res.json();
549
-
550
- if (data.success) {
551
- const html = '<h4>今日积分消耗</h4><p style="font-size:24px;font-weight:600;color:#667eea;">' +
552
- (data.data?.total || 0) + ' 积分</p>';
553
- document.getElementById('credits-stats').innerHTML = html;
554
- } else {
555
- document.getElementById('credits-stats').innerHTML = '<p style="color:#e74c3c;">' + data.msg + '</p>';
556
- }
557
- } catch (err) {
558
- document.getElementById('credits-stats').innerHTML = '<p style="color:#e74c3c;">加载失败</p>';
559
- }
560
- }
561
-
562
- async loadModules() {
563
- // Reset to list view
564
- document.getElementById('modules-list-header')?.classList.remove('hidden');
565
- document.getElementById('modules-table')?.closest('.panel')?.classList.remove('hidden');
566
- document.getElementById('module-detail')?.classList.add('hidden');
567
- document.getElementById('statistics-panel')?.classList.remove('hidden');
568
- document.getElementById('registry-test-section')?.classList.remove('hidden');
569
- document.getElementById('registry-test-output')?.classList.remove('hidden');
570
-
571
- // Load statistics and start auto-refresh
572
- this.loadModuleStats();
573
- this.startStatsAutoRefresh();
574
-
575
- try {
576
- // 获取模块列表和运行状态
577
- const result = await this.callRpc('launcher.list_modules', {});
578
- const modules = result.modules || [];
579
-
580
- const tbody = document.getElementById('modules-tbody');
581
- if (modules.length === 0) {
582
- tbody.innerHTML = '<tr><td colspan="9" class="text-muted" style="text-align:center;padding:40px;">暂无模块</td></tr>';
583
- return;
584
- }
585
-
586
- let html = '';
587
- modules.forEach(mod => {
588
- // 状态圆点
589
- const stateClass = mod.state === 'enabled' ? 'enabled' : mod.state === 'manual' ? 'manual' : 'disabled';
590
-
591
- // 运行状态判断
592
- const running = mod.actual_state ? mod.actual_state.startsWith('running') : false;
593
- const pending = this.moduleActionPending.has(mod.name);
594
- const pendingAction = this.moduleActionPending.get(mod.name);
595
-
596
- const runningStatus = pending
597
- ? `<span style="color:var(--warning);">${pendingAction === 'start' ? '启动中…' : '停止中…'}</span>`
598
- : running
599
- ? '<span style="color:var(--success);">运行中</span>'
600
- : '<span style="color:var(--gray-400);">已停止</span>';
601
-
602
- // 默认状态下拉选项
603
- const stateOptions = `
604
- <option value="enabled" ${mod.state === 'enabled' ? 'selected' : ''}>自动</option>
605
- <option value="manual" ${mod.state === 'manual' ? 'selected' : ''}>手动</option>
606
- <option value="disabled" ${mod.state === 'disabled' ? 'selected' : ''}>禁用</option>
607
- `;
608
-
609
- // 统一操作按钮逻辑
610
- const isCore = ['kernel', 'launcher'].includes(mod.name);
611
- const displayOrder = mod.display_order || 0;
612
- const isHighOrder = displayOrder >= 80;
613
- const isDisabledState = mod.state === 'disabled';
614
-
615
- // 完全禁止操作的条件:核心模块 或 display_order>=80 或 disabled状态
616
- const fullyDisabled = isCore || isHighOrder || isDisabledState;
617
-
618
- let btnClass, btnLabel, btnAction, btnDisabled;
619
-
620
- if (fullyDisabled) {
621
- // 完全禁用
622
- btnClass = 'btn-secondary';
623
- btnLabel = '禁用';
624
- btnAction = '';
625
- btnDisabled = 'disabled';
626
- } else if (pending) {
627
- // 操作中
628
- btnClass = pendingAction === 'start' ? 'btn-warning' : 'btn-warning';
629
- btnLabel = pendingAction === 'start' ? '启动中…' : '停止中…';
630
- btnAction = '';
631
- btnDisabled = 'disabled';
632
- } else if (running) {
633
- // 运行中 → 可停止
634
- btnClass = 'btn-danger';
635
- btnLabel = '停止';
636
- btnAction = `onclick="app.stopModule('${mod.name}')"`;
637
- btnDisabled = '';
638
- } else {
639
- // 已停止 → 可启动
640
- btnClass = 'btn-success';
641
- btnLabel = '启动';
642
- btnAction = `onclick="app.startModule('${mod.name}')"`;
643
- btnDisabled = '';
644
- }
645
-
646
- html += `<tr data-module="${mod.name}" class="module-row" onclick="app.showModuleDetails('${mod.name}')">
647
- <td><span class="module-state-dot ${stateClass}"></span></td>
648
- <td><strong>${mod.display_name || mod.name}</strong> <span style="color:#999;font-size:12px;">(${mod.name})</span></td>
649
- <td><span class="module-type-badge type-${mod.type || 'unknown'}">${mod.type || '?'}</span></td>
650
- <td>${mod.version || '-'}</td>
651
- <td>${mod.preferred_port || '-'}</td>
652
- <td>${runningStatus}</td>
653
- <td onclick="event.stopPropagation()">
654
- <select class="module-state-select" data-module="${mod.name}" onchange="app.onModuleStateChange(this)">
655
- ${stateOptions}
656
- </select>
657
- </td>
658
- <td onclick="event.stopPropagation()">
659
- <button class="btn btn-sm ${btnClass}" ${btnAction} ${btnDisabled}>${btnLabel}</button>
660
- </td>
661
- </tr>`;
662
- });
663
-
664
- tbody.innerHTML = html;
665
- } catch (err) {
666
- console.error('[Evol] Load modules failed:', err);
667
- document.getElementById('modules-tbody').innerHTML =
668
- `<tr><td colspan="8" style="text-align:center;padding:40px;color:#e74c3c;">加载失败: ${err.message}</td></tr>`;
669
- }
670
- }
671
-
672
- async loadModuleStats() {
673
- try {
674
- // 对齐 Web 模块:使用 kernel.health 获取运行时长
675
- const health = await this.callRpc('kernel.health', {});
676
- const eventStats = health.event_stats || {};
677
-
678
- // 对齐 Web 模块:使用 kernel.stats 获取统计数据
679
- const stats = await this.callRpc('kernel.stats', {});
680
- const counters = stats.counters || {};
681
- const rpcStats = stats.rpc || {};
682
-
683
- // 获取模块列表(用于计算模块数量和注册记录)
684
- let modules = [];
685
- try {
686
- const modulesRes = await this.callRpc('launcher.list_modules', {});
687
- modules = modulesRes.modules || [];
688
- } catch (err) {
689
- if (!err.message.includes('not ready')) {
690
- console.warn('[Evol] Failed to get modules for stats:', err);
691
- }
692
- }
693
-
694
- // 计算运行时长
695
- const uptime = eventStats.uptime_seconds || 0;
696
-
697
- // 计算模块数量
698
- const moduleCount = modules.length;
699
-
700
- // 获取所有注册记录并分类统计
701
- let registryByCategory = {
702
- modules: 0, // module.* 字段
703
- rpc: 0, // tools.rpc.* 字段
704
- hook: 0, // tools.hook.* 字段
705
- api: 0 // tools.api.* 字段
706
- };
707
- let totalRecords = 0;
708
-
709
- for (const mod of modules) {
710
- try {
711
- // 对齐 Web 模块:使用 registry.lookup 查询每个模块的注册记录
712
- const regRes = await this.callRpc('registry.lookup', { module: mod.name });
713
- const records = regRes.results || [];
714
- totalRecords += records.length;
715
-
716
- // 按字段路径分类
717
- for (const rec of records) {
718
- const field = rec.field || '';
719
- if (field.startsWith('module.')) {
720
- registryByCategory.modules++;
721
- } else if (field.startsWith('tools.rpc.')) {
722
- registryByCategory.rpc++;
723
- } else if (field.startsWith('tools.hook.')) {
724
- registryByCategory.hook++;
725
- } else if (field.startsWith('tools.api.')) {
726
- registryByCategory.api++;
727
- }
728
- }
729
- } catch (e) {
730
- // 模块可能还未注册,忽略错误
731
- }
732
- }
733
-
734
- // 事件统计
735
- const eventsRouted = counters.events_routed || 0;
736
-
737
- // RPC 调用统计
738
- const rpcCalls = rpcStats.total || 0;
739
-
740
- // 更新 UI
741
- document.getElementById('stat-uptime').textContent = this.formatUptime(uptime);
742
- document.getElementById('stat-modules').textContent = moduleCount;
743
- document.getElementById('stat-registry').textContent = totalRecords;
744
- document.getElementById('stat-rpc').textContent = registryByCategory.rpc;
745
- document.getElementById('stat-hooks').textContent = registryByCategory.hook;
746
- document.getElementById('stat-api').textContent = registryByCategory.api;
747
- document.getElementById('stat-events').textContent = eventsRouted;
748
- document.getElementById('stat-rpc-calls').textContent = rpcCalls;
749
- } catch (err) {
750
- console.error('[Evol] Load stats failed:', err);
751
- // 不清空 UI,保留上次的值
752
- }
753
- }
754
-
755
- formatUptime(seconds) {
756
- // 对齐 Web 模块的格式化逻辑
757
- if (seconds < 60) return `${Math.floor(seconds)}秒`;
758
- if (seconds < 3600) return `${Math.floor(seconds / 60)}分钟`;
759
- if (seconds < 86400) {
760
- const h = Math.floor(seconds / 3600);
761
- const m = Math.floor((seconds % 3600) / 60);
762
- return m > 0 ? `${h}小时${m}分` : `${h}小时`;
763
- }
764
- const d = Math.floor(seconds / 86400);
765
- const h = Math.floor((seconds % 86400) / 3600);
766
- return h > 0 ? `${d}天${h}小时` : `${d}天`;
767
- }
768
-
769
- startStatsAutoRefresh() {
770
- if (this.statsRefreshTimer) clearInterval(this.statsRefreshTimer);
771
- this.statsRefreshTimer = setInterval(() => {
772
- if (this.currentPage === 'modules') {
773
- this.loadModuleStats();
774
- }
775
- }, 5000);
776
- }
777
-
778
- async showModuleDetails(moduleName) {
779
- try {
780
- // 对齐 Web 模块:使用 launcher.get_module_config 获取完整配置
781
- const mod = await this.callRpc('launcher.get_module_config', { module_name: moduleName });
782
-
783
- // 隐藏列表,显示详情
784
- document.getElementById('modules-list-header')?.classList.add('hidden');
785
- document.getElementById('modules-table')?.closest('.panel')?.classList.add('hidden');
786
- document.getElementById('statistics-panel')?.classList.add('hidden');
787
- document.getElementById('registry-test-section')?.classList.add('hidden');
788
- document.getElementById('registry-test-output')?.classList.add('hidden');
789
- document.getElementById('module-detail')?.classList.remove('hidden');
790
-
791
- // 保存当前模块名(用于后续操作)
792
- this.currentModuleName = moduleName;
793
-
794
- // Header
795
- document.getElementById('module-detail-name').textContent = mod.display_name || mod.name;
796
- const badge = document.getElementById('module-detail-type-badge');
797
- if (badge) {
798
- badge.textContent = mod.type || '?';
799
- badge.className = `module-type-badge type-${mod.type || 'unknown'}`;
800
- }
801
-
802
- // 【区块1:模块标识】
803
- this._setVal('mod-source-path', mod.source_path || '');
804
- this._setVal('mod-meta-name', mod.name || '');
805
- this._setVal('mod-meta-type', mod.type || '');
806
- this._setVal('mod-meta-runtime', mod.runtime || '');
807
- this._setVal('mod-meta-entry', mod.entry || '');
808
- this._setVal('mod-meta-display-name', mod.display_name || '');
809
- this._setVal('mod-meta-version', mod.version || '');
810
-
811
- // 【区块2:启动配置】
812
- this._setVal('mod-meta-state', mod.state || 'enabled');
813
- const monitorValue = mod.monitor != null ? String(mod.monitor) : 'true';
814
- this._setVal('mod-meta-monitor', monitorValue);
815
-
816
- // 【区块3:网络配置】
817
- this._setVal('mod-meta-port', mod.preferred_port != null ? mod.preferred_port : '');
818
-
819
- // 监听地址:根据模块设置默认值
820
- let defaultIp = '127.0.0.1';
821
- if (mod.name === 'web' || mod.name === 'evol') {
822
- defaultIp = '0.0.0.0'; // web/evol 模块默认允许远程
823
- }
824
- this._setVal('mod-meta-ip', mod.advertise_ip || defaultIp);
825
-
826
- // 运行状态
827
- await this._updateModuleDetailStatus(moduleName);
828
-
829
- // 【区块4:模块配置文件】
830
- const configSection = document.getElementById('module-config-section');
831
- const configTree = document.getElementById('module-config-tree');
832
- if (mod.has_config && mod.config) {
833
- configSection?.classList.remove('hidden');
834
- if (configTree) {
835
- configTree.innerHTML = '';
836
- this._renderConfigTree(mod.config, configTree, '');
837
- }
838
- } else {
839
- configSection?.classList.add('hidden');
840
- }
841
-
842
- // 绑定自动保存事件监听器
843
- this._bindAutoSaveListeners();
844
-
845
- } catch (err) {
846
- alert('加载模块详情失败: ' + err.message);
847
- console.error('[Evol] showModuleDetails failed:', err);
848
- }
849
- }
850
-
851
- // 辅助方法:设置表单值
852
- _setVal(id, value) {
853
- const el = document.getElementById(id);
854
- if (el) {
855
- if (el.tagName === 'SELECT') {
856
- el.value = value;
857
- } else if (el.type === 'number') {
858
- el.value = value === '' ? '' : value;
859
- } else {
860
- el.value = value;
861
- }
862
- }
863
- }
864
-
865
- // 更新模块详情页的运行状态
866
- async _updateModuleDetailStatus(moduleName) {
867
- try {
868
- const result = await this.callRpc('launcher.list_modules', {});
869
- const modules = result.modules || [];
870
- const mod = modules.find(m => m.name === moduleName);
871
-
872
- if (mod) {
873
- const running = mod.actual_state ? mod.actual_state.startsWith('running') : false;
874
- const statusEl = document.getElementById('module-detail-run-status');
875
- if (statusEl) {
876
- statusEl.textContent = running ? '运行中' : '已停止';
877
- statusEl.style.color = running ? '#27ae60' : '#e74c3c';
878
- }
879
-
880
- // 更新按钮状态
881
- const startBtn = document.getElementById('btn-detail-start');
882
- const stopBtn = document.getElementById('btn-detail-stop');
883
- if (startBtn) startBtn.disabled = running;
884
- if (stopBtn) stopBtn.disabled = !running;
885
- }
886
- } catch (err) {
887
- console.error('[Evol] Update detail status failed:', err);
888
- }
889
- }
890
-
891
- // 渲染配置树(简化版)
892
- _renderConfigTree(config, container, prefix) {
893
- if (!config || typeof config !== 'object') return;
894
-
895
- for (const [key, value] of Object.entries(config)) {
896
- const fullKey = prefix ? `${prefix}.${key}` : key;
897
- const div = document.createElement('div');
898
- div.style.marginBottom = '8px';
899
-
900
- if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
901
- // 嵌套对象
902
- div.innerHTML = `<strong style="color:#666;">${key}:</strong>`;
903
- container.appendChild(div);
904
- const subContainer = document.createElement('div');
905
- subContainer.style.marginLeft = '20px';
906
- container.appendChild(subContainer);
907
- this._renderConfigTree(value, subContainer, fullKey);
908
- } else {
909
- // 简单值
910
- div.innerHTML = `
911
- <label style="display:inline-block;width:200px;font-size:13px;color:#666;">${key}:</label>
912
- <input type="text" value="${value}" data-config-key="${fullKey}"
913
- style="padding:4px 8px;border:1px solid #ddd;border-radius:4px;width:300px;">
914
- `;
915
- container.appendChild(div);
916
- }
917
- }
918
- }
919
-
920
- // 绑定自动保存监听器
921
- _bindAutoSaveListeners() {
922
- // 防抖保存函数
923
- if (!this._debouncedSave) {
924
- this._debouncedSave = this._debounce(() => this._saveModuleConfig(), 500);
925
- }
926
-
927
- // 绑定元数据字段
928
- document.querySelectorAll('#module-detail [data-field]').forEach(el => {
929
- el.removeEventListener('input', this._debouncedSave);
930
- el.removeEventListener('change', this._debouncedSave);
931
- const event = (el.tagName === 'SELECT') ? 'change' : 'input';
932
- el.addEventListener(event, this._debouncedSave);
933
- });
934
-
935
- // 绑定配置树字段
936
- document.querySelectorAll('#module-config-tree [data-config-key]').forEach(el => {
937
- el.removeEventListener('input', this._debouncedSave);
938
- el.addEventListener('input', this._debouncedSave);
939
- });
940
- }
941
-
942
- // 防抖函数
943
- _debounce(func, wait) {
944
- let timeout;
945
- return function executedFunction(...args) {
946
- const later = () => {
947
- clearTimeout(timeout);
948
- func(...args);
949
- };
950
- clearTimeout(timeout);
951
- timeout = setTimeout(later, wait);
952
- };
953
- }
954
-
955
- // 保存模块配置
956
- async _saveModuleConfig() {
957
- if (!this.currentModuleName) return;
958
-
959
- try {
960
- // 收集元数据
961
- const metadata = {};
962
- document.querySelectorAll('#module-detail [data-field]').forEach(el => {
963
- const field = el.dataset.field;
964
- let value = el.value;
965
-
966
- // 类型转换
967
- if (el.type === 'number') {
968
- value = value === '' ? null : parseInt(value);
969
- } else if (field === 'monitor') {
970
- value = value === 'true';
971
- }
972
-
973
- metadata[field] = value;
974
- });
975
-
976
- // 收集配置文件
977
- const config = {};
978
- document.querySelectorAll('#module-config-tree [data-config-key]').forEach(el => {
979
- const key = el.dataset.configKey;
980
- config[key] = el.value;
981
- });
982
-
983
- // 调用更新 RPC
984
- await this.callRpc('launcher.update_module_config', {
985
- module_name: this.currentModuleName,
986
- metadata: metadata,
987
- config: Object.keys(config).length > 0 ? config : undefined
988
- });
989
-
990
- // 显示保存成功提示(简单版)
991
- console.log('[Evol] Module config saved successfully');
992
-
993
- } catch (err) {
994
- console.error('[Evol] Save module config failed:', err);
995
- alert('保存失败: ' + err.message);
996
- }
997
- }
998
-
999
- async startModule(moduleName) {
1000
- if (['kernel', 'launcher'].includes(moduleName)) return; // 静默拦截核心模块
1001
- if (this.moduleActionPending.has(moduleName)) return; // 防抖
1002
-
1003
- this.moduleActionPending.set(moduleName, 'start');
1004
- this.updateModuleButtons(moduleName);
1005
-
1006
- try {
1007
- await this.callRpc('launcher.start_module', { name: moduleName });
1008
- // 延迟刷新,等待模块实际启动后再查询状态
1009
- setTimeout(async () => {
1010
- this.moduleActionPending.delete(moduleName);
1011
- await this.loadModules();
1012
- // 检查启动结果
1013
- const result = await this.callRpc('launcher.list_modules', {});
1014
- const mod = (result.modules || []).find(m => m.name === moduleName);
1015
- const running = mod?.actual_state?.startsWith('running');
1016
- if (running) {
1017
- this.showToast(`${moduleName} 启动成功`, 'success');
1018
- } else {
1019
- this.showToast(`${moduleName} 启动超时,请检查日志`, 'error');
1020
- }
1021
- }, 1500);
1022
- } catch (err) {
1023
- this.moduleActionPending.delete(moduleName);
1024
- this.updateModuleButtons(moduleName);
1025
- this.showToast(`启动失败: ${err.message}`, 'error');
1026
- }
1027
- }
1028
-
1029
- async stopModule(moduleName) {
1030
- if (['kernel', 'launcher'].includes(moduleName)) return; // 静默拦截核心模块
1031
- if (this.moduleActionPending.has(moduleName)) return; // 防抖
1032
-
1033
- this.moduleActionPending.set(moduleName, 'stop');
1034
- this.updateModuleButtons(moduleName);
1035
-
1036
- try {
1037
- await this.callRpc('launcher.stop_module', { name: moduleName, reason: 'user_request' });
1038
- // 延迟刷新,等待模块实际停止后再查询状态
1039
- setTimeout(async () => {
1040
- this.moduleActionPending.delete(moduleName);
1041
- await this.loadModules();
1042
- // 检查停止结果
1043
- const result = await this.callRpc('launcher.list_modules', {});
1044
- const mod = (result.modules || []).find(m => m.name === moduleName);
1045
- const running = mod?.actual_state?.startsWith('running');
1046
- if (!running) {
1047
- this.showToast(`${moduleName} 停止成功`, 'success');
1048
- } else {
1049
- this.showToast(`${moduleName} 停止超时,请检查日志`, 'error');
1050
- }
1051
- }, 1500);
1052
- } catch (err) {
1053
- this.moduleActionPending.delete(moduleName);
1054
- this.updateModuleButtons(moduleName);
1055
- this.showToast(`停止失败: ${err.message}`, 'error');
1056
- }
1057
- }
1058
-
1059
- updateModuleButtons(moduleName) {
1060
- // 触发重新渲染按钮状态
1061
- this.loadModules();
1062
- }
1063
-
1064
- async onModuleStateChange(selectEl) {
1065
- const moduleName = selectEl.dataset.module;
1066
- const newState = selectEl.value;
1067
-
1068
- // 禁用下拉,防止重复操作
1069
- selectEl.disabled = true;
1070
-
1071
- try {
1072
- // 调用 RPC 更新模块配置
1073
- await this.callRpc('launcher.update_module_config', {
1074
- module_name: moduleName,
1075
- metadata: { state: newState }
1076
- });
1077
- this.showToast(`模块 ${moduleName} 默认状态已更新为 ${newState}`, 'success');
1078
-
1079
- // 更新状态圆点
1080
- const row = selectEl.closest('tr');
1081
- const dot = row?.querySelector('.module-state-dot');
1082
- if (dot) {
1083
- dot.className = `module-state-dot ${newState === 'enabled' ? 'enabled' : newState === 'manual' ? 'manual' : 'disabled'}`;
1084
- }
1085
- } catch (err) {
1086
- this.showToast('更新失败: ' + err.message, 'error');
1087
- // 恢复原值
1088
- this.loadModules();
1089
- } finally {
1090
- selectEl.disabled = false;
1091
- }
1092
- }
1093
-
1094
- async restartKite() {
1095
- // 禁用按钮,防止重复点击
1096
- const btn = document.getElementById('btn-restart-kite');
1097
- if (btn) {
1098
- btn.disabled = true;
1099
- btn.innerHTML = '<span>⏳</span><span>重启中...</span>';
1100
- }
1101
-
1102
- try {
1103
- const data = await this.callRpc('launcher.restart_launcher', { reason: 'user_request' });
1104
-
1105
- // 检查是否有错误
1106
- if (data.error) {
1107
- this.showToast(`重启失败: ${data.error}`, 'error');
1108
- if (btn) {
1109
- btn.disabled = false;
1110
- btn.innerHTML = '<span>🔄</span><span>重启 Kite</span>';
1111
- }
1112
- return;
1113
- }
1114
-
1115
- // 成功 - 显示重启提示并轮询检测重启完成
1116
- this.showToast('Kite 正在重启...', 'success');
1117
-
1118
- // 轮询检测 Kite 是否重启完成(每 0.5s 检查一次,最多 30s)
1119
- let attempts = 0;
1120
- const maxAttempts = 60; // 30s
1121
- const checkInterval = setInterval(async () => {
1122
- attempts++;
1123
- try {
1124
- // 尝试调用 RPC,如果成功说明重启完成
1125
- await this.callRpc('kernel.health', {});
1126
- clearInterval(checkInterval);
1127
- this.showToast('Kite 重启完成', 'success');
1128
- window.location.reload();
1129
- } catch (err) {
1130
- // 还在重启中,继续等待
1131
- if (attempts >= maxAttempts) {
1132
- clearInterval(checkInterval);
1133
- this.showToast('重启超时,请手动刷新页面', 'warning');
1134
- if (btn) {
1135
- btn.disabled = false;
1136
- btn.innerHTML = '<span>🔄</span><span>重启 Kite</span>';
1137
- }
1138
- }
1139
- }
1140
- }, 500);
1141
- } catch (err) {
1142
- this.showToast(`重启失败: ${err.message}`, 'error');
1143
- if (btn) {
1144
- btn.disabled = false;
1145
- btn.innerHTML = '<span>🔄</span><span>重启 Kite</span>';
1146
- }
1147
- }
1148
- }
1149
-
1150
- // 详情页操作方法
1151
- async startModuleFromDetail() {
1152
- if (!this.currentModuleName) return;
1153
- await this.startModule(this.currentModuleName);
1154
- // 刷新详情页状态
1155
- setTimeout(() => this._updateModuleDetailStatus(this.currentModuleName), 1500);
1156
- }
1157
-
1158
- async stopModuleFromDetail() {
1159
- if (!this.currentModuleName) return;
1160
- if (!confirm(`确定要停止模块 ${this.currentModuleName} 吗?`)) return;
1161
- await this.stopModule(this.currentModuleName);
1162
- // 刷新详情页状态
1163
- setTimeout(() => this._updateModuleDetailStatus(this.currentModuleName), 1500);
1164
- }
1165
-
1166
- async resetModuleDefaults() {
1167
- if (!this.currentModuleName) return;
1168
- if (!confirm(`确定要恢复模块 ${this.currentModuleName} 的默认配置吗?`)) return;
1169
-
1170
- try {
1171
- await this.callRpc('launcher.reset_module_config', { module_name: this.currentModuleName });
1172
- this.showToast('配置已恢复为默认值', 'success');
1173
- // 重新加载详情
1174
- await this.showModuleDetails(this.currentModuleName);
1175
- } catch (err) {
1176
- this.showToast(`恢复默认值失败: ${err.message}`, 'error');
1177
- }
1178
- }
1179
-
1180
- async toggleConsole() {
1181
- const console = document.getElementById('realtime-console');
1182
- const text = document.getElementById('console-toggle-text');
1183
-
1184
- if (console.style.display === 'none') {
1185
- // 展开控制台
1186
- console.style.display = 'block';
1187
- text.textContent = '收起控制台';
1188
- this.consoleExpanded = true;
1189
-
1190
- // 订阅全部事件
1191
- await this.subscribeAllEvents();
1192
- } else {
1193
- // 收起控制台
1194
- console.style.display = 'none';
1195
- text.textContent = '展开控制台';
1196
- this.consoleExpanded = false;
1197
-
1198
- // 清空事件日志
1199
- this.eventLogs = [];
1200
- document.getElementById('console-output').textContent = '';
1201
-
1202
- // 恢复默认订阅(只订阅 module.* 事件)
1203
- await this.subscribeDefaultEvents();
1204
- }
1205
- }
1206
-
1207
- async subscribeAllEvents() {
1208
- if (!this.wsConnected || this.eventSubscribed) return;
1209
-
1210
- try {
1211
- // 订阅所有事件(使用通配符)
1212
- await this.callRpc('event.subscribe', { events: ['*'] });
1213
- this.eventSubscribed = true;
1214
- console.log('[Evol] Subscribed to all events');
1215
- } catch (err) {
1216
- console.error('[Evol] Failed to subscribe all events:', err);
1217
- }
1218
- }
1219
-
1220
- async subscribeDefaultEvents() {
1221
- if (!this.wsConnected) return;
1222
-
1223
- try {
1224
- // 只订阅 module.* 事件(用于刷新模块列表)
1225
- await this.callRpc('event.subscribe', { events: ['module.*'] });
1226
- this.eventSubscribed = false;
1227
- console.log('[Evol] Subscribed to default events (module.*)');
1228
- } catch (err) {
1229
- console.error('[Evol] Failed to subscribe default events:', err);
1230
- }
1231
- }
1232
-
1233
- clearConsole() {
1234
- this.eventLogs = [];
1235
- this.renderEventLogs();
1236
- }
1237
-
1238
- // 添加事件日志
1239
- addEventLog(event, data) {
1240
- const timestamp = Date.now();
1241
- const module = this.extractModuleFromEvent(event);
1242
-
1243
- // 记录已知的模块和事件
1244
- if (module) this.knownModules.add(module);
1245
- this.knownEvents.add(event);
1246
-
1247
- // 添加到日志数组
1248
- this.eventLogs.unshift({
1249
- timestamp,
1250
- module,
1251
- event,
1252
- data,
1253
- raw: JSON.stringify(data)
1254
- });
1255
-
1256
- // 限制日志数量(最多保留1000条)
1257
- if (this.eventLogs.length > 1000) {
1258
- this.eventLogs = this.eventLogs.slice(0, 1000);
1259
- }
1260
-
1261
- // 更新筛选器选项
1262
- this.updateFilterOptions();
1263
-
1264
- // 重新渲染
1265
- this.renderEventLogs();
1266
- }
1267
-
1268
- // 从事件名提取模块名
1269
- extractModuleFromEvent(event) {
1270
- // 事件格式通常是 module.event_name 或 category.module.event_name
1271
- const parts = event.split('.');
1272
- if (parts.length >= 2) {
1273
- return parts[0]; // 返回第一部分作为模块名
1274
- }
1275
- return null;
1276
- }
1277
-
1278
- // 更新筛选器选项
1279
- updateFilterOptions() {
1280
- // 更新模块筛选器
1281
- const moduleSelect = document.getElementById('filter-module');
1282
- if (moduleSelect) {
1283
- const currentValue = moduleSelect.value;
1284
- const modules = Array.from(this.knownModules).sort();
1285
-
1286
- let html = '<option value="">全部模块</option>';
1287
- modules.forEach(mod => {
1288
- html += `<option value="${mod}">${mod}</option>`;
1289
- });
1290
-
1291
- moduleSelect.innerHTML = html;
1292
- moduleSelect.value = currentValue;
1293
- }
1294
-
1295
- // 更新事件筛选器
1296
- const eventSelect = document.getElementById('filter-event');
1297
- if (eventSelect) {
1298
- const currentValue = eventSelect.value;
1299
- const events = Array.from(this.knownEvents).sort();
1300
-
1301
- let html = '<option value="">全部事件</option>';
1302
- events.forEach(evt => {
1303
- html += `<option value="${evt}">${evt}</option>`;
1304
- });
1305
-
1306
- eventSelect.innerHTML = html;
1307
- eventSelect.value = currentValue;
1308
- }
1309
- }
1310
-
1311
- // 渲染事件日志
1312
- renderEventLogs() {
1313
- const output = document.getElementById('console-output');
1314
- if (!output) return;
1315
-
1316
- // 获取筛选条件
1317
- const filterModule = document.getElementById('filter-module')?.value || '';
1318
- const filterEvent = document.getElementById('filter-event')?.value || '';
1319
- const filterKeyword = document.getElementById('filter-keyword')?.value || '';
1320
- const filterTime = parseInt(document.getElementById('filter-time')?.value || '0');
1321
-
1322
- // 筛选日志
1323
- const now = Date.now();
1324
- const filtered = this.eventLogs.filter(log => {
1325
- // 时间筛选
1326
- if (filterTime > 0) {
1327
- const age = (now - log.timestamp) / 1000; // 秒
1328
- if (age > filterTime) return false;
1329
- }
1330
-
1331
- // 模块筛选
1332
- if (filterModule && log.module !== filterModule) return false;
1333
-
1334
- // 事件筛选
1335
- if (filterEvent && log.event !== filterEvent) return false;
1336
-
1337
- // 关键词筛选(glob 模式)
1338
- if (filterKeyword) {
1339
- const pattern = this.globToRegex(filterKeyword);
1340
- const searchText = `${log.event} ${log.raw}`.toLowerCase();
1341
- if (!pattern.test(searchText)) return false;
1342
- }
1343
-
1344
- return true;
1345
- });
1346
-
1347
- // 渲染(时间倒序,最新的在最上面)
1348
- let html = '';
1349
- filtered.forEach(log => {
1350
- const time = this.formatTimestamp(log.timestamp);
1351
- const module = log.module || '?';
1352
- const event = log.event;
1353
- const data = this.formatEventData(log.data);
1354
-
1355
- // 根据事件类型设置颜色
1356
- let color = '#d4d4d4';
1357
- if (event.includes('error') || event.includes('failed')) {
1358
- color = '#f48771';
1359
- } else if (event.includes('warning')) {
1360
- color = '#dcdcaa';
1361
- } else if (event.includes('started') || event.includes('success')) {
1362
- color = '#4ec9b0';
1363
- }
1364
-
1365
- html += `<span style="color:#858585;">${time}</span> `;
1366
- html += `<span style="color:#569cd6;">[${module}]</span> `;
1367
- html += `<span style="color:${color};">${event}</span> `;
1368
- html += `<span style="color:#9cdcfe;">${data}</span>\n`;
1369
- });
1370
-
1371
- output.innerHTML = html || '<span style="color:#858585;">暂无事件日志</span>';
1372
-
1373
- // 保持滚动在顶部(因为是倒序显示)
1374
- output.scrollTop = 0;
1375
- }
1376
-
1377
- // 格式化时间戳
1378
- formatTimestamp(timestamp) {
1379
- const date = new Date(timestamp);
1380
- const h = String(date.getHours()).padStart(2, '0');
1381
- const m = String(date.getMinutes()).padStart(2, '0');
1382
- const s = String(date.getSeconds()).padStart(2, '0');
1383
- const ms = String(date.getMilliseconds()).padStart(3, '0');
1384
- return `${h}:${m}:${s}.${ms}`;
1385
- }
1386
-
1387
- // 格式化事件数据(人类可读)
1388
- formatEventData(data) {
1389
- if (!data || typeof data !== 'object') {
1390
- return JSON.stringify(data);
1391
- }
1392
-
1393
- // 特殊格式化处理
1394
- const formatted = [];
1395
-
1396
- // 常见字段的友好显示
1397
- if (data.module) formatted.push(`module=${data.module}`);
1398
- if (data.state) formatted.push(`state=${data.state}`);
1399
- if (data.status) formatted.push(`status=${data.status}`);
1400
- if (data.port) formatted.push(`port=${data.port}`);
1401
- if (data.pid) formatted.push(`pid=${data.pid}`);
1402
- if (data.error) formatted.push(`error="${data.error}"`);
1403
- if (data.message) formatted.push(`msg="${data.message}"`);
1404
- if (data.duration !== undefined) formatted.push(`duration=${data.duration}ms`);
1405
-
1406
- // 如果有格式化的字段,返回格式化结果
1407
- if (formatted.length > 0) {
1408
- return formatted.join(' ');
1409
- }
1410
-
1411
- // 否则返回紧凑的 JSON
1412
- return JSON.stringify(data);
1413
- }
1414
-
1415
- // Glob 转正则表达式
1416
- globToRegex(pattern) {
1417
- const escaped = pattern
1418
- .replace(/[.+^${}()|[\]\\]/g, '\\$&') // 转义特殊字符
1419
- .replace(/\*/g, '.*') // * 匹配任意字符
1420
- .replace(/\?/g, '.'); // ? 匹配单个字符
1421
- return new RegExp(escaped, 'i'); // 不区分大小写
1422
- }
1423
-
1424
- appendConsoleLog(message) {
1425
- // 保留旧方法以兼容其他代码
1426
- const output = document.getElementById('console-output');
1427
- const timestamp = new Date().toLocaleTimeString('zh-CN', { hour12: false });
1428
- output.textContent += `[${timestamp}] ${message}\n`;
1429
- output.scrollTop = output.scrollHeight;
1430
- }
1431
-
1432
- async runRegistryTest() {
1433
- // 调用 registry-tests.js 中的 runAllTests() 函数
1434
- if (typeof runAllTests === 'function') {
1435
- await runAllTests();
1436
- } else {
1437
- const output = document.getElementById('test-output');
1438
- output.textContent = '错误: registry-tests.js 未加载或 runAllTests 函数不存在';
1439
- }
1440
- }
1441
-
1442
- clearTestOutput() {
1443
- document.getElementById('test-output').textContent = '';
1444
- }
1445
-
1446
- async loadTokens() {
1447
- // 根据当前激活的标签页加载对应的 token
1448
- const activeTab = document.querySelector('.tab.active')?.dataset.tab || 'kite';
1449
- if (activeTab === 'kite') {
1450
- await this.loadKiteTokens();
1451
- } else {
1452
- await this.loadEvolTokens();
1453
- }
1454
- }
1455
-
1456
- async loadKiteTokens() {
1457
- try {
1458
- const result = await this.callRpc('evol.list_kite_tokens', {});
1459
- const tokens = result.tokens || [];
1460
-
1461
- const tbody = document.getElementById('kite-tokens-tbody');
1462
- if (tokens.length === 0) {
1463
- tbody.innerHTML = '<tr><td colspan="9" class="text-muted" style="text-align:center;padding:40px;">暂无 Kite Token</td></tr>';
1464
- return;
1465
- }
1466
-
1467
- // 缩略显示函数:头部6位...尾部8位
1468
- const truncate = (str, headLen = 6, tailLen = 8) => {
1469
- if (!str || str.length <= headLen + tailLen + 3) return str;
1470
- return `${str.substring(0, headLen)}...${str.substring(str.length - tailLen)}`;
1471
- };
1472
-
1473
- let html = '';
1474
- tokens.forEach(token => {
1475
- // Token 缩略显示(前6位...后8位)
1476
- const tokenDisplay = truncate(token.token, 6, 8);
1477
-
1478
- // 设备信息(设备名 + 设备ID缩略)
1479
- const deviceId = token.deviceId || 'unknown';
1480
- const deviceIdShort = truncate(deviceId, 6, 6);
1481
- const deviceInfo = `${token.deviceName || 'Unknown'}<br><span style="font-size:11px;color:#999;">${deviceIdShort}</span>`;
1482
-
1483
- // 手机号显示
1484
- const phone = token.phone || '<span style="color:#999;">未绑定</span>';
1485
-
1486
- // 时间格式化
1487
- const formatTime = (isoStr) => {
1488
- if (!isoStr) return '-';
1489
- const date = new Date(isoStr);
1490
- return date.toLocaleString('zh-CN', {
1491
- month: '2-digit',
1492
- day: '2-digit',
1493
- hour: '2-digit',
1494
- minute: '2-digit'
1495
- });
1496
- };
1497
-
1498
- const createdAt = formatTime(token.createdAt);
1499
- const lastUsedAt = formatTime(token.lastUsedAt);
1500
- const expiresAt = formatTime(token.expiresAt);
1501
-
1502
- // 计算剩余有效期
1503
- const now = new Date();
1504
- const expireDate = token.expiresAt ? new Date(token.expiresAt) : null;
1505
- let remainingTime = '-';
1506
- let isExpired = false;
1507
-
1508
- if (expireDate) {
1509
- const diffMs = expireDate - now;
1510
- isExpired = diffMs <= 0;
1511
-
1512
- if (isExpired) {
1513
- remainingTime = '已过期';
1514
- } else {
1515
- const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
1516
- const diffHours = Math.floor((diffMs % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
1517
-
1518
- if (diffDays > 0) {
1519
- remainingTime = `${diffDays}天`;
1520
- } else if (diffHours > 0) {
1521
- remainingTime = `${diffHours}小时`;
1522
- } else {
1523
- const diffMinutes = Math.floor((diffMs % (1000 * 60 * 60)) / (1000 * 60));
1524
- remainingTime = `${diffMinutes}分钟`;
1525
- }
1526
- }
1527
- }
1528
-
1529
- const status = isExpired ? '已过期' : '有效';
1530
- const statusColor = isExpired ? '#e74c3c' : '#27ae60';
1531
- const remainingColor = isExpired ? '#e74c3c' : (expireDate && (expireDate - now) < 7 * 24 * 60 * 60 * 1000 ? '#ff9800' : '#666');
1532
-
1533
- html += `<tr>
1534
- <td><code style="font-size:11px;" title="${token.token}">${tokenDisplay}</code></td>
1535
- <td style="font-size:12px;">${deviceInfo}</td>
1536
- <td style="font-size:12px;">${phone}</td>
1537
- <td style="font-size:12px;">${createdAt}</td>
1538
- <td style="font-size:12px;">${lastUsedAt}</td>
1539
- <td style="font-size:12px;">${expiresAt}</td>
1540
- <td style="font-size:12px;color:${remainingColor};font-weight:500;">${remainingTime}</td>
1541
- <td style="color:${statusColor};font-weight:500;">${status}</td>
1542
- <td>
1543
- <button class="btn btn-sm btn-danger" onclick="app.deleteToken('${token.token}')" ${isExpired ? 'disabled' : ''}>吊销</button>
1544
- </td>
1545
- </tr>`;
1546
- });
1547
-
1548
- tbody.innerHTML = html;
1549
- } catch (err) {
1550
- console.error('[evol] Load Kite tokens failed:', err);
1551
- document.getElementById('kite-tokens-tbody').innerHTML =
1552
- `<tr><td colspan="9" style="text-align:center;padding:40px;color:#e74c3c;">加载失败: ${err.message}</td></tr>`;
1553
- }
1554
- }
1555
-
1556
- async loadEvolTokens() {
1557
- try {
1558
- const result = await this.callRpc('evol.list_evol_tokens', {});
1559
- const tokens = result.tokens || [];
1560
-
1561
- const tbody = document.getElementById('evol-tokens-tbody');
1562
- if (tokens.length === 0) {
1563
- tbody.innerHTML = '<tr><td colspan="8" class="text-muted" style="text-align:center;padding:40px;">暂无 Evol Token</td></tr>';
1564
- return;
1565
- }
1566
-
1567
- // 缩略显示函数
1568
- const truncate = (str, headLen = 6, tailLen = 8) => {
1569
- if (!str || str.length <= headLen + tailLen + 3) return str;
1570
- return `${str.substring(0, headLen)}...${str.substring(str.length - tailLen)}`;
1571
- };
1572
-
1573
- // 时间格式化
1574
- const formatTime = (isoStr) => {
1575
- if (!isoStr) return '-';
1576
- const date = new Date(isoStr);
1577
- return date.toLocaleString('zh-CN', {
1578
- month: '2-digit',
1579
- day: '2-digit',
1580
- hour: '2-digit',
1581
- minute: '2-digit'
1582
- });
1583
- };
1584
-
1585
- let html = '';
1586
- tokens.forEach(token => {
1587
- const tokenDisplay = truncate(token.token, 6, 8);
1588
- const phone = token.phone || '-';
1589
- const nickName = token.nickName || '-';
1590
- const credits = `${token.credits || 0} / ${token.creditsLimit || 0}`;
1591
- const vipInfo = `${token.vipTypeName || 'Unknown'}<br><span style="font-size:11px;color:#999;">剩余${token.vipRemainingDays || 0}天</span>`;
1592
- const obtainedAt = formatTime(token.obtainedAt);
1593
- const lastUsedAt = formatTime(token.lastUsedAt);
1594
- const expiresAt = formatTime(token.expiresAt);
1595
-
1596
- html += `<tr>
1597
- <td><code style="font-size:11px;" title="${token.token}">${tokenDisplay}</code></td>
1598
- <td style="font-size:12px;">${phone}</td>
1599
- <td style="font-size:12px;">${nickName}</td>
1600
- <td style="font-size:12px;">${credits}</td>
1601
- <td style="font-size:12px;">${vipInfo}</td>
1602
- <td style="font-size:12px;">${obtainedAt}</td>
1603
- <td style="font-size:12px;">${lastUsedAt}</td>
1604
- <td style="font-size:12px;">${expiresAt}</td>
1605
- </tr>`;
1606
- });
1607
-
1608
- tbody.innerHTML = html;
1609
- } catch (err) {
1610
- console.error('[evol] Load Evol tokens failed:', err);
1611
- document.getElementById('evol-tokens-tbody').innerHTML =
1612
- `<tr><td colspan="8" style="text-align:center;padding:40px;color:#e74c3c;">加载失败: ${err.message}</td></tr>`;
1613
- }
1614
- }
1615
-
1616
- async deleteToken(token) {
1617
- const confirmed = await window.dialog.confirm('确定要吊销此 Token 吗?删除后该设备将无法访问。', '吊销 Token');
1618
- if (!confirmed) return;
1619
-
1620
- try {
1621
- await this.callRpc('evol.revoke_token', { token });
1622
- window.dialog.success('Token 已成功吊销');
1623
- this.loadTokens();
1624
- } catch (err) {
1625
- window.dialog.error('吊销失败: ' + err.message);
1626
- }
1627
- }
1628
-
1629
- async refreshTokens() {
1630
- this.loadTokens();
1631
- }
1632
-
1633
- showToast(message, type = 'info') {
1634
- // 使用全局 showMessage 函数
1635
- showMessage(message, type);
1636
- }
1637
- }
1638
-
1639
-
1640
- // Global app instance
1641
- let app;
1642
-
1643
- // Initialize app on load
1644
- document.addEventListener('DOMContentLoaded', () => {
1645
- app = new EvolApp();
1646
- app.init();
1647
-
1648
- // Login form handlers
1649
- document.getElementById('btn-send-code').addEventListener('click', async () => {
1650
- const phone = document.getElementById('login-phone').value.trim();
1651
-
1652
- if (!phone) {
1653
- showMessage('请输入手机号', 'error');
1654
- return;
1655
- }
1656
-
1657
- if (!/^1[3-9]\d{9}$/.test(phone)) {
1658
- showMessage('请输入有效的中国大陆手机号(11位数字,以1开头)', 'error');
1659
- return;
1660
- }
1661
-
1662
- const btn = document.getElementById('btn-send-code');
1663
- btn.disabled = true;
1664
- btn.textContent = '发送中...';
1665
-
1666
- try {
1667
- const data = await app.sendSMS(phone);
1668
- console.log('SMS API response:', data);
1669
-
1670
- if (data.success) {
1671
- showMessage('验证码已发送,请查收短信', 'success');
1672
- // 焦点移到验证码输入框
1673
- document.getElementById('login-code').focus();
1674
- let countdown = 60;
1675
- const timer = setInterval(() => {
1676
- countdown--;
1677
- btn.textContent = countdown + '秒后重试';
1678
- if (countdown <= 0) {
1679
- clearInterval(timer);
1680
- btn.disabled = false;
1681
- btn.textContent = '发送验证码';
1682
- }
1683
- }, 1000);
1684
- } else {
1685
- const errorMsg = data.msg || data.message || '发送失败,请稍后重试';
1686
- showMessage('发送失败: ' + errorMsg, 'error');
1687
- console.error('SMS API error:', data);
1688
- btn.disabled = false;
1689
- btn.textContent = '发送验证码';
1690
- }
1691
- } catch (err) {
1692
- console.error('SMS request error:', err);
1693
- showMessage('网络错误: ' + err.message, 'error');
1694
- btn.disabled = false;
1695
- btn.textContent = '发送验证码';
1696
- }
1697
- });
1698
-
1699
- document.getElementById('btn-login').addEventListener('click', async () => {
1700
- const phone = document.getElementById('login-phone').value.trim();
1701
- const code = document.getElementById('login-code').value.trim();
1702
-
1703
- if (!phone || !code) {
1704
- showMessage('请输入手机号和验证码', 'error');
1705
- return;
1706
- }
1707
-
1708
- const btn = document.getElementById('btn-login');
1709
- btn.disabled = true;
1710
- btn.textContent = '登录中...';
1711
-
1712
- try {
1713
- const data = await app.login(phone, code);
1714
- if (data.success) {
1715
- showMessage('登录成功', 'success');
1716
- } else {
1717
- showMessage(data.msg || '登录失败', 'error');
1718
- btn.disabled = false;
1719
- btn.textContent = '登录';
1720
- }
1721
- } catch (err) {
1722
- showMessage('网络错误', 'error');
1723
- btn.disabled = false;
1724
- btn.textContent = '登录';
1725
- }
1726
- });
1727
-
1728
- document.getElementById('btn-logout').addEventListener('click', () => {
1729
- app.logout();
1730
- });
1731
-
1732
- // Module management event listeners
1733
- document.getElementById('btn-toggle-console')?.addEventListener('click', () => {
1734
- app.toggleConsole();
1735
- });
1736
-
1737
- document.getElementById('btn-clear-console')?.addEventListener('click', () => {
1738
- app.clearConsole();
1739
- });
1740
-
1741
- document.getElementById('btn-restart-kite')?.addEventListener('click', () => {
1742
- app.restartKite();
1743
- });
1744
-
1745
- document.getElementById('btn-test-registry')?.addEventListener('click', () => {
1746
- app.runRegistryTest();
1747
- });
1748
-
1749
- document.getElementById('btn-clear-test-output')?.addEventListener('click', () => {
1750
- app.clearTestOutput();
1751
- });
1752
-
1753
- document.getElementById('btn-module-back')?.addEventListener('click', () => {
1754
- app.loadModules();
1755
- });
1756
-
1757
- document.getElementById('btn-detail-start')?.addEventListener('click', () => {
1758
- app.startModuleFromDetail();
1759
- });
1760
-
1761
- document.getElementById('btn-detail-stop')?.addEventListener('click', () => {
1762
- app.stopModuleFromDetail();
1763
- });
1764
-
1765
- document.getElementById('btn-reset-defaults')?.addEventListener('click', () => {
1766
- app.resetModuleDefaults();
1767
- });
1768
-
1769
- // Token management event listeners
1770
- document.getElementById('btn-refresh-tokens')?.addEventListener('click', () => {
1771
- app.refreshTokens();
1772
- });
1773
-
1774
- // Tab switching event listeners
1775
- document.querySelectorAll('.tab').forEach(tab => {
1776
- tab.addEventListener('click', () => {
1777
- // 移除所有 active 类
1778
- document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
1779
- document.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active'));
1780
-
1781
- // 添加 active 类到当前标签
1782
- tab.classList.add('active');
1783
- const tabName = tab.dataset.tab;
1784
- document.getElementById(`tab-${tabName}`).classList.add('active');
1785
-
1786
- // 加载对应的数据
1787
- if (tabName === 'kite') {
1788
- app.loadKiteTokens();
1789
- } else if (tabName === 'evol') {
1790
- app.loadEvolTokens();
1791
- }
1792
- });
1793
- });
1794
- });
1795
-
1796
- function showMessage(msg, type) {
1797
- const el = document.getElementById('login-message');
1798
- el.textContent = msg;
1799
- el.className = type === 'error' ? 'error-msg' : 'success-msg';
1800
- }