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