@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
@@ -15,6 +15,7 @@ from datetime import datetime, timezone
15
15
  import asyncio
16
16
  import traceback
17
17
  import uuid
18
+ import random
18
19
 
19
20
  import websockets
20
21
 
@@ -25,6 +26,7 @@ SYSTEM_BROADCAST_EVENTS = {
25
26
  "module.crashed", "module.exiting", "module.offline",
26
27
  "module.shutdown.ack", "module.shutdown.ready",
27
28
  "system.ready", "registry.updated",
29
+ "system.instance.started", "system.instance.stopped",
28
30
  }
29
31
 
30
32
 
@@ -129,6 +131,12 @@ def _load_module_config() -> dict:
129
131
  if "advertise_ip" in fm:
130
132
  result["advertise_ip"] = str(fm["advertise_ip"])
131
133
 
134
+ # max_connections(弹性连接上限)
135
+ try:
136
+ result["max_connections"] = max(1, min(10, int(fm.get("max_connections", 1))))
137
+ except (ValueError, TypeError):
138
+ result["max_connections"] = 1
139
+
132
140
  except SystemExit:
133
141
  raise # Re-raise exit to prevent catching by outer except
134
142
  except Exception as e:
@@ -381,6 +389,14 @@ _ws_global = None
381
389
  _shutting_down = False
382
390
  _exit_code = 0 # Exit code for main() to use
383
391
 
392
+ # 弹性多连接
393
+ _extra_ws: dict = {} # slot → WebSocket(附加连接)
394
+ _extra_ws_tasks: dict = {} # slot → recv loop Task
395
+ _kernel_port = "" # 缓存 kernel_port,供 offer handler 使用
396
+ _pending_rpc: dict[str, asyncio.Future] = {} # rpc_id → Future(等待响应)
397
+
398
+ _has_registered = False
399
+
384
400
 
385
401
  def _is_auth_failure(e: Exception) -> bool:
386
402
  """Check if a WebSocket exception indicates authentication failure."""
@@ -392,212 +408,251 @@ def _is_auth_failure(e: Exception) -> bool:
392
408
 
393
409
  async def main():
394
410
  global _ws_global, _shutting_down
395
- # Initialize log file paths
396
- global _log_dir, _log_latest_path, _crash_log_path
397
- module_data = os.environ.get("KITE_MODULE_DATA")
398
- if module_data:
399
- _log_dir = os.path.join(module_data, "log")
400
- os.makedirs(_log_dir, exist_ok=True)
401
- suffix = os.environ.get("KITE_INSTANCE_SUFFIX", "")
402
-
403
- _log_latest_path = os.path.join(_log_dir, f"latest{suffix}.log")
404
- try:
405
- with open(_log_latest_path, "w", encoding="utf-8") as f:
406
- pass
407
- except Exception:
408
- _log_latest_path = None
409
-
410
- _crash_log_path = os.path.join(_log_dir, f"crashes{suffix}.jsonl")
411
- try:
412
- with open(_crash_log_path, "w", encoding="utf-8") as f:
413
- pass
414
- except Exception:
415
- _crash_log_path = None
416
-
417
- _resolve_daily_log_path()
418
-
419
- _setup_exception_hooks()
420
-
421
- _t0 = time.monotonic()
422
-
423
- # Read boot_info from stdin (only token)
424
- token = ""
425
- try:
426
- line = sys.stdin.readline().strip()
427
- if line:
428
- boot_info = json.loads(line)
429
- token = boot_info.get("token", "")
430
- except Exception:
431
- pass
432
-
433
- # Read kernel_port: env first (fast path), stdin fallback (parallel start)
434
- kernel_port = int(os.environ.get("KITE_KERNEL_PORT", "0"))
435
- if not kernel_port:
436
- msg = _read_stdin_kite_message("kernel_port", timeout=10)
437
- if msg:
438
- kernel_port = int(msg.get("kernel_port", 0))
439
-
440
- if not token or not kernel_port:
441
- print("[backup] ERROR: Missing token or kernel_port")
442
- sys.exit(1)
443
-
444
- print(f"[backup] Token received ({len(token)} chars), kernel port: {kernel_port} ({_fmt_elapsed(_t0)})")
445
-
446
- # Start reconnect loop
447
- await _ws_loop(token, kernel_port, _t0)
411
+ if _startup_config.get("mode") == "remote":
412
+ await _remote_mode_loop(_startup_config["gateway_url"], _startup_config["kite_token"], _startup_config["t0"])
413
+ else:
414
+ await _ws_loop(_startup_config["token"], _startup_config["kernel_port"], _startup_config["t0"])
448
415
 
449
416
 
450
417
  async def _ws_loop(token: str, kernel_port: int, _t0: float):
451
418
  """Connect to Kernel with exponential backoff reconnection."""
452
419
  global _shutting_down, _exit_code
453
- retry_delay = 0.3
454
- max_delay = 5.0
455
- max_retries = 10
420
+ retry_delay = 0.5
421
+ max_delay = 10.0
456
422
  attempt = 0
423
+ cooldown_attempts = 0
424
+
457
425
  while not _shutting_down:
458
426
  try:
459
427
  await _ws_connect(token, kernel_port, _t0)
460
- retry_delay = 0.3
428
+ retry_delay = 0.5
461
429
  attempt = 0
430
+ cooldown_attempts = 0
462
431
  except asyncio.CancelledError:
463
432
  return
464
433
  except Exception as e:
465
- attempt += 1
466
- if _is_auth_failure(e):
467
- print(f"[backup] Kernel 认证失败,退出")
468
- _exit_code = 1
469
- _shutting_down = True
434
+ if _shutting_down:
470
435
  return
471
- if attempt >= max_retries:
472
- print(f"[backup] 重连失败 {max_retries} 次,退出")
436
+
437
+ code = _get_close_code(e)
438
+
439
+ # never: 永不重连
440
+ if code in (4001, 4003, 4004, 1008, 4010):
441
+ print(f"[backup] 致命错误 (code {code}),退出")
473
442
  _exit_code = 1
474
443
  _shutting_down = True
475
444
  return
445
+
446
+ # cooldown: 速率限制
447
+ if code == 4020:
448
+ cooldown_attempts += 1
449
+ if cooldown_attempts >= 5:
450
+ print(f"[backup] 速率限制重试 5 次,退出")
451
+ _exit_code = 1
452
+ _shutting_down = True
453
+ return
454
+ print(f"[backup] 速率限制,10.0s 后重试 ({cooldown_attempts}/5)")
455
+ await asyncio.sleep(10.0)
456
+ continue
457
+
458
+ # standard: 指数退避 + jitter
459
+ attempt += 1
460
+ jitter = retry_delay * 0.2 * random.random()
461
+ sleep_time = retry_delay + jitter
476
462
  _write_crash(type(e), e, e.__traceback__, severity="error", handled=True)
477
- print(f"[backup] 连接错误: {e}, {retry_delay:.1f}s 后重试 ({attempt}/{max_retries})")
463
+ print(f"[backup] 连接错误: {e}, {sleep_time:.1f}s 后重试 (attempt {attempt})")
464
+
478
465
  _ws_global_clear()
479
466
  if _shutting_down:
480
467
  return
481
- await asyncio.sleep(retry_delay)
468
+ await asyncio.sleep(sleep_time if 'sleep_time' in locals() else retry_delay)
482
469
  retry_delay = min(retry_delay * 2, max_delay)
483
470
 
484
471
 
472
+ def _get_close_code(e: Exception) -> int:
473
+ """从 websockets 异常中提取关闭码"""
474
+ if hasattr(e, 'rcvd') and e.rcvd is not None:
475
+ return getattr(e.rcvd, 'code', 0)
476
+ return 0
477
+
478
+
485
479
  def _ws_global_clear():
486
480
  global _ws_global
487
481
  _ws_global = None
488
482
 
489
483
 
484
+ async def _do_init(ws):
485
+ """收到 system.require_init 后执行:subscribe + register + module.ready"""
486
+ global _has_registered
487
+ reason = "startup" if not _has_registered else "recovery"
488
+ print(f"[backup] Received system.require_init (reason={reason})")
489
+
490
+ # 1. Subscribe to events
491
+ await _rpc_call(ws, "event.subscribe", {
492
+ "events": [
493
+ "module.started",
494
+ "module.stopped",
495
+ "module.shutdown",
496
+ ],
497
+ })
498
+ print(f"[backup] Subscribed to events")
499
+
500
+ # 2. Register to Kernel Registry via RPC
501
+ await _rpc_call(ws, "registry.register", {
502
+ "module_id": "backup",
503
+ "module_type": "service",
504
+ "launcher_id": "launcher",
505
+ "tools": {
506
+ "rpc": {
507
+ "module": {
508
+ "health": {"method": "health", "description": "健康检查"},
509
+ "status": {"method": "status", "description": "状态查询"},
510
+ "config": {
511
+ "get": {"method": "get_settings", "description": "获取配置"},
512
+ "update": {"method": "update_settings", "description": "更新配置"},
513
+ "reset": {"method": "reset_settings", "description": "恢复默认配置"},
514
+ }
515
+ }
516
+ }
517
+ },
518
+ "events_publish": {
519
+ "backup": {
520
+ "test": {"description": "Test event from backup module"},
521
+ }
522
+ },
523
+ "events_subscribe": [
524
+ "module.started",
525
+ "module.stopped",
526
+ "module.shutdown",
527
+ ],
528
+ })
529
+ print(f"[backup] Registered to Kernel")
530
+
531
+ # 3. Publish module.ready
532
+ if not _shutting_down:
533
+ startup_time = time.monotonic() - _start_ts
534
+ await _publish_event(ws, "module.ready", {
535
+ "module_id": "backup",
536
+ "graceful_shutdown": True,
537
+ "startup_time": startup_time,
538
+ "reason": reason,
539
+ })
540
+ print(f"[backup] module.ready published (reason={reason})")
541
+
542
+ _has_registered = True
543
+
544
+ # Start test event loop in background
545
+ asyncio.create_task(_test_event_loop(ws))
546
+
547
+
490
548
  async def _ws_connect(token: str, kernel_port: int, _t0: float):
491
- """Single WebSocket session: connect → subscriberegisterready receive loop."""
492
- global _ws_global
549
+ """Single WebSocket session: connect → authstart receiver wait for system.require_init."""
550
+ global _ws_global, _kernel_port
551
+ _kernel_port = kernel_port
493
552
 
494
- ws_url = f"ws://127.0.0.1:{kernel_port}/ws?token={token}&id=backup"
553
+ ws_url = f"ws://127.0.0.1:{kernel_port}/ws?id=backup"
495
554
  print(f"[backup] Connecting to Kernel: {ws_url}")
496
555
 
497
556
  async with websockets.connect(ws_url, open_timeout=5, ping_interval=None, close_timeout=10) as ws:
557
+ # Send auth message first
558
+ auth_req = {
559
+ "jsonrpc": "2.0",
560
+ "id": "auth",
561
+ "method": "auth",
562
+ "params": {"token": token}
563
+ }
564
+ await ws.send(json.dumps(auth_req))
565
+
566
+ # Wait for auth response
567
+ auth_resp_raw = await asyncio.wait_for(ws.recv(), timeout=5)
568
+ auth_resp = json.loads(auth_resp_raw)
569
+ if "error" in auth_resp:
570
+ raise Exception(f"Auth failed: {auth_resp['error']}")
571
+
498
572
  _ws_global = ws
499
573
  print(f"[backup] Connected to Kernel ({_fmt_elapsed(_t0)})")
500
574
 
501
- # Subscribe to events
502
- await _rpc_call(ws, "event.subscribe", {
503
- "events": [
504
- "module.started",
505
- "module.stopped",
506
- "module.shutdown",
507
- ],
508
- })
509
- print(f"[backup] Subscribed to events ({_fmt_elapsed(_t0)})")
575
+ # Start receiver task — wait for system.require_init to trigger _do_init
576
+ receiver_task = asyncio.create_task(_ws_receiver(ws))
577
+ try:
578
+ # Wait for receiver to finish (connection closed or error)
579
+ await receiver_task
580
+ finally:
581
+ receiver_task.cancel()
582
+ for fut in _pending_rpc.values():
583
+ if not fut.done():
584
+ fut.set_result({"error": {"code": -32001, "message": "Connection lost"}})
585
+ _pending_rpc.clear()
586
+
587
+
588
+ async def _ws_receiver(ws):
589
+ """Main connection receive loop: route events, RPC requests, and RPC responses.
590
+ Detects system.require_init to trigger _do_init."""
591
+ async for raw in ws:
592
+ try:
593
+ msg = json.loads(raw)
594
+ except (json.JSONDecodeError, TypeError):
595
+ continue
510
596
 
511
- # Register to Kernel Registry via RPC
512
- await _rpc_call(ws, "registry.register", {
513
- "module_id": "backup",
514
- "module_type": "service",
515
- "launcher_id": "launcher", # 声明归属的 Launcher
516
- "tools": {
517
- "rpc": {
518
- "module": {
519
- "health": {"method": "health", "description": "健康检查"},
520
- "status": {"method": "status", "description": "状态查询"},
521
- "config": {
522
- "get": {"method": "get_settings", "description": "获取配置"},
523
- "update": {"method": "update_settings", "description": "更新配置"},
524
- "reset": {"method": "reset_settings", "description": "恢复默认配置"},
525
- }
526
- }
527
- }
528
- },
529
- "events_publish": {
530
- "backup": {
531
- "test": {"description": "Test event from backup module"},
532
- }
533
- },
534
- "events_subscribe": [
535
- "module.started",
536
- "module.stopped",
537
- "module.shutdown",
538
- ],
539
- })
540
- print(f"[backup] Registered to Kernel ({_fmt_elapsed(_t0)})")
541
-
542
- # Publish module.ready (every reconnect)
543
- if not _shutting_down:
544
- startup_time = time.monotonic() - _t0
545
- await _rpc_call(ws, "event.publish", {
546
- "event_id": str(uuid.uuid4()),
547
- "event": "module.ready",
548
- "data": {
549
- "module_id": "backup",
550
- "graceful_shutdown": True,
551
- "startup_time": startup_time,
552
- },
553
- })
554
- print(f"[backup] module.ready published ({_fmt_elapsed(_t0)})")
597
+ try:
598
+ has_method = "method" in msg
599
+ has_id = "id" in msg
600
+
601
+ if has_method and not has_id:
602
+ # 检测 system.require_init 事件
603
+ params = msg.get("params", {})
604
+ event_type = params.get("event", "")
605
+ if event_type == "system.require_init":
606
+ asyncio.create_task(_do_init(ws))
607
+ continue
608
+ # Event Notification run in background to prevent deadlock
609
+ asyncio.create_task(_handle_event_notification(msg))
610
+ elif has_method and has_id:
611
+ # Incoming RPC request — run in background to prevent deadlock
612
+ asyncio.create_task(_handle_rpc_request(ws, msg))
613
+ elif not has_method and has_id:
614
+ _handle_rpc_response(msg)
615
+ except Exception as e:
616
+ print(f"[backup] 消息处理异常(已忽略): {e}")
555
617
 
556
- # Start test event loop in background
557
- test_task = asyncio.create_task(_test_event_loop(ws))
558
618
 
559
- # Message loop: handle incoming RPC + events
560
- # CRITICAL: RPC 死锁防范
561
- # - 入站 RPC 请求必须用 create_task() 异步执行,不可 await
562
- # - 原因:如果 handler 内部调用 rpc_call() 发出站请求,出站响应需要本接收循环来分发
563
- # - 如果接收循环被 await handler 阻塞,出站响应永远收不到 超时死锁
564
- # - 事件通知和 RPC 响应可以同步处理(它们不会反向调用 rpc_call)
565
- async for raw in ws:
566
- try:
567
- msg = json.loads(raw)
568
- except (json.JSONDecodeError, TypeError):
569
- continue
619
+ async def _rpc_call(ws, method: str, params: dict = None,
620
+ wait_response: bool = True, timeout: float = 3.0) -> dict:
621
+ """JSON-RPC 2.0 request。默认等待响应。"""
622
+ rpc_id = str(uuid.uuid4())
623
+ msg = {"jsonrpc": "2.0", "id": rpc_id, "method": method}
624
+ if params:
625
+ msg["params"] = params
570
626
 
571
- try:
572
- has_method = "method" in msg
573
- has_id = "id" in msg
627
+ if not wait_response:
628
+ await ws.send(json.dumps(msg))
629
+ return {}
574
630
 
575
- if has_method and not has_id:
576
- # Event Notification
577
- await _handle_event_notification(msg)
578
- elif has_method and has_id:
579
- # Incoming RPC request — run in background to prevent deadlock
580
- asyncio.create_task(_handle_rpc_request(ws, msg))
581
- # Ignore RPC responses (we don't await them in this simple impl)
582
- except Exception as e:
583
- print(f"[backup] 消息处理异常(已忽略): {e}")
631
+ future = asyncio.get_event_loop().create_future()
632
+ _pending_rpc[rpc_id] = future
633
+ await ws.send(json.dumps(msg))
634
+ try:
635
+ return await asyncio.wait_for(future, timeout=timeout)
636
+ except asyncio.TimeoutError:
637
+ _pending_rpc.pop(rpc_id, None)
638
+ return {"error": {"code": -32000, "message": f"RPC timeout: {method} ({timeout}s)"}}
584
639
 
585
640
 
586
- async def _rpc_call(ws, method: str, params: dict = None):
587
- """Send a JSON-RPC 2.0 request (fire-and-forget, no response awaited)."""
588
- msg = {"jsonrpc": "2.0", "id": str(uuid.uuid4()), "method": method}
589
- if params:
590
- msg["params"] = params
591
- await ws.send(json.dumps(msg))
641
+ def _handle_rpc_response(msg: dict):
642
+ """Route JSON-RPC response to pending future."""
643
+ rpc_id = msg.get("id")
644
+ future = _pending_rpc.pop(rpc_id, None)
645
+ if future and not future.done():
646
+ future.set_result(msg)
592
647
 
593
648
 
594
- async def _publish_event(ws, event: dict):
595
- """Publish an event via RPC event.publish."""
649
+ async def _publish_event(ws, event: str, data: dict = None):
650
+ """Publish event via event.publish RPC (fire-and-forget)."""
596
651
  await _rpc_call(ws, "event.publish", {
597
652
  "event_id": str(uuid.uuid4()),
598
- "event": event.get("event", ""),
599
- "data": event.get("data", {}),
600
- })
653
+ "event": event,
654
+ "data": data or {},
655
+ }, wait_response=False)
601
656
 
602
657
 
603
658
  async def _handle_ping_event(data: dict):
@@ -605,13 +660,10 @@ async def _handle_ping_event(data: dict):
605
660
  t1 = data.get("ping_time")
606
661
  t2 = time.time()
607
662
 
608
- await _publish_event(_ws_global, {
609
- "event": "system.pong",
610
- "data": {
611
- "module_id": MODULE_NAME,
612
- "ping_time": t1,
613
- "pong_time": t2,
614
- },
663
+ await _publish_event(_ws_global, "system.pong", {
664
+ "module_id": MODULE_NAME,
665
+ "ping_time": t1,
666
+ "pong_time": t2,
615
667
  })
616
668
 
617
669
 
@@ -626,6 +678,14 @@ async def _handle_event_notification(msg: dict):
626
678
  await _handle_ping_event(data)
627
679
  return
628
680
 
681
+ # 弹性连接 offer/release
682
+ if event_type == "system.connection.offer":
683
+ asyncio.create_task(_handle_connection_offer(data))
684
+ return
685
+ if event_type == "system.connection.release":
686
+ asyncio.create_task(_handle_connection_release(data))
687
+ return
688
+
629
689
  # Special handling for module.shutdown
630
690
  if event_type == "module.shutdown":
631
691
  target = data.get("module_id", "")
@@ -741,7 +801,7 @@ async def _rpc_get_settings(params: dict) -> dict:
741
801
  "events": frontmatter.get("events"),
742
802
  "subscriptions": frontmatter.get("subscriptions"),
743
803
  "depends_on": frontmatter.get("depends_on"),
744
- "has_config": False, # backup 模块暂无 config.yaml
804
+ "has_config": False, # backup 模块暂无业务配置
745
805
  "config": None,
746
806
  }
747
807
 
@@ -758,9 +818,9 @@ async def _rpc_update_settings(params: dict) -> dict:
758
818
  frontmatter[key] = value
759
819
  _write_module_md(frontmatter, body)
760
820
 
761
- # 更新 config.yaml(如果需要)
821
+ # 更新业务配置(如果需要)
762
822
  if config:
763
- # backup 模块暂无 config.yaml,此处预留接口
823
+ # backup 模块暂无业务配置,此处预留接口
764
824
  pass
765
825
 
766
826
  # 返回更新后的完整设置
@@ -799,53 +859,290 @@ async def _rpc_reset_settings(params: dict) -> dict:
799
859
 
800
860
 
801
861
 
862
+ async def _handle_connection_offer(data):
863
+ """处理 Kernel 下发的 slot token,建立附加连接。"""
864
+ slots = data.get("slots", {})
865
+ for slot_str, info in slots.items():
866
+ slot = int(slot_str)
867
+ token = info.get("token", "")
868
+ if not token or slot in _extra_ws:
869
+ continue
870
+ asyncio.create_task(_connect_slot(slot, token))
871
+
872
+
873
+ async def _connect_slot(slot, token):
874
+ """建立单个 slot 附加连接。"""
875
+ ws_url = f"ws://127.0.0.1:{_kernel_port}/ws"
876
+ try:
877
+ ws = await websockets.connect(ws_url, open_timeout=5, ping_interval=None, close_timeout=5)
878
+ auth_req = {"jsonrpc": "2.0", "id": f"auth-slot-{slot}", "method": "auth", "params": {"token": token}}
879
+ await ws.send(json.dumps(auth_req))
880
+ resp = json.loads(await asyncio.wait_for(ws.recv(), timeout=5))
881
+ if "error" in resp:
882
+ await ws.close()
883
+ return
884
+ _extra_ws[slot] = ws
885
+ _extra_ws_tasks[slot] = asyncio.create_task(_slot_recv_loop(slot, ws))
886
+ print(f"[backup] Slot {slot} connected")
887
+ except Exception as e:
888
+ print(f"[backup] Slot {slot} connect failed: {e}")
889
+
890
+
891
+ async def _slot_recv_loop(slot, ws):
892
+ """附加连接的接收循环:与主连接平等处理所有消息。"""
893
+ try:
894
+ async for raw in ws:
895
+ try:
896
+ msg = json.loads(raw)
897
+ except (json.JSONDecodeError, TypeError):
898
+ continue
899
+ try:
900
+ has_method = "method" in msg
901
+ has_id = "id" in msg
902
+
903
+ if has_method and not has_id:
904
+ asyncio.create_task(_handle_event_notification(msg))
905
+ elif has_method and has_id:
906
+ asyncio.create_task(_handle_rpc_request(ws, msg))
907
+ elif not has_method and has_id:
908
+ _handle_rpc_response(msg)
909
+ except Exception as e:
910
+ print(f"[backup] Slot {slot} 消息处理异常(已忽略): {e}")
911
+ except Exception as e:
912
+ print(f"[backup] Slot {slot} 接收循环异常: {e}")
913
+ finally:
914
+ _extra_ws.pop(slot, None)
915
+ _extra_ws_tasks.pop(slot, None)
916
+
917
+
918
+ async def _handle_connection_release(data):
919
+ """Kernel 请求释放 slot,优雅关闭。"""
920
+ for slot in data.get("slots", []):
921
+ ws = _extra_ws.pop(slot, None)
922
+ task = _extra_ws_tasks.pop(slot, None)
923
+ if ws:
924
+ try:
925
+ await ws.close(code=1000, reason="release")
926
+ except Exception:
927
+ pass
928
+ if task:
929
+ task.cancel()
930
+
931
+
802
932
  async def _handle_shutdown():
803
933
  """Handle module.shutdown event — ack → exiting → cleanup → ready → exit."""
804
934
  global _shutting_down
805
935
  print("[backup] Received shutdown request")
806
936
  _shutting_down = True
807
937
  # Step 1: Send ack (立即确认收到)
808
- await _publish_event(_ws_global, {
809
- "event": "module.shutdown.ack",
810
- "data": {"module_id": "backup"},
811
- })
938
+ await _publish_event(_ws_global, "module.shutdown.ack", {"module_id": "backup"})
812
939
  # Step 2: Send module.exiting (开始清理)
813
- await _publish_event(_ws_global, {
814
- "event": "module.exiting",
815
- "data": {
816
- "module_id": "backup",
817
- "type": "passive",
818
- "reason": "shutdown_requested",
819
- "restart": "auto",
820
- "action": "none",
821
- "timeout": 2.0,
822
- "restart_delay": 0.0,
823
- },
940
+ await _publish_event(_ws_global, "module.exiting", {
941
+ "module_id": "backup",
942
+ "type": "passive",
943
+ "reason": "shutdown_requested",
944
+ "restart": "auto",
945
+ "action": "none",
946
+ "timeout": 2.0,
947
+ "restart_delay": 0.0,
824
948
  })
825
949
  # Step 3: Cleanup (nothing to clean up for backup)
950
+ # 关闭所有附加连接
951
+ for _s, _w in list(_extra_ws.items()):
952
+ try:
953
+ await _w.close(code=1000, reason="shutdown")
954
+ except Exception:
955
+ pass
956
+ for _t in _extra_ws_tasks.values():
957
+ _t.cancel()
958
+ _extra_ws.clear()
959
+ _extra_ws_tasks.clear()
826
960
  # Step 4: Send ready (清理完成)
827
- await _publish_event(_ws_global, {
828
- "event": "module.shutdown.ready",
829
- "data": {"module_id": "backup"},
830
- })
961
+ await _publish_event(_ws_global, "module.shutdown.ready", {"module_id": "backup"})
831
962
  print("[backup] Shutdown ready, exiting")
832
- # Step 5: Exit
833
- sys.exit(_exit_code)
963
+
964
+ # 等待 Kernel 处理 shutdown.ready(防止 Close 帧抢先)
965
+ await asyncio.sleep(0.1)
966
+
967
+ # Step 5: Close WebSocket connection gracefully
968
+ if _ws_global:
969
+ try:
970
+ await _ws_global.close(code=1000, reason="Graceful shutdown")
971
+ print("[backup] WebSocket closed")
972
+ except Exception as e:
973
+ print(f"[backup] Failed to close WebSocket: {e}")
974
+
975
+ # Note: Do NOT call sys.exit() in async context
976
+ # Let the event loop naturally complete
834
977
 
835
978
 
836
979
  async def _test_event_loop(ws):
837
980
  """Publish a test event every 10 seconds."""
838
- while True:
839
- await asyncio.sleep(10)
840
- await _publish_event(ws, {
841
- "event": "backup.test",
842
- "data": {
981
+ try:
982
+ while True:
983
+ await asyncio.sleep(10)
984
+ await _publish_event(ws, "backup.test", {
843
985
  "message": "test event from backup",
844
986
  "timestamp": datetime.now(timezone.utc).isoformat(),
845
- },
846
- })
847
- print("[backup] test event published")
987
+ })
988
+ except Exception:
989
+ pass
990
+
991
+
992
+ _startup_config = {} # populated by _validate_and_prepare()
993
+
994
+
995
+ def _validate_and_prepare() -> dict:
996
+ """同步启动验证:日志初始化、读取 token 和 kernel_port。
997
+ 失败直接 sys.exit(1),成功返回启动参数。在 asyncio.run() 之前调用。"""
998
+ t0 = time.monotonic()
999
+ kernel_port = os.environ.get("KITE_KERNEL_PORT")
1000
+ if kernel_port:
1001
+ return _prepare_local_mode(int(kernel_port), t0)
1002
+ config = _load_module_config()
1003
+ gateway_url = config.get("gateway_url") or os.environ.get("KITE_GATEWAY_URL")
1004
+ if gateway_url:
1005
+ return _prepare_remote_mode(gateway_url, t0)
1006
+ print(f"[{MODULE_NAME}] ERROR: No KITE_KERNEL_PORT and no gateway_url")
1007
+ sys.exit(1)
1008
+
1009
+ def _prepare_local_mode(kernel_port: int, t0: float) -> dict:
1010
+ global _log_dir, _log_latest_path, _crash_log_path
1011
+ module_data = os.environ.get("KITE_MODULE_DATA")
1012
+ if module_data:
1013
+ _log_dir = os.path.join(module_data, "log")
1014
+ os.makedirs(_log_dir, exist_ok=True)
1015
+ suffix = os.environ.get("KITE_INSTANCE_SUFFIX", "")
1016
+ _log_latest_path = os.path.join(_log_dir, f"latest{suffix}.log")
1017
+ try:
1018
+ with open(_log_latest_path, "w", encoding="utf-8") as f: pass
1019
+ except Exception: _log_latest_path = None
1020
+ _crash_log_path = os.path.join(_log_dir, f"crashes{suffix}.jsonl")
1021
+ try:
1022
+ with open(_crash_log_path, "w", encoding="utf-8") as f: pass
1023
+ except Exception: _crash_log_path = None
1024
+ _resolve_daily_log_path()
1025
+ _setup_exception_hooks()
1026
+ line = sys.stdin.readline().strip()
1027
+ if not line:
1028
+ print(f"[{MODULE_NAME}] ERROR: stdin closed")
1029
+ sys.exit(1)
1030
+ try: msg = json.loads(line)
1031
+ except json.JSONDecodeError as e:
1032
+ print(f"[{MODULE_NAME}] ERROR: Invalid JSON: {e}")
1033
+ sys.exit(1)
1034
+ if "error" in msg:
1035
+ print(f"[{MODULE_NAME}] 启动失败: {msg.get('message')}")
1036
+ sys.exit(1)
1037
+ token = msg.get("token", "")
1038
+ if not token:
1039
+ print(f"[{MODULE_NAME}] ERROR: No token")
1040
+ sys.exit(1)
1041
+ print(f"[{MODULE_NAME}] Local mode: port={kernel_port}")
1042
+ return {"mode": "local", "token": token, "kernel_port": kernel_port, "t0": t0}
1043
+
1044
+ def _prepare_remote_mode(gateway_url: str, t0: float) -> dict:
1045
+ global _log_dir, _log_latest_path, _crash_log_path
1046
+ home = os.environ.get("HOME") or os.environ.get("USERPROFILE") or os.path.expanduser("~")
1047
+ data_dir = os.path.join(home, ".kite", "remote", MODULE_NAME)
1048
+ os.makedirs(data_dir, exist_ok=True)
1049
+ _log_dir = os.path.join(data_dir, "log")
1050
+ os.makedirs(_log_dir, exist_ok=True)
1051
+ _log_latest_path = os.path.join(_log_dir, "latest.log")
1052
+ try:
1053
+ with open(_log_latest_path, "w", encoding="utf-8") as f: pass
1054
+ except Exception: _log_latest_path = None
1055
+ _crash_log_path = os.path.join(_log_dir, "crashes.jsonl")
1056
+ try:
1057
+ with open(_crash_log_path, "w", encoding="utf-8") as f: pass
1058
+ except Exception: _crash_log_path = None
1059
+ _resolve_daily_log_path()
1060
+ _setup_exception_hooks()
1061
+ kite_token = _get_kite_token(MODULE_NAME, gateway_url)
1062
+ print(f"[{MODULE_NAME}] Remote mode: gateway={gateway_url}")
1063
+ return {"mode": "remote", "gateway_url": gateway_url, "kite_token": kite_token, "t0": t0}
1064
+
1065
+ def _gateway_to_filename(gateway_url: str) -> str:
1066
+ try:
1067
+ from urllib.parse import urlparse
1068
+ parsed = urlparse(gateway_url)
1069
+ host = parsed.hostname or "unknown"
1070
+ port = parsed.port or (443 if parsed.scheme == "wss" else 80)
1071
+ return f"{host}-{port}.json".replace(":", "-").replace("/", "-")
1072
+ except Exception: return "default.json"
1073
+
1074
+ def _load_token_cache(module_name: str, gateway_url: str) -> dict | None:
1075
+ home = os.environ.get("HOME") or os.environ.get("USERPROFILE") or os.path.expanduser("~")
1076
+ token_file = os.path.join(home, ".kite", "remote", module_name, "tokens", _gateway_to_filename(gateway_url))
1077
+ if not os.path.exists(token_file): return None
1078
+ try:
1079
+ with open(token_file, "r") as f: return json.load(f)
1080
+ except Exception: return None
1081
+
1082
+ def _clear_token_cache(module_name: str, gateway_url: str):
1083
+ home = os.environ.get("HOME") or os.environ.get("USERPROFILE") or os.path.expanduser("~")
1084
+ token_file = os.path.join(home, ".kite", "remote", module_name, "tokens", _gateway_to_filename(gateway_url))
1085
+ if os.path.exists(token_file):
1086
+ try: os.remove(token_file)
1087
+ except Exception: pass
1088
+
1089
+ def _get_kite_token(module_name: str, gateway_url: str) -> str:
1090
+ token = os.environ.get("KITE_TOKEN")
1091
+ if token: return token
1092
+ cache = _load_token_cache(module_name, gateway_url)
1093
+ if cache: return cache["token"]
1094
+ print(f"[{module_name}] No token for {gateway_url}")
1095
+ print(f" export KITE_TOKEN=<token>")
1096
+ sys.exit(1)
1097
+
1098
+
1099
+ async def _remote_mode_loop(gateway_url: str, kite_token: str, _t0: float):
1100
+ global _shutting_down, _exit_code
1101
+ retry_count = 0
1102
+ while not _shutting_down and retry_count < 10:
1103
+ try:
1104
+ await _remote_connect(gateway_url, kite_token, _t0)
1105
+ retry_count = 0
1106
+ except asyncio.CancelledError: break
1107
+ except Exception as e:
1108
+ if _shutting_down: break
1109
+ retry_count += 1
1110
+ await asyncio.sleep(min(2 ** retry_count, 60))
1111
+ if retry_count >= 10: _exit_code = 1
1112
+
1113
+ async def _remote_connect(gateway_url: str, kite_token: str, _t0: float):
1114
+ global _ws_global
1115
+ async with websockets.connect(gateway_url, open_timeout=10, ping_interval=30) as ws:
1116
+ challenge = json.loads(await ws.recv())
1117
+ auth_req = {"jsonrpc": "2.0", "id": "auth", "method": "auth.connect",
1118
+ "params": {"nonce": challenge["params"]["nonce"], "module_id": MODULE_NAME,
1119
+ "auth": {"method": "kite_token", "token": kite_token},
1120
+ "client": {"type": "module", "platform": sys.platform}}}
1121
+ await ws.send(json.dumps(auth_req))
1122
+ hello_resp = json.loads(await ws.recv())
1123
+ if "error" in hello_resp:
1124
+ error = hello_resp["error"]
1125
+ if error.get("code") in (4001, 4010, 4011):
1126
+ _clear_token_cache(MODULE_NAME, gateway_url)
1127
+ print(f"[{MODULE_NAME}] Token invalid, re-authenticate")
1128
+ sys.exit(1)
1129
+ raise Exception(f"Connection failed: {error}")
1130
+ print(f"[{MODULE_NAME}] Connected via Gateway")
1131
+ _ws_global = ws
1132
+
1133
+ # Start receiver task — wait for system.require_init to trigger _do_init
1134
+ receiver_task = asyncio.create_task(_ws_receiver(ws))
1135
+ try:
1136
+ await receiver_task
1137
+ finally:
1138
+ receiver_task.cancel()
1139
+ for fut in _pending_rpc.values():
1140
+ if not fut.done():
1141
+ fut.set_result({"error": {"code": -32001, "message": "Connection lost"}})
1142
+ _pending_rpc.clear()
848
1143
 
849
1144
 
850
1145
  if __name__ == "__main__":
1146
+ _startup_config = _validate_and_prepare()
851
1147
  asyncio.run(main())
1148
+ sys.exit(_exit_code)