@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
@@ -14,6 +14,7 @@ Kernel WebSocket 中转服务
14
14
 
15
15
  import asyncio
16
16
  import json
17
+ import os
17
18
  import secrets
18
19
  import time
19
20
  import uuid
@@ -23,6 +24,9 @@ from typing import Optional
23
24
  import websockets
24
25
  from fastapi import WebSocket, WebSocketDisconnect
25
26
 
27
+ from extensions.services.kite_console.nonce_pool import NoncePool
28
+ from extensions.services.kite_console.mfa_totp import TOTPVerifier
29
+
26
30
 
27
31
  class SessionInfo:
28
32
  """前端会话信息"""
@@ -35,6 +39,7 @@ class SessionInfo:
35
39
  client_ws: WebSocket,
36
40
  frontend_token: str,
37
41
  role: str,
42
+ kernel_token: str,
38
43
  ):
39
44
  self.session_token = session_token
40
45
  self.module_id = module_id
@@ -42,6 +47,7 @@ class SessionInfo:
42
47
  self.client_ws: Optional[WebSocket] = client_ws
43
48
  self.frontend_token = frontend_token
44
49
  self.role = role
50
+ self.kernel_token = kernel_token
45
51
  self.created_at = time.time()
46
52
  self.last_active = time.time()
47
53
  self.status = "active" # active | waiting_reconnect
@@ -59,7 +65,9 @@ class KernelRelay:
59
65
  reconnect_timeout: int,
60
66
  permissions: dict,
61
67
  pairing_manager,
62
- web_server, # 新增:web server 实例,用于发送事件
68
+ web_server, # web server 实例,用于发送事件
69
+ auth_manager=None, # 新增:AuthManager 实例,用于 Kite Token 认证
70
+ oauth_manager=None, # 新增:OAuthManager 实例,用于 OAuth 认证
63
71
  ):
64
72
  """
65
73
  初始化中转服务。
@@ -73,6 +81,8 @@ class KernelRelay:
73
81
  permissions: 权限配置(角色 → RPC 白名单)
74
82
  pairing_manager: 配对管理器实例
75
83
  web_server: web server 实例
84
+ auth_manager: AuthManager 实例(可选,用于 Kite Token 认证)
85
+ oauth_manager: OAuthManager 实例(可选,用于 OAuth auth_ticket 认证)
76
86
  """
77
87
  self.kernel_host = kernel_host
78
88
  self.kernel_port = kernel_port
@@ -82,6 +92,16 @@ class KernelRelay:
82
92
  self.permissions = permissions
83
93
  self.pairing_manager = pairing_manager
84
94
  self.web_server = web_server
95
+ self.auth_manager = auth_manager
96
+ self.oauth_manager = oauth_manager
97
+
98
+ # Nonce 池(challenge-response 防重放)
99
+ self.nonce_pool = NoncePool(max_size=10000, ttl=600)
100
+
101
+ # TLS configuration
102
+ # 默认值根据环境变量:开发环境允许 WS,生产环境强制 WSS
103
+ env = os.environ.get("KITE_ENV", "development").lower()
104
+ self.require_tls = os.environ.get("KITE_REQUIRE_TLS", "true" if env == "production" else "false").lower() == "true"
85
105
 
86
106
  # session_token → SessionInfo
87
107
  self.sessions: dict[str, SessionInfo] = {}
@@ -89,6 +109,16 @@ class KernelRelay:
89
109
  # 待重连的 session(超时清理)
90
110
  self.reconnect_timers: dict[str, asyncio.Task] = {}
91
111
 
112
+ # 速率限制:(ip, device_id) → [timestamp, timestamp, ...]
113
+ self._rate_limits: dict[tuple[str, str], list[float]] = {}
114
+ self._rate_limit_max = 20 # 10 秒内最多 20 次
115
+ self._rate_limit_window = 10.0 # 秒
116
+
117
+ # MFA/TOTP 验证器
118
+ self._totp = TOTPVerifier()
119
+ # MFA 密钥存储:token → totp_secret(由外部配置注入)
120
+ self._mfa_secrets: dict[str, str] = {}
121
+
92
122
  async def handle_client(self, client_ws: WebSocket):
93
123
  """
94
124
  处理客户端连接。
@@ -100,9 +130,28 @@ class KernelRelay:
100
130
  4. 创建或恢复 Kernel 连接
101
131
  5. 双向转发消息
102
132
  """
133
+ # Check TLS requirement before accepting
134
+ if self.require_tls:
135
+ # Check if connection is secure (WSS)
136
+ if client_ws.url.scheme != "wss":
137
+ await client_ws.close(code=1008, reason="TLS required")
138
+ print(f"[relay] Rejected non-TLS connection from {client_ws.client.host if client_ws.client else 'unknown'}")
139
+ return
140
+
103
141
  await client_ws.accept()
104
142
 
105
143
  try:
144
+ # 速率限制检查
145
+ client_ip = client_ws.client.host if client_ws.client else "unknown"
146
+ if not self._check_rate_limit(client_ip, "unknown"):
147
+ await client_ws.send_json({
148
+ "type": "error",
149
+ "message": "Rate limit exceeded"
150
+ })
151
+ await client_ws.close(code=4020, reason="Rate limit exceeded")
152
+ await self._audit_log("auth.rate_limited", {"ip": client_ip})
153
+ return
154
+
106
155
  # 接收认证/配对/请求配对码消息
107
156
  raw = await client_ws.receive_text()
108
157
  msg = json.loads(raw)
@@ -111,6 +160,9 @@ class KernelRelay:
111
160
  if msg_type == "request_code":
112
161
  # 请求配对码
113
162
  await self._handle_request_code(client_ws, msg)
163
+ elif msg_type == "challenge":
164
+ # Challenge-response 握手(第一步:客户端请求 challenge)
165
+ await self._handle_challenge(client_ws, msg)
114
166
  elif msg_type == "pair":
115
167
  # 配对流程
116
168
  await self._handle_pair(client_ws, msg)
@@ -120,7 +172,7 @@ class KernelRelay:
120
172
  else:
121
173
  await client_ws.send_json({
122
174
  "type": "error",
123
- "message": "Invalid message type, expected 'request_code', 'pair' or 'auth'"
175
+ "message": "Invalid message type, expected 'challenge', 'request_code', 'pair' or 'auth'"
124
176
  })
125
177
  await client_ws.close(code=4000, reason="Invalid message type")
126
178
 
@@ -133,6 +185,95 @@ class KernelRelay:
133
185
  except Exception:
134
186
  pass
135
187
 
188
+ async def _handle_challenge(self, client_ws: WebSocket, msg: dict):
189
+ """处理 challenge 请求(握手第一步)"""
190
+ client_ip = client_ws.client.host if client_ws.client else "unknown"
191
+ nonce = self.nonce_pool.generate(metadata={"client_ip": client_ip})
192
+
193
+ await client_ws.send_json({
194
+ "type": "challenge",
195
+ "nonce": nonce,
196
+ "protocol_version": "1.0",
197
+ "auth_methods": ["pairing_code", "kite_token", "oauth"],
198
+ "expires_in": self.nonce_pool.ttl,
199
+ "server_time": time.time(), # 客户端可据此校准时钟偏移
200
+ })
201
+
202
+ # 等待客户端的 connect 消息(带 nonce)
203
+ try:
204
+ raw = await asyncio.wait_for(client_ws.receive_text(), timeout=30)
205
+ connect_msg = json.loads(raw)
206
+
207
+ if connect_msg.get("type") != "connect":
208
+ await client_ws.send_json({
209
+ "type": "error",
210
+ "message": "Expected 'connect' message after challenge"
211
+ })
212
+ await client_ws.close(code=4000, reason="Protocol error")
213
+ return
214
+
215
+ # 验证 nonce
216
+ returned_nonce = connect_msg.get("nonce")
217
+ if not returned_nonce:
218
+ await client_ws.send_json({
219
+ "type": "error",
220
+ "message": "Missing nonce in connect message"
221
+ })
222
+ await client_ws.close(code=4000, reason="Missing nonce")
223
+ return
224
+
225
+ nonce_meta = self.nonce_pool.verify(returned_nonce)
226
+ if nonce_meta is None:
227
+ await client_ws.send_json({
228
+ "type": "error",
229
+ "message": "Invalid or expired nonce"
230
+ })
231
+ await client_ws.close(code=4001, reason="Invalid nonce")
232
+ return
233
+
234
+ # Nonce 验证通过,根据 auth_method 分发
235
+ auth_method = connect_msg.get("auth_method", "")
236
+
237
+ if auth_method == "pairing_code":
238
+ code = connect_msg.get("code")
239
+ if not code:
240
+ await client_ws.send_json({"type": "error", "message": "Missing pairing code"})
241
+ await client_ws.close(code=4000, reason="Missing code")
242
+ return
243
+ await self._handle_pair(client_ws, {"code": code})
244
+
245
+ elif auth_method == "kite_token":
246
+ token = connect_msg.get("token")
247
+ session_token = connect_msg.get("session_token")
248
+ if not token or not session_token:
249
+ await client_ws.send_json({"type": "error", "message": "Missing token or session_token"})
250
+ await client_ws.close(code=4000, reason="Missing credentials")
251
+ return
252
+ await self._handle_auth(client_ws, {"token": token, "session_token": session_token})
253
+
254
+ elif auth_method == "oauth":
255
+ auth_ticket = connect_msg.get("auth_ticket")
256
+ if not auth_ticket:
257
+ await client_ws.send_json({"type": "error", "message": "Missing auth_ticket"})
258
+ await client_ws.close(code=4000, reason="Missing auth_ticket")
259
+ return
260
+ await self._handle_auth(client_ws, {
261
+ "method": "oauth",
262
+ "auth_ticket": auth_ticket,
263
+ "session_token": connect_msg.get("session_token", "")
264
+ })
265
+
266
+ else:
267
+ await client_ws.send_json({
268
+ "type": "error",
269
+ "message": f"Unsupported auth_method: {auth_method}"
270
+ })
271
+ await client_ws.close(code=4000, reason="Unsupported auth method")
272
+
273
+ except asyncio.TimeoutError:
274
+ await client_ws.send_json({"type": "error", "message": "Connect timeout"})
275
+ await client_ws.close(code=4000, reason="Timeout")
276
+
136
277
  async def _handle_request_code(self, client_ws: WebSocket, msg: dict):
137
278
  """处理请求配对码"""
138
279
  # 生成配对码
@@ -141,15 +282,17 @@ class KernelRelay:
141
282
  # 发送事件给 Launcher(通过 Kernel)
142
283
  if self.web_server and self.web_server._ws:
143
284
  try:
144
- await self.web_server._publish_event({
145
- "event": "pairing.status",
146
- "data": {
285
+ await self.web_server._publish_event(
286
+ self.web_server._ws,
287
+ "pairing.status",
288
+ {
147
289
  "step": "code_generated",
148
290
  "success": True,
149
291
  "code": code,
150
- "expires_in": 300
292
+ "expires_in": 300,
293
+ "module_id": "evol"
151
294
  }
152
- })
295
+ )
153
296
  except Exception as e:
154
297
  print(f"[relay] Failed to publish pairing event: {e}")
155
298
 
@@ -179,14 +322,15 @@ class KernelRelay:
179
322
  # 发送配对失败事件
180
323
  if self.web_server and self.web_server._ws:
181
324
  try:
182
- await self.web_server._publish_event({
183
- "event": "pairing.status",
184
- "data": {
325
+ await self.web_server._publish_event(
326
+ self.web_server._ws,
327
+ "pairing.status",
328
+ {
185
329
  "step": "completed",
186
330
  "success": False,
187
331
  "reason": "Invalid pairing code"
188
332
  }
189
- })
333
+ )
190
334
  except Exception as e:
191
335
  print(f"[relay] Failed to publish pairing failed event: {e}")
192
336
 
@@ -195,6 +339,7 @@ class KernelRelay:
195
339
  "message": "Invalid pairing code"
196
340
  })
197
341
  await client_ws.close(code=4001, reason="Invalid pairing code")
342
+ await self._audit_log("auth.pair_failed", {"reason": "invalid_code"})
198
343
  return
199
344
 
200
345
  # 生成 session_token
@@ -213,6 +358,55 @@ class KernelRelay:
213
358
  """处理认证请求(已有 token)"""
214
359
  frontend_token = msg.get("token")
215
360
  session_token = msg.get("session_token")
361
+ auth_method = msg.get("method", "") # 可选:oauth
362
+
363
+ # OAuth auth_ticket 认证
364
+ if auth_method == "oauth":
365
+ auth_ticket = msg.get("auth_ticket")
366
+ if not auth_ticket:
367
+ await client_ws.send_json({
368
+ "type": "error",
369
+ "message": "Missing auth_ticket for OAuth auth"
370
+ })
371
+ await client_ws.close(code=4000, reason="Missing auth_ticket")
372
+ return
373
+
374
+ if not self.oauth_manager:
375
+ await client_ws.send_json({
376
+ "type": "error",
377
+ "message": "OAuth not configured"
378
+ })
379
+ await client_ws.close(code=4000, reason="OAuth not configured")
380
+ return
381
+
382
+ ticket_info = self.oauth_manager.verify_auth_ticket(auth_ticket)
383
+ if not ticket_info:
384
+ await client_ws.send_json({
385
+ "type": "error",
386
+ "message": "Invalid or expired auth_ticket"
387
+ })
388
+ await client_ws.close(code=4001, reason="Invalid auth_ticket")
389
+ await self._audit_log("auth.failed", {"reason": "invalid_auth_ticket", "auth_type": "oauth"})
390
+ return
391
+ print(f"[Relay] Authenticated via OAuth ({ticket_info['provider']}), user={ticket_info['user_info'].get('name', 'unknown')}")
392
+ await self._audit_log("auth.login", {
393
+ "auth_type": "oauth",
394
+ "provider": ticket_info["provider"],
395
+ "user": ticket_info["user_info"].get("name", "unknown"),
396
+ "role": role,
397
+ })
398
+
399
+ # 生成 session_token
400
+ if not session_token:
401
+ session_token = "sess_" + secrets.token_urlsafe(6)[:6]
402
+
403
+ await self._create_new_connection(
404
+ client_ws,
405
+ session_token,
406
+ f"oauth:{ticket_info['provider']}:{ticket_info['user_info'].get('id', '')}",
407
+ role
408
+ )
409
+ return
216
410
 
217
411
  if not frontend_token or not session_token:
218
412
  await client_ws.send_json({
@@ -222,16 +416,47 @@ class KernelRelay:
222
416
  await client_ws.close(code=4000, reason="Missing credentials")
223
417
  return
224
418
 
225
- # 验证 frontend_token
419
+ # 1. 尝试配对码认证
226
420
  token_info = self.pairing_manager.verify_token(frontend_token)
227
- if not token_info:
421
+ if token_info:
422
+ role = token_info["role"]
423
+ auth_type = "pairing"
424
+ print(f"[Relay] Authenticated via pairing code, role={role}")
425
+
426
+ # 2. 尝试 Kite Token 认证
427
+ elif self.auth_manager and self.auth_manager.verify_kite_token(frontend_token):
428
+ role = "admin" # Kite Token 用户默认为 admin
429
+ auth_type = "kite_token"
430
+ print(f"[Relay] Authenticated via Kite Token, role={role}")
431
+ # 构造 token_info 格式以保持兼容
432
+ token_info = {"role": role}
433
+
434
+ # 3. 认证失败
435
+ else:
228
436
  await client_ws.send_json({
229
437
  "type": "error",
230
438
  "message": "Invalid or expired token"
231
439
  })
232
440
  await client_ws.close(code=4001, reason="Invalid token")
441
+ await self._audit_log("auth.failed", {"reason": "invalid_token", "session_token": session_token})
233
442
  return
234
443
 
444
+ # 审计:认证成功
445
+ await self._audit_log("auth.login", {"auth_type": auth_type, "role": role, "session_token": session_token})
446
+
447
+ # MFA 检查(可选:如果该 token 配置了 MFA 密钥)
448
+ mfa_secret = self._mfa_secrets.get(frontend_token)
449
+ if mfa_secret:
450
+ mfa_code = msg.get("mfa_code", "")
451
+ if not mfa_code or not self._totp.verify(mfa_secret, mfa_code):
452
+ await client_ws.send_json({
453
+ "type": "error",
454
+ "message": "MFA verification failed"
455
+ })
456
+ await client_ws.close(code=4004, reason="MFA failed")
457
+ await self._audit_log("auth.mfa_failed", {"session_token": session_token})
458
+ return
459
+
235
460
  # 检查是否是重连
236
461
  if session_token in self.sessions:
237
462
  await self._handle_reconnect(client_ws, session_token, token_info)
@@ -240,7 +465,7 @@ class KernelRelay:
240
465
  client_ws,
241
466
  session_token,
242
467
  frontend_token,
243
- token_info["role"]
468
+ role
244
469
  )
245
470
 
246
471
  async def _create_new_connection(
@@ -257,8 +482,11 @@ class KernelRelay:
257
482
  module_id = f"{self.base_module_id}-{suffix}"
258
483
 
259
484
  try:
485
+ # 向 Launcher 申请 kernel_token
486
+ kernel_token = await self._request_kernel_token(module_id)
487
+
260
488
  # 连接 Kernel
261
- kernel_ws = await self._connect_kernel(module_id)
489
+ kernel_ws = await self._connect_kernel(module_id, kernel_token)
262
490
 
263
491
  # 创建 session
264
492
  session = SessionInfo(
@@ -268,6 +496,7 @@ class KernelRelay:
268
496
  client_ws=client_ws,
269
497
  frontend_token=frontend_token,
270
498
  role=role,
499
+ kernel_token=kernel_token,
271
500
  )
272
501
  self.sessions[session_token] = session
273
502
 
@@ -285,15 +514,16 @@ class KernelRelay:
285
514
  # 如果是配对,发送配对成功事件给 Launcher
286
515
  if is_pairing and self.web_server and self.web_server._ws:
287
516
  try:
288
- await self.web_server._publish_event({
289
- "event": "pairing.status",
290
- "data": {
517
+ await self.web_server._publish_event(
518
+ self.web_server._ws,
519
+ "pairing.status",
520
+ {
291
521
  "step": "completed",
292
522
  "success": True,
293
523
  "module_id": module_id,
294
524
  "role": role
295
525
  }
296
- })
526
+ )
297
527
  except Exception as e:
298
528
  print(f"[relay] Failed to publish pairing success event: {e}")
299
529
 
@@ -301,12 +531,39 @@ class KernelRelay:
301
531
  await self._relay_messages(session)
302
532
 
303
533
  except Exception as e:
304
- print(f"[relay] Failed to create connection: {e}")
534
+ error_msg = str(e)
535
+
536
+ # 判断错误类型
537
+ is_fatal = self._is_fatal_error(error_msg)
538
+ error_code = 1011 # Internal Error (default)
539
+
540
+ if is_fatal:
541
+ # 永久性错误(权限、配置错误)
542
+ error_code = 1008 # Policy Violation
543
+ print(f"\033[31m[relay] 致命错误: {error_msg}\033[0m")
544
+ if "relay_modules whitelist" in error_msg:
545
+ print(f"\033[31m[relay] 请在 launcher/module.md 的 relay.modules 中添加本模块名\033[0m")
546
+ else:
547
+ print(f"[relay] Failed to create connection: {error_msg}")
548
+
305
549
  await client_ws.send_json({
306
550
  "type": "error",
307
- "message": f"Failed to connect to Kernel: {str(e)}"
551
+ "message": f"Failed to connect to Kernel: {error_msg}",
552
+ "fatal": is_fatal, # 告知前端是否应该重试
553
+ "code": error_code
308
554
  })
309
- await client_ws.close(code=1011, reason="Kernel connection failed")
555
+ await client_ws.close(code=error_code, reason="Kernel connection failed")
556
+
557
+ def _is_fatal_error(self, error_msg: str) -> bool:
558
+ """判断是否为永久性错误(不应重试)"""
559
+ fatal_keywords = [
560
+ "Permission denied",
561
+ "not in relay_modules whitelist",
562
+ "module_id must start with",
563
+ "Invalid module_id",
564
+ "Token limit reached",
565
+ ]
566
+ return any(keyword in error_msg for keyword in fatal_keywords)
310
567
 
311
568
  async def _handle_reconnect(
312
569
  self,
@@ -339,33 +596,63 @@ class KernelRelay:
339
596
  # 继续双向转发
340
597
  await self._relay_messages(session)
341
598
 
342
- async def _connect_kernel(self, module_id: str):
599
+ async def _request_kernel_token(self, module_id: str) -> str:
600
+ """向 Launcher 申请 kernel_token"""
601
+ if not self.web_server or not self.web_server._ws:
602
+ raise RuntimeError("evol_server not connected to Kernel")
603
+
604
+ print(f"[relay] Requesting kernel_token for {module_id} from Launcher")
605
+
606
+ try:
607
+ resp = await self.web_server._rpc_call(
608
+ self.web_server._ws,
609
+ "launcher.request_client_token",
610
+ {"module_id": module_id}
611
+ )
612
+ # _rpc_call 返回完整 JSON-RPC 响应,需要解包 result 层
613
+ inner = resp.get("result", resp)
614
+ token = inner.get("token")
615
+ if not token:
616
+ raise RuntimeError(f"Launcher returned no token: {result}")
617
+
618
+ print(f"[relay] Received kernel_token for {module_id}")
619
+ return token
620
+
621
+ except Exception as e:
622
+ print(f"[relay] Failed to request kernel_token: {e}")
623
+ raise
624
+
625
+ async def _connect_kernel(self, module_id: str, kernel_token: str):
343
626
  """连接到 Kernel"""
344
- url = f"ws://{self.kernel_host}:{self.kernel_port}/ws?token={self.kernel_token}&id={module_id}"
627
+ url = f"ws://{self.kernel_host}:{self.kernel_port}/ws?id={module_id}"
628
+ print(f"[relay] DEBUG: Connecting to Kernel with module_id={module_id}")
345
629
  kernel_ws = await websockets.connect(
346
630
  url,
347
631
  open_timeout=5,
348
- ping_interval=20,
349
- ping_timeout=20,
632
+ ping_interval=None,
350
633
  close_timeout=10
351
634
  )
635
+ print(f"[relay] DEBUG: Connected to Kernel")
352
636
 
353
- # 订阅事件
637
+ # 1. 先发送认证请求(Kernel 要求第一条消息必须是 auth)
638
+ auth_id = str(uuid.uuid4())
354
639
  await self._send_to_kernel(kernel_ws, {
355
640
  "jsonrpc": "2.0",
356
- "id": str(uuid.uuid4()),
357
- "method": "event.subscribe",
641
+ "id": auth_id,
642
+ "method": "auth",
358
643
  "params": {
359
- "events": [
360
- "module.started",
361
- "module.stopped",
362
- "module.crashed",
363
- "module.ready",
364
- ]
644
+ "token": kernel_token
365
645
  }
366
646
  })
367
647
 
368
- # 注册模块
648
+ # 等待认证响应
649
+ auth_response = await asyncio.wait_for(kernel_ws.recv(), timeout=5.0)
650
+ auth_msg = json.loads(auth_response)
651
+ if "error" in auth_msg:
652
+ raise RuntimeError(f"Kernel auth failed: {auth_msg['error']}")
653
+ print(f"[relay] DEBUG: Kernel auth success")
654
+
655
+ # 2. 注册模块(不预订阅事件,由前端自己决定)
369
656
  await self._send_to_kernel(kernel_ws, {
370
657
  "jsonrpc": "2.0",
371
658
  "id": str(uuid.uuid4()),
@@ -373,12 +660,6 @@ class KernelRelay:
373
660
  "params": {
374
661
  "module_id": module_id,
375
662
  "module_type": "web_client",
376
- "events_subscribe": [
377
- "module.started",
378
- "module.stopped",
379
- "module.crashed",
380
- "module.ready",
381
- ]
382
663
  }
383
664
  })
384
665
 
@@ -440,10 +721,13 @@ class KernelRelay:
440
721
 
441
722
  async def _forward_client_to_kernel(self, session: SessionInfo):
442
723
  """转发客户端消息到 Kernel(带权限检查)"""
443
- while True:
444
- raw = await session.client_ws.receive_text()
724
+ try:
725
+ while True:
726
+ raw = await session.client_ws.receive_text()
445
727
  msg = json.loads(raw)
446
728
 
729
+ # print(f"[relay] Client → Kernel: {msg.get('method', msg.get('type', 'unknown'))}")
730
+
447
731
  # 处理心跳 ping
448
732
  if msg.get("type") == "ping":
449
733
  await session.client_ws.send_json({"type": "pong"})
@@ -474,13 +758,35 @@ class KernelRelay:
474
758
  await self._handle_web_rpc(session, msg)
475
759
  continue
476
760
 
477
- # 转发到 Kernel
761
+ # 转发到 Kernel(包括 evol.* 调用)
762
+ # print(f"[relay] Forwarding to Kernel: {method}")
478
763
  await self._send_to_kernel(session.kernel_ws, msg)
764
+ except (WebSocketDisconnect, AttributeError, asyncio.CancelledError,
765
+ websockets.exceptions.ConnectionClosedOK, websockets.exceptions.ConnectionClosedError):
766
+ pass # 客户端断开或 Kernel 连接关闭,正常退出
479
767
 
480
768
  async def _forward_kernel_to_client(self, session: SessionInfo):
481
769
  """转发 Kernel 消息到客户端"""
482
- async for raw in session.kernel_ws:
770
+ try:
771
+ async for raw in session.kernel_ws:
772
+ # 解析消息内容用于日志
773
+ # try:
774
+ # msg = json.loads(raw)
775
+ # if "method" in msg:
776
+ # print(f"[relay] Kernel → Client: {msg['method']} ({len(raw)} bytes)")
777
+ # elif "result" in msg:
778
+ # print(f"[relay] Kernel → Client: response id={msg.get('id')} ({len(raw)} bytes)")
779
+ # elif "error" in msg:
780
+ # print(f"[relay] Kernel → Client: error id={msg.get('id')} ({len(raw)} bytes)")
781
+ # else:
782
+ # print(f"[relay] Kernel → Client: {len(raw)} bytes")
783
+ # except:
784
+ # print(f"[relay] Kernel → Client: {len(raw)} bytes")
483
785
  await session.client_ws.send_text(raw)
786
+ except (websockets.exceptions.ConnectionClosedOK, websockets.exceptions.ConnectionClosedError):
787
+ pass # Kernel 连接关闭,正常退出
788
+ except Exception:
789
+ pass # client_ws 断开或被置 None,正常退出
484
790
 
485
791
  def _check_permission(self, role: str, msg: dict) -> bool:
486
792
  """检查 RPC 权限"""
@@ -526,9 +832,10 @@ class KernelRelay:
526
832
  async def _graceful_shutdown(self, session: SessionInfo):
527
833
  """代表前端执行优雅退出"""
528
834
  print(f"[relay] Graceful shutdown: {session.module_id}")
835
+ await self._audit_log("auth.logout", {"module_id": session.module_id, "reason": "reconnect_timeout"})
529
836
 
530
837
  try:
531
- # 发送 module.exiting 事件
838
+ # 发送 module.exiting 事件(带 token_revoked 标记)
532
839
  await self._send_to_kernel(session.kernel_ws, {
533
840
  "jsonrpc": "2.0",
534
841
  "id": str(uuid.uuid4()),
@@ -538,7 +845,8 @@ class KernelRelay:
538
845
  "event": "module.exiting",
539
846
  "data": {
540
847
  "module_id": session.module_id,
541
- "action": "none"
848
+ "action": "none",
849
+ "token_revoked": True
542
850
  }
543
851
  }
544
852
  })
@@ -587,7 +895,7 @@ class KernelRelay:
587
895
  method = method[4:]
588
896
 
589
897
  try:
590
- # 调用 web_server 的 RPC 处理器
898
+ # 调用 evol_server 的 RPC 处理器
591
899
  if method == "list_tokens":
592
900
  print(f"[relay] Calling list_tokens")
593
901
  result = await self.web_server._rpc_list_tokens()
@@ -600,23 +908,25 @@ class KernelRelay:
600
908
  print(f"[relay] RPC success: {method}, result keys: {list(result.keys()) if isinstance(result, dict) else type(result)}")
601
909
 
602
910
  # 返回结果
603
- await session.client_ws.send_json({
604
- "jsonrpc": "2.0",
605
- "id": rpc_id,
606
- "result": result
607
- })
911
+ if session.client_ws:
912
+ await session.client_ws.send_json({
913
+ "jsonrpc": "2.0",
914
+ "id": rpc_id,
915
+ "result": result
916
+ })
608
917
  except Exception as e:
609
918
  # 红色高亮显示 RPC 错误
610
919
  print(f"\033[91m[relay] ✗ RPC 错误: {method}, 错误: {e}\033[0m")
611
- # 返回错误
612
- await session.client_ws.send_json({
613
- "jsonrpc": "2.0",
614
- "id": rpc_id,
615
- "error": {
616
- "code": -32603,
617
- "message": str(e)
618
- }
619
- })
920
+ # 返回错误(仅当连接存在时)
921
+ if session.client_ws:
922
+ await session.client_ws.send_json({
923
+ "jsonrpc": "2.0",
924
+ "id": rpc_id,
925
+ "error": {
926
+ "code": -32603,
927
+ "message": str(e)
928
+ }
929
+ })
620
930
 
621
931
  async def close_all_sessions(self):
622
932
  """优雅关闭所有会话(用于 shutdown)"""
@@ -641,3 +951,72 @@ class KernelRelay:
641
951
 
642
952
  self.sessions.clear()
643
953
  print(f"[relay] All sessions closed")
954
+
955
+ # ── 审计日志 ──
956
+
957
+ async def _audit_log(self, event: str, data: dict):
958
+ """
959
+ 发布 auth.* 审计事件到 Kernel。
960
+
961
+ Args:
962
+ event: 事件名(如 auth.login, auth.logout, auth.failed)
963
+ data: 事件数据
964
+ """
965
+ if not self.web_server or not self.web_server._ws:
966
+ return
967
+ try:
968
+ await self.web_server._publish_event(
969
+ self.web_server._ws,
970
+ event,
971
+ {
972
+ **data,
973
+ "timestamp": time.time(),
974
+ "source": "relay",
975
+ }
976
+ )
977
+ except Exception as e:
978
+ print(f"[relay] Audit log failed: {e}")
979
+
980
+ # ── 速率限制 ──
981
+
982
+ def _check_rate_limit(self, ip: str, device_id: str) -> bool:
983
+ """
984
+ 检查 (IP, device_id) 是否超出速率限制。
985
+
986
+ Returns:
987
+ True 表示允许,False 表示被限制
988
+ """
989
+ key = (ip, device_id)
990
+ now = time.time()
991
+ cutoff = now - self._rate_limit_window
992
+
993
+ # 获取或创建时间戳列表
994
+ timestamps = self._rate_limits.get(key, [])
995
+
996
+ # 清理过期的时间戳
997
+ timestamps = [t for t in timestamps if t > cutoff]
998
+
999
+ # 检查是否超限
1000
+ if len(timestamps) >= self._rate_limit_max:
1001
+ self._rate_limits[key] = timestamps
1002
+ return False
1003
+
1004
+ # 记录本次请求
1005
+ timestamps.append(now)
1006
+ self._rate_limits[key] = timestamps
1007
+
1008
+ # 定期清理长期不活跃的 key(避免内存泄漏)
1009
+ if len(self._rate_limits) > 1000:
1010
+ self._cleanup_rate_limits(now)
1011
+
1012
+ return True
1013
+
1014
+ def _cleanup_rate_limits(self, now: float):
1015
+ """清理不活跃的速率限制条目"""
1016
+ cutoff = now - self._rate_limit_window * 10 # 10 个窗口期未活跃则清理
1017
+ expired = [
1018
+ k for k, ts_list in self._rate_limits.items()
1019
+ if not ts_list or ts_list[-1] < cutoff
1020
+ ]
1021
+ for k in expired:
1022
+ del self._rate_limits[k]