@agentunion/kite 1.5.0 → 1.6.1

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 (574) 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/__init__.py +9 -1
  492. package/kite_cli/builders/__init__.py +4 -0
  493. package/kite_cli/builders/base.py +67 -0
  494. package/kite_cli/builders/custom.py +31 -0
  495. package/kite_cli/builders/detector.py +56 -0
  496. package/kite_cli/builders/go.py +34 -0
  497. package/kite_cli/builders/gradle.py +41 -0
  498. package/kite_cli/builders/maven.py +36 -0
  499. package/kite_cli/builders/npm.py +44 -0
  500. package/kite_cli/builders/python.py +37 -0
  501. package/kite_cli/commands/BUILD_GUIDE.md +109 -0
  502. package/kite_cli/commands/build.py +142 -0
  503. package/kite_cli/commands/check.py +60 -0
  504. package/kite_cli/commands/config.py +156 -0
  505. package/kite_cli/commands/deps.py +58 -0
  506. package/kite_cli/commands/deps_install.py +7 -7
  507. package/kite_cli/commands/disable.py +162 -0
  508. package/kite_cli/commands/enable.py +162 -0
  509. package/kite_cli/commands/export.py +96 -0
  510. package/kite_cli/commands/import_cmd.py +110 -0
  511. package/kite_cli/commands/install.py +50 -23
  512. package/kite_cli/commands/install_skill.py +107 -0
  513. package/kite_cli/commands/list.py +128 -31
  514. package/kite_cli/commands/outdated.py +202 -0
  515. package/kite_cli/commands/search.py +33 -17
  516. package/kite_cli/commands/update.py +115 -2
  517. package/kite_cli/commands/venv_setup.py +6 -6
  518. package/kite_cli/commands/why.py +48 -0
  519. package/kite_cli/core/config_manager.py +145 -0
  520. package/kite_cli/core/downloader.py +32 -2
  521. package/kite_cli/main.py +153 -7
  522. package/kite_cli/utils/colors.py +153 -0
  523. package/kite_cli/utils/dependency_graph.py +209 -0
  524. package/kite_cli/utils/process.py +55 -0
  525. package/kite_cli/utils/progress.py +207 -0
  526. package/kite_cli/utils/table.py +101 -0
  527. package/launcher/count_lines.py +192 -43
  528. package/launcher/entry.py +4543 -2802
  529. package/launcher/logging_setup.py +54 -1
  530. package/launcher/module.md +32 -6
  531. package/launcher/module_scanner.py +93 -20
  532. package/launcher/process_manager.py +355 -76
  533. package/main.py +6 -0
  534. package/package.json +4 -1
  535. package/requirements.txt +41 -38
  536. package/scripts/auto-fix-deps.py +128 -0
  537. package/scripts/env-manager.js +25 -2
  538. package/scripts/final-test.js +78 -0
  539. package/scripts/setup-python-env.js +700 -191
  540. package/scripts/test-alluser.js +48 -0
  541. package/scripts/test-different-version.js +86 -0
  542. package/scripts/test-direct.js +63 -0
  543. package/scripts/test-extract-installer.js +28 -0
  544. package/scripts/test-install-log.js +54 -0
  545. package/scripts/test-installer.js +39 -0
  546. package/scripts/test-integration.js +250 -0
  547. package/scripts/test-real-install.js +210 -0
  548. package/scripts/test-targetdir.js +49 -0
  549. package/scripts/test-venv-real.js +47 -0
  550. package/scripts/test-venv-simple.js +57 -0
  551. package/scripts/test-wait.js +49 -0
  552. package/scripts/test-with-log.js +63 -0
  553. package/extensions/services/evol/config.yaml +0 -149
  554. package/extensions/services/evol/routes/routes_management_ws.py +0 -127
  555. package/extensions/services/evol/static/index_evol.html +0 -14
  556. package/extensions/services/evol/static/js/app.js +0 -6304
  557. package/extensions/services/evol/static/js/auth.js +0 -326
  558. package/extensions/services/evol/static/js/evol-app-fixed.js +0 -50
  559. package/extensions/services/evol/static/js/evol-app.js.bak +0 -1800
  560. package/extensions/services/evol/static/js/kernel-client-example.js +0 -228
  561. package/extensions/services/evol/static/js/main.js +0 -141
  562. package/extensions/services/evol/static/js/stats.js +0 -217
  563. package/extensions/services/evol/static/js/token-manager.js +0 -175
  564. package/extensions/services/proxy/CHANGELOG_20260308.md +0 -258
  565. package/extensions/services/proxy/_fix_prints.py +0 -133
  566. package/extensions/services/proxy/_fix_prints2.py +0 -87
  567. package/extensions/services/proxy/console_auth.py +0 -109
  568. package/extensions/services/proxy/logs/websocket.log +0 -260
  569. package/extensions/services/proxy/main.py +0 -240
  570. package/extensions/services/proxy/requirements.txt +0 -13
  571. package/extensions/services/web/config.yaml +0 -149
  572. /package/extensions/services/{evol → kite_console}/static/pairing.html +0 -0
  573. /package/extensions/services/{evol → kite_console}/static/test_registry.html +0 -0
  574. /package/extensions/services/{evol → kite_console}/static/test_relay.html +0 -0
@@ -11,6 +11,7 @@ import logging
11
11
  import os
12
12
  import time
13
13
  import uuid
14
+ import random
14
15
  from datetime import datetime, timezone
15
16
  from pathlib import Path
16
17
 
@@ -48,26 +49,36 @@ SYSTEM_BROADCAST_EVENTS = {
48
49
  "module.crashed", "module.exiting", "module.offline",
49
50
  "module.shutdown.ack", "module.shutdown.ready",
50
51
  "system.ready", "registry.updated",
52
+ "system.instance.started", "system.instance.stopped",
51
53
  }
52
54
 
53
55
 
54
56
  class WebServer:
55
57
 
56
58
  def __init__(self, token: str = "", kernel_port: int = 0,
57
- host: str = "0.0.0.0", port: int = 0, boot_t0: float = 0):
59
+ host: str = "0.0.0.0", port: int = 0, boot_t0: float = 0,
60
+ max_connections: int = 1,
61
+ gateway_url: str = "", kite_token: str = ""):
58
62
  self.token = token
59
63
  self.kernel_port = kernel_port
60
64
  self.host = host
61
65
  self.port = port
62
66
  self.boot_t0 = boot_t0
67
+ self.max_connections = max_connections
68
+ self.gateway_url = gateway_url
69
+ self.kite_token = kite_token
70
+ self._extra_ws: dict = {} # slot → WebSocket
71
+ self._extra_ws_tasks: dict = {} # slot → recv loop Task
63
72
  self._ws_task: asyncio.Task | None = None
64
73
  self._test_task: asyncio.Task | None = None
65
74
  self._ws: object | None = None
66
75
  self._shutting_down = False
67
76
  self._exit_code = 0 # Exit code for main() to use
77
+ self._auth_failed = False
68
78
  self._uvicorn_server = None # set by entry.py for graceful shutdown
69
79
  self._start_time = time.time()
70
- self._rpc_futures = {} # Store pending RPC request futures
80
+ self._pending_rpc: dict[str, asyncio.Future] = {} # 等待响应的 RPC futures
81
+ self._has_registered = False
71
82
  self.bt_manager: BluetoothManager | None = None
72
83
  self.task_manager: TaskManager | None = None
73
84
  self.app = self._create_app()
@@ -78,6 +89,21 @@ class WebServer:
78
89
 
79
90
  @app.on_event("startup")
80
91
  async def _startup():
92
+ # Token already set in entry.py, no need to read from stdin
93
+ if not server.token:
94
+ print("[web] ERROR: Missing token, cannot connect to Kernel")
95
+ return
96
+
97
+ # Start Kernel WS connection (module.ready depends on this)
98
+ if server.kernel_port:
99
+ server._ws_task = asyncio.create_task(server._ws_loop())
100
+ server._test_task = asyncio.create_task(server._test_event_loop())
101
+
102
+ # Business initialization in background (does not block module.ready)
103
+ asyncio.create_task(_deferred_init())
104
+
105
+ async def _deferred_init():
106
+ """Business initialization that runs after WS connection starts."""
81
107
  # Load business configurations
82
108
  module_dir = Path(__file__).parent
83
109
  business_configs = load_business_configs(str(module_dir))
@@ -148,11 +174,6 @@ class WebServer:
148
174
 
149
175
  logger.info("Web Management: managers initialized")
150
176
 
151
- # Start background tasks directly
152
- if server.kernel_port:
153
- server._ws_task = asyncio.create_task(server._ws_loop())
154
- server._test_task = asyncio.create_task(server._test_event_loop())
155
-
156
177
  @app.on_event("shutdown")
157
178
  async def _shutdown():
158
179
  if server._ws_task:
@@ -254,143 +275,200 @@ class WebServer:
254
275
 
255
276
  return app
256
277
 
278
+ # ── system.require_init 处理 ──
279
+
280
+ async def _do_init(self, ws):
281
+ """收到 system.require_init 后执行:订阅 + 注册 + module.ready"""
282
+ reason = "startup" if not self._has_registered else "recovery"
283
+ print(f"[web] Received system.require_init (reason={reason})")
284
+
285
+ try:
286
+ # Subscribe to events
287
+ await self._rpc_call(ws, "event.subscribe", {
288
+ "events": [
289
+ "module.started",
290
+ "module.stopped",
291
+ "module.crashed",
292
+ "module.ready",
293
+ "module.exiting",
294
+ "module.shutdown",
295
+ "module.shutdown.ack",
296
+ "module.shutdown.ready",
297
+ ],
298
+ })
299
+
300
+ # Register to Kernel Registry via RPC
301
+ await self._rpc_call(ws, "registry.register", {
302
+ "module_id": "web",
303
+ "module_type": "service",
304
+ "base_url": f"http://127.0.0.1:{self.port}",
305
+ "health_path": "/health",
306
+ "display": {
307
+ "urls": {
308
+ "Web 管理后台": f"http://127.0.0.1:{self.port}"
309
+ }
310
+ },
311
+ "tools": {
312
+ "rpc": {
313
+ "module": {
314
+ "health": {"method": "health", "description": "健康检查"},
315
+ "status": {"method": "status", "description": "状态查询"}
316
+ },
317
+ "web": {
318
+ "list_tokens": {"method": "list_tokens", "description": "列出所有令牌"},
319
+ "revoke_token": {"method": "revoke_token", "description": "撤销令牌"}
320
+ }
321
+ }
322
+ },
323
+ "events_publish": {
324
+ "web": {
325
+ "test": {"description": "Test event from web module"},
326
+ "started": {"description": "Web UI started with access URL"},
327
+ }
328
+ },
329
+ "events_subscribe": [
330
+ "module.started",
331
+ "module.stopped",
332
+ "module.crashed",
333
+ "module.ready",
334
+ "module.exiting",
335
+ "module.shutdown",
336
+ "module.shutdown.ack",
337
+ "module.shutdown.ready",
338
+ ],
339
+ })
340
+ elapsed = time.monotonic() - self.boot_t0 if self.boot_t0 else 0
341
+ elapsed_str = f" ({elapsed:.1f}s)" if elapsed else ""
342
+ print(f"[web] Registered to Kernel{elapsed_str}")
343
+
344
+ # Send module.ready
345
+ if not self._shutting_down:
346
+ startup_time = time.monotonic() - self.boot_t0 if self.boot_t0 else 0
347
+ await self._publish_event(ws, "module.ready", {
348
+ "module_id": "web",
349
+ "graceful_shutdown": True,
350
+ "startup_time": startup_time,
351
+ "reason": reason,
352
+ })
353
+ elapsed = time.monotonic() - self.boot_t0 if self.boot_t0 else 0
354
+ if elapsed < 1:
355
+ elapsed_str = f"{elapsed * 1000:.0f}ms"
356
+ elif elapsed < 10:
357
+ elapsed_str = f"{elapsed:.1f}s"
358
+ else:
359
+ elapsed_str = f"{elapsed:.0f}s"
360
+ print(f"[web] module.ready published ({elapsed_str})")
361
+
362
+ # Publish web.started event with access URL
363
+ display_host = "localhost" if self.host == "0.0.0.0" else self.host
364
+ access_url = f"http://{display_host}:{self.port}"
365
+ await self._publish_event(ws, "web.started", {
366
+ "module_id": "web",
367
+ "url": access_url,
368
+ "host": self.host,
369
+ "port": self.port,
370
+ })
371
+
372
+ self._has_registered = True
373
+
374
+ except Exception as e:
375
+ print(f"[web] _do_init failed: {e}")
376
+
257
377
  # ── Kernel WebSocket client ──
258
378
 
259
379
  async def _ws_loop(self):
260
380
  """Connect to Kernel, subscribe, register, and listen. Reconnect on failure."""
261
- retry_delay = 0.3
262
- max_delay = 5.0
263
- max_retries = 10
381
+ retry_delay = 0.5
382
+ max_delay = 10.0
264
383
  attempt = 0
384
+ cooldown_attempts = 0
385
+
265
386
  while not self._shutting_down:
266
387
  try:
267
388
  await self._ws_connect()
268
- retry_delay = 0.3 # reset on successful connection
389
+ retry_delay = 0.5
269
390
  attempt = 0
391
+ cooldown_attempts = 0
270
392
  except asyncio.CancelledError:
271
393
  print(f"[web] WS loop cancelled")
272
394
  return
273
395
  except Exception as e:
274
- attempt += 1
275
- # Auth failure don't retry
276
- if hasattr(e, 'rcvd') and e.rcvd is not None:
277
- code = e.rcvd.code if hasattr(e.rcvd, 'code') else 0
278
- if code in (4001, 4003):
279
- print(f"[web] Kernel 认证失败 (code {code}),退出")
280
- self._exit_code = 1
281
- self._shutting_down = True
282
- if self._uvicorn_server:
283
- self._uvicorn_server.should_exit = True
284
- return
285
- if attempt >= max_retries:
286
- print(f"[web] Kernel 重连失败 {max_retries} 次,退出")
396
+ if self._shutting_down:
397
+ print(f"[web] Shutting down, not retrying connection")
398
+ return
399
+
400
+ code = self._get_close_code(e)
401
+
402
+ # never: 永不重连
403
+ if code in (4001, 4003, 4004, 1008, 4010):
404
+ print(f"[web] 致命错误 (code {code}),退出")
287
405
  self._exit_code = 1
406
+ self._auth_failed = True
288
407
  self._shutting_down = True
289
408
  if self._uvicorn_server:
290
409
  self._uvicorn_server.should_exit = True
291
410
  return
292
- if self._shutting_down:
293
- print(f"[web] Shutting down, not retrying connection")
294
- return
295
- print(f"[web] Kernel connection error: {e}, retrying in {retry_delay:.1f}s ({attempt}/{max_retries})")
411
+
412
+ # cooldown: 速率限制
413
+ if code == 4020:
414
+ cooldown_attempts += 1
415
+ if cooldown_attempts >= 5:
416
+ print(f"[web] 速率限制重试 5 次,退出")
417
+ self._exit_code = 1
418
+ self._shutting_down = True
419
+ if self._uvicorn_server:
420
+ self._uvicorn_server.should_exit = True
421
+ return
422
+ print(f"[web] 速率限制,10.0s 后重试 ({cooldown_attempts}/5)")
423
+ await asyncio.sleep(10.0)
424
+ continue
425
+
426
+ # standard: 指数退避 + jitter
427
+ attempt += 1
428
+ jitter = retry_delay * 0.2 * random.random()
429
+ sleep_time = retry_delay + jitter
430
+ print(f"[web] Kernel connection error: {e}, retrying in {sleep_time:.1f}s (attempt {attempt})")
431
+
296
432
  self._ws = None
297
433
  if self._shutting_down:
298
434
  print(f"[web] Shutting down, exiting WS loop")
299
435
  return
300
- await asyncio.sleep(retry_delay)
436
+ await asyncio.sleep(sleep_time if 'sleep_time' in locals() else retry_delay)
301
437
  retry_delay = min(retry_delay * 2, max_delay)
302
438
 
439
+ def _get_close_code(self, e: Exception) -> int:
440
+ """从 websockets 异常中提取关闭码"""
441
+ if hasattr(e, 'rcvd') and e.rcvd is not None:
442
+ return getattr(e.rcvd, 'code', 0)
443
+ return 0
444
+
303
445
  async def _ws_connect(self):
304
446
  """Single WebSocket session: connect, register, subscribe, receive loop."""
305
- url = f"ws://127.0.0.1:{self.kernel_port}/ws?token={self.token}&id=web"
447
+ url = f"ws://127.0.0.1:{self.kernel_port}/ws?id=web"
306
448
  print(f"[web] WS connecting to Kernel")
307
449
  try:
308
450
  async with websockets.connect(url, open_timeout=5, ping_interval=None, close_timeout=10) as ws:
451
+ # Send auth message first
452
+ auth_req = {
453
+ "jsonrpc": "2.0",
454
+ "id": "auth",
455
+ "method": "auth",
456
+ "params": {"token": self.token}
457
+ }
458
+ await ws.send(json.dumps(auth_req))
459
+
460
+ # Wait for auth response
461
+ auth_resp_raw = await asyncio.wait_for(ws.recv(), timeout=5)
462
+ auth_resp = json.loads(auth_resp_raw)
463
+ if "error" in auth_resp:
464
+ raise Exception(f"Auth failed: {auth_resp['error']}")
465
+
309
466
  self._ws = ws
310
467
  elapsed = time.monotonic() - self.boot_t0 if self.boot_t0 else 0
311
468
  elapsed_str = f" ({elapsed:.1f}s)" if elapsed else ""
312
469
  print(f"[web] Connected to Kernel{elapsed_str}")
313
470
 
314
- # Subscribe to events
315
- await self._rpc_call(ws, "event.subscribe", {
316
- "events": [
317
- "module.started",
318
- "module.stopped",
319
- "module.crashed",
320
- "module.ready",
321
- "module.exiting",
322
- "module.shutdown",
323
- "module.shutdown.ack",
324
- "module.shutdown.ready",
325
- ],
326
- })
327
-
328
- # Register to Kernel Registry via RPC
329
- await self._rpc_call(ws, "registry.register", {
330
- "module_id": "web",
331
- "module_type": "service",
332
- "api_endpoint": f"http://127.0.0.1:{self.port}",
333
- "health_endpoint": "/health",
334
- "tools": {
335
- "rpc": {
336
- "module": {
337
- "health": {"method": "health", "description": "健康检查"},
338
- "status": {"method": "status", "description": "状态查询"}
339
- },
340
- "web": {
341
- "list_tokens": {"method": "list_tokens", "description": "列出所有令牌"},
342
- "revoke_token": {"method": "revoke_token", "description": "撤销令牌"}
343
- }
344
- }
345
- },
346
- "events_publish": {
347
- "web": {
348
- "test": {"description": "Test event from web module"},
349
- "started": {"description": "Web UI started with access URL"},
350
- }
351
- },
352
- "events_subscribe": [
353
- "module.started",
354
- "module.stopped",
355
- "module.crashed",
356
- "module.ready",
357
- "module.exiting",
358
- "module.shutdown",
359
- "module.shutdown.ack",
360
- "module.shutdown.ready",
361
- ],
362
- })
363
- print(f"[web] Registered to Kernel{elapsed_str}")
364
-
365
- # Send module.ready (every reconnect, not just first time)
366
- if not self._shutting_down:
367
- startup_time = time.monotonic() - self.boot_t0 if self.boot_t0 else 0
368
- await self._rpc_call(ws, "event.publish", {
369
- "event_id": str(uuid.uuid4()),
370
- "event": "module.ready",
371
- "data": {
372
- "module_id": "web",
373
- "graceful_shutdown": True,
374
- "startup_time": startup_time,
375
- },
376
- })
377
- elapsed_str = self._fmt_elapsed(self.boot_t0)
378
- print(f"[web] module.ready published ({elapsed_str})")
379
-
380
- # Publish web.started event with access URL
381
- display_host = "localhost" if self.host == "0.0.0.0" else self.host
382
- access_url = f"http://{display_host}:{self.port}"
383
- await self._publish_event({
384
- "event": "web.started",
385
- "data": {
386
- "module_id": "web",
387
- "url": access_url,
388
- "host": self.host,
389
- "port": self.port,
390
- },
391
- })
392
-
393
- # Receive loop
471
+ # Receive loop (system.require_init will trigger _do_init)
394
472
  # CRITICAL: RPC 死锁防范
395
473
  # - 入站 RPC 请求必须用 create_task() 异步执行,不可 await
396
474
  # - 原因:如果 handler 内部调用 rpc_call() 发出站请求,出站响应需要本接收循环来分发
@@ -411,16 +489,20 @@ class WebServer:
411
489
  has_result_or_error = "result" in msg or "error" in msg
412
490
 
413
491
  if has_method and not has_id:
414
- # Event Notification
415
- await self._handle_event_notification(msg)
492
+ # 检测 system.require_init 事件
493
+ params = msg.get("params", {})
494
+ event_type = params.get("event", "")
495
+ if event_type == "system.require_init":
496
+ asyncio.create_task(self._do_init(ws))
497
+ continue
498
+ # Event Notification — run in background to prevent deadlock
499
+ asyncio.create_task(self._handle_event_notification(msg))
416
500
  elif has_method and has_id:
417
501
  # Incoming RPC request — run in background to prevent deadlock
418
502
  asyncio.create_task(self._handle_rpc_request(ws, msg))
419
503
  elif has_id and has_result_or_error:
420
504
  # RPC response — resolve pending future
421
- rpc_id = msg.get("id")
422
- if rpc_id in self._rpc_futures:
423
- self._rpc_futures[rpc_id].set_result(msg)
505
+ self._handle_rpc_response(msg)
424
506
  except Exception as e:
425
507
  print(f"[web] 消息处理异常(已忽略): {e}")
426
508
  except Exception as e:
@@ -433,13 +515,37 @@ class WebServer:
433
515
  finally:
434
516
  print(f"[web] WebSocket connection closed")
435
517
  self._ws = None
436
-
437
- async def _rpc_call(self, ws, method: str, params: dict = None):
438
- """Send a JSON-RPC 2.0 request (fire-and-forget, no response awaited)."""
439
- msg = {"jsonrpc": "2.0", "id": str(uuid.uuid4()), "method": method}
518
+ # 清理所有 pending RPC futures(连接断开,不会再收到响应)
519
+ for rpc_id, future in self._pending_rpc.items():
520
+ if not future.done():
521
+ future.set_exception(ConnectionError("WebSocket disconnected"))
522
+ self._pending_rpc.clear()
523
+
524
+ async def _rpc_call(self, ws, method: str, params: dict = None,
525
+ wait_response: bool = True, timeout: float = 3.0) -> dict:
526
+ """JSON-RPC 2.0 request。默认等待响应。"""
527
+ rpc_id = str(uuid.uuid4())
528
+ msg = {"jsonrpc": "2.0", "id": rpc_id, "method": method}
440
529
  if params:
441
530
  msg["params"] = params
531
+ if not wait_response:
532
+ await ws.send(json.dumps(msg))
533
+ return {}
534
+ future = asyncio.get_event_loop().create_future()
535
+ self._pending_rpc[rpc_id] = future
442
536
  await ws.send(json.dumps(msg))
537
+ try:
538
+ return await asyncio.wait_for(future, timeout=timeout)
539
+ except asyncio.TimeoutError:
540
+ self._pending_rpc.pop(rpc_id, None)
541
+ return {"error": {"code": -32000, "message": f"RPC timeout: {method} ({timeout}s)"}}
542
+
543
+ def _handle_rpc_response(self, msg: dict):
544
+ """分发 RPC 响应到对应的 pending future。"""
545
+ rpc_id = msg.get("id")
546
+ future = self._pending_rpc.pop(rpc_id, None)
547
+ if future and not future.done():
548
+ future.set_result(msg)
443
549
 
444
550
  async def _handle_ping_event(self, data: dict):
445
551
  """Handle system.ping event and reply with system.pong."""
@@ -447,13 +553,10 @@ class WebServer:
447
553
  t1 = data.get("ping_time")
448
554
  t2 = time.time()
449
555
 
450
- await self._publish_event({
451
- "event": "system.pong",
452
- "data": {
453
- "module_id": "web",
454
- "ping_time": t1,
455
- "pong_time": t2,
456
- },
556
+ await self._publish_event(self._ws, "system.pong", {
557
+ "module_id": "web",
558
+ "ping_time": t1,
559
+ "pong_time": t2,
457
560
  })
458
561
 
459
562
  async def _handle_event_notification(self, msg: dict):
@@ -467,6 +570,14 @@ class WebServer:
467
570
  await self._handle_ping_event(data)
468
571
  return
469
572
 
573
+ # 弹性连接 offer/release
574
+ if event_type == "system.connection.offer":
575
+ asyncio.create_task(self._handle_connection_offer(data))
576
+ return
577
+ if event_type == "system.connection.release":
578
+ asyncio.create_task(self._handle_connection_release(data))
579
+ return
580
+
470
581
  # Log all events for debugging
471
582
  print(f"[web] Event received: {event_type}, data: {data}")
472
583
 
@@ -629,6 +740,74 @@ class WebServer:
629
740
 
630
741
  return {"success": True, "message": "Token revoked successfully"}
631
742
 
743
+ async def _handle_connection_offer(self, data):
744
+ """处理 Kernel 下发的 slot token,建立附加连接。"""
745
+ slots = data.get("slots", {})
746
+ for slot_str, info in slots.items():
747
+ slot = int(slot_str)
748
+ token = info.get("token", "")
749
+ if not token or slot in self._extra_ws:
750
+ continue
751
+ asyncio.create_task(self._connect_slot(slot, token))
752
+
753
+ async def _connect_slot(self, slot, token):
754
+ """建立单个 slot 附加连接。"""
755
+ ws_url = f"ws://127.0.0.1:{self.kernel_port}/ws"
756
+ try:
757
+ ws = await websockets.connect(ws_url, open_timeout=5, ping_interval=None, close_timeout=5)
758
+ auth_req = {"jsonrpc": "2.0", "id": f"auth-slot-{slot}", "method": "auth", "params": {"token": token}}
759
+ await ws.send(json.dumps(auth_req))
760
+ resp = json.loads(await asyncio.wait_for(ws.recv(), timeout=5))
761
+ if "error" in resp:
762
+ await ws.close()
763
+ return
764
+ self._extra_ws[slot] = ws
765
+ self._extra_ws_tasks[slot] = asyncio.create_task(self._slot_recv_loop(slot, ws))
766
+ print(f"[web] Slot {slot} connected")
767
+ except Exception as e:
768
+ print(f"[web] Slot {slot} connect failed: {e}")
769
+
770
+ async def _slot_recv_loop(self, slot, ws):
771
+ """附加 slot 接收循环:与主连接平等处理所有消息。"""
772
+ try:
773
+ async for raw in ws:
774
+ try:
775
+ msg = json.loads(raw)
776
+ except (json.JSONDecodeError, TypeError):
777
+ continue
778
+
779
+ try:
780
+ has_method = "method" in msg
781
+ has_id = "id" in msg
782
+ has_result_or_error = "result" in msg or "error" in msg
783
+
784
+ if has_method and not has_id:
785
+ asyncio.create_task(self._handle_event_notification(msg))
786
+ elif has_method and has_id:
787
+ asyncio.create_task(self._handle_rpc_request(ws, msg))
788
+ elif has_id and has_result_or_error:
789
+ self._handle_rpc_response(msg)
790
+ except Exception as e:
791
+ print(f"[web] Slot {slot} 消息处理异常: {e}")
792
+ except Exception as e:
793
+ print(f"[web] Slot {slot} recv loop exited: {e}")
794
+ finally:
795
+ self._extra_ws.pop(slot, None)
796
+ self._extra_ws_tasks.pop(slot, None)
797
+
798
+ async def _handle_connection_release(self, data):
799
+ """Kernel 请求释放 slot,优雅关闭。"""
800
+ for slot in data.get("slots", []):
801
+ ws = self._extra_ws.pop(slot, None)
802
+ task = self._extra_ws_tasks.pop(slot, None)
803
+ if ws:
804
+ try:
805
+ await ws.close(code=1000, reason="release")
806
+ except Exception:
807
+ pass
808
+ if task:
809
+ task.cancel()
810
+
632
811
  async def _handle_shutdown(self):
633
812
  """Handle module.shutdown: ack → exiting → cleanup → ready → close connections → exit."""
634
813
  print("[web] ========== SHUTDOWN STARTED ==========")
@@ -637,25 +816,21 @@ class WebServer:
637
816
 
638
817
  # Step 1: Send ack (立即确认收到)
639
818
  print("[web] Sending shutdown ack...")
640
- await self._publish_event({
641
- "event": "module.shutdown.ack",
642
- "data": {"module_id": "web"},
819
+ await self._publish_event(self._ws, "module.shutdown.ack", {
820
+ "module_id": "web",
643
821
  })
644
822
  print("[web] shutdown ack sent")
645
823
 
646
824
  # Step 2: Send module.exiting (开始清理)
647
825
  print("[web] Sending module.exiting...")
648
- await self._publish_event({
649
- "event": "module.exiting",
650
- "data": {
651
- "module_id": "web",
652
- "type": "passive",
653
- "reason": "shutdown_requested",
654
- "restart": "auto",
655
- "action": "none",
656
- "timeout": 3.0,
657
- "restart_delay": 0.0,
658
- },
826
+ await self._publish_event(self._ws, "module.exiting", {
827
+ "module_id": "web",
828
+ "type": "passive",
829
+ "reason": "shutdown_requested",
830
+ "restart": "auto",
831
+ "action": "none",
832
+ "timeout": 3.0,
833
+ "restart_delay": 0.0,
659
834
  })
660
835
  print("[web] module.exiting sent")
661
836
 
@@ -681,15 +856,36 @@ class WebServer:
681
856
 
682
857
  print("[web] All WebSocket connections closed")
683
858
 
684
- # Step 4: Send ready (after closing connections)
859
+ # Step 4: Send ready(必须在关闭连接之前发送)
685
860
  print("[web] Sending shutdown ready...")
686
- await self._publish_event({
687
- "event": "module.shutdown.ready",
688
- "data": {"module_id": "web"},
861
+ await self._publish_event(self._ws, "module.shutdown.ready", {
862
+ "module_id": "web",
689
863
  })
690
864
  print("[web] shutdown ready sent")
691
865
 
692
- # Step 5: Trigger uvicorn graceful shutdown
866
+ # 等待 Kernel 处理 shutdown.ready
867
+ await asyncio.sleep(0.01)
868
+
869
+ # Step 5: 关闭所有附加连接
870
+ for _s, _w in list(self._extra_ws.items()):
871
+ try:
872
+ await _w.close(code=1000, reason="shutdown")
873
+ except Exception:
874
+ pass
875
+ for _t in self._extra_ws_tasks.values():
876
+ _t.cancel()
877
+ self._extra_ws.clear()
878
+ self._extra_ws_tasks.clear()
879
+
880
+ # Step 5: Close Kernel WebSocket connection gracefully
881
+ if self._ws:
882
+ try:
883
+ await self._ws.close(code=1000, reason="Graceful shutdown")
884
+ print("[web] Kernel WebSocket closed")
885
+ except Exception as e:
886
+ print(f"[web] Failed to close Kernel WebSocket: {e}")
887
+
888
+ # Step 6: Trigger uvicorn graceful shutdown
693
889
  print("[web] Triggering uvicorn graceful shutdown...")
694
890
  if self._uvicorn_server:
695
891
  self._uvicorn_server.should_exit = True
@@ -697,37 +893,28 @@ class WebServer:
697
893
 
698
894
  print("[web] ========== SHUTDOWN COMPLETE ==========")
699
895
 
700
- # Give uvicorn a moment to start shutdown, then force exit
701
- # This prevents hanging on lingering connections
702
- await asyncio.sleep(0.5)
703
- import sys
704
- sys.exit(0)
896
+ # Note: Do NOT call sys.exit() in async context
897
+ # Let uvicorn naturally complete its shutdown
705
898
 
706
- async def _publish_event(self, event: dict):
707
- """Publish an event via RPC event.publish."""
708
- if not self._ws:
709
- print(f"[web] WARNING: Cannot publish event {event.get('event')}, WebSocket not connected")
710
- return
711
- try:
712
- await self._rpc_call(self._ws, "event.publish", {
713
- "event_id": str(uuid.uuid4()),
714
- "event": event.get("event", ""),
715
- "data": event.get("data", {}),
716
- })
717
- except Exception as e:
718
- print(f"[web] ERROR: Failed to publish event {event.get('event')}: {e}")
899
+ async def _publish_event(self, ws, event: str, data: dict = None):
900
+ """通过 RPC event.publish 发布事件(fire-and-forget)。"""
901
+ await self._rpc_call(ws, "event.publish", {
902
+ "event_id": str(uuid.uuid4()),
903
+ "event": event,
904
+ "data": data or {},
905
+ }, wait_response=False)
719
906
 
720
907
  # ── Test event loop ──
721
908
 
722
909
  async def _test_event_loop(self):
723
910
  """Publish a test event every 10 seconds."""
724
- while True:
725
- await asyncio.sleep(10)
726
- await self._publish_event({
727
- "event": "web.test",
728
- "data": {
729
- "message": "test event from web",
730
- "timestamp": datetime.now(timezone.utc).isoformat(),
731
- },
732
- })
733
- print("[web] test event published")
911
+ try:
912
+ while True:
913
+ await asyncio.sleep(10)
914
+ if self._ws:
915
+ await self._publish_event(self._ws, "web.test", {
916
+ "message": "test event from web",
917
+ "timestamp": datetime.now(timezone.utc).isoformat(),
918
+ })
919
+ except Exception:
920
+ pass