@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
@@ -0,0 +1,964 @@
1
+ """
2
+ Gateway 模块入口 - 远程接入网关
3
+
4
+ 从 stdin 读 boot_info → 连接 Kernel → auth → registry.register → 启动 WS 服务器 → module.ready → 消息循环
5
+ """
6
+
7
+ import builtins
8
+ import json
9
+ import os
10
+ import sys
11
+ import threading
12
+ import re
13
+ import time
14
+ from datetime import datetime, timezone
15
+
16
+ import asyncio
17
+ import traceback
18
+ import uuid
19
+ import random
20
+
21
+ import websockets
22
+
23
+
24
+ # System broadcast events
25
+ SYSTEM_BROADCAST_EVENTS = {
26
+ "module.ready", "module.registered", "module.started", "module.stopped",
27
+ "module.crashed", "module.exiting", "module.offline",
28
+ "module.shutdown.ack", "module.shutdown.ready",
29
+ "system.ready", "registry.updated",
30
+ "system.instance.started", "system.instance.stopped",
31
+ }
32
+
33
+
34
+ # ── Module configuration ──
35
+
36
+ def _load_module_config() -> dict:
37
+ _this_dir = os.path.dirname(os.path.abspath(__file__))
38
+ module_md = os.path.join(_this_dir, "module.md")
39
+ project_root = os.environ.get("KITE_PROJECT", "")
40
+ if project_root and _this_dir.startswith(project_root):
41
+ rel_path = os.path.relpath(_this_dir, project_root)
42
+ else:
43
+ rel_path = _this_dir
44
+ result = {"name": "", "preferred_port": 0, "advertise_ip": "0.0.0.0"}
45
+ if not os.path.exists(module_md):
46
+ print(f"[{rel_path}] ERROR: module.md not found")
47
+ sys.exit(1)
48
+ try:
49
+ with open(module_md, encoding="utf-8") as f:
50
+ text = f.read()
51
+ m = re.match(r'^---\s*\n(.*?)\n---', text, re.DOTALL)
52
+ if not m:
53
+ print(f"[{rel_path}] ERROR: Missing YAML frontmatter")
54
+ sys.exit(1)
55
+ try:
56
+ import yaml
57
+ fm = yaml.safe_load(m.group(1)) or {}
58
+ except ImportError:
59
+ print(f"[{rel_path}] ERROR: PyYAML not installed")
60
+ sys.exit(1)
61
+ if "name" not in fm:
62
+ print(f"[{rel_path}] ERROR: Missing 'name' field")
63
+ sys.exit(1)
64
+ raw_name = str(fm["name"]).strip()
65
+ sanitized = re.sub(r'[^a-zA-Z0-9_\-]', '', raw_name)
66
+ if sanitized != raw_name or not sanitized:
67
+ print(f"[{rel_path}] ERROR: Invalid module name '{raw_name}'")
68
+ sys.exit(1)
69
+ result["name"] = sanitized
70
+ if "preferred_port" in fm:
71
+ try:
72
+ result["preferred_port"] = int(fm["preferred_port"])
73
+ except (ValueError, TypeError):
74
+ pass
75
+ if "advertise_ip" in fm:
76
+ result["advertise_ip"] = str(fm["advertise_ip"])
77
+ # max_connections(弹性连接上限)
78
+ try:
79
+ result["max_connections"] = max(1, min(10, int(fm.get("max_connections", 1))))
80
+ except (ValueError, TypeError):
81
+ result["max_connections"] = 1
82
+ except SystemExit:
83
+ raise
84
+ except Exception as e:
85
+ print(f"[{rel_path}] ERROR: Failed to read module.md: {e}")
86
+ sys.exit(1)
87
+ return result
88
+
89
+ _module_config = _load_module_config()
90
+ MODULE_NAME = _module_config["name"]
91
+ PREFERRED_PORT = _module_config["preferred_port"]
92
+ ADVERTISE_IP = _module_config["advertise_ip"]
93
+
94
+
95
+ # ── Safe stdout/stderr ──
96
+
97
+ class _SafeWriter:
98
+ def __init__(self, stream):
99
+ self._stream = stream
100
+ def write(self, s):
101
+ try:
102
+ self._stream.write(s)
103
+ except (BrokenPipeError, OSError):
104
+ pass
105
+ def flush(self):
106
+ try:
107
+ self._stream.flush()
108
+ except (BrokenPipeError, OSError):
109
+ pass
110
+ def __getattr__(self, name):
111
+ return getattr(self._stream, name)
112
+
113
+ sys.stdout = _SafeWriter(sys.stdout)
114
+ sys.stderr = _SafeWriter(sys.stderr)
115
+
116
+
117
+ # ── Timestamped print + log file writer ──
118
+
119
+ _builtin_print = builtins.print
120
+ _start_ts = time.monotonic()
121
+ _last_ts = time.monotonic()
122
+ _ANSI_RE = re.compile(r"\033\[[0-9;]*m")
123
+ _log_lock = threading.Lock()
124
+ _log_latest_path = None
125
+ _log_daily_path = None
126
+ _log_daily_date = ""
127
+ _log_dir = None
128
+ _crash_log_path = None
129
+
130
+ def _strip_ansi(s: str) -> str:
131
+ return _ANSI_RE.sub("", s)
132
+
133
+ def _resolve_daily_log_path():
134
+ global _log_daily_path, _log_daily_date
135
+ if not _log_dir:
136
+ return
137
+ today = datetime.now().strftime("%Y-%m-%d")
138
+ if today == _log_daily_date and _log_daily_path:
139
+ return
140
+ month_dir = os.path.join(_log_dir, today[:7])
141
+ os.makedirs(month_dir, exist_ok=True)
142
+ _log_daily_path = os.path.join(month_dir, f"{today}.log")
143
+ _log_daily_date = today
144
+
145
+ def _write_log(plain_line: str):
146
+ with _log_lock:
147
+ if _log_latest_path:
148
+ try:
149
+ with open(_log_latest_path, "a", encoding="utf-8") as f:
150
+ f.write(plain_line)
151
+ except Exception:
152
+ pass
153
+ _resolve_daily_log_path()
154
+ if _log_daily_path:
155
+ try:
156
+ with open(_log_daily_path, "a", encoding="utf-8") as f:
157
+ f.write(plain_line)
158
+ except Exception:
159
+ pass
160
+
161
+ def _write_crash(exc_type, exc_value, exc_tb, thread_name=None, severity="critical", handled=False):
162
+ record = {
163
+ "timestamp": datetime.now(timezone.utc).isoformat(),
164
+ "module": MODULE_NAME,
165
+ "thread": thread_name or threading.current_thread().name,
166
+ "exception_type": exc_type.__name__ if exc_type else "Unknown",
167
+ "exception_message": str(exc_value),
168
+ "traceback": "".join(traceback.format_exception(exc_type, exc_value, exc_tb)),
169
+ "severity": severity, "handled": handled,
170
+ "process_id": os.getpid(), "platform": sys.platform,
171
+ "runtime_version": f"Python {sys.version.split()[0]}",
172
+ }
173
+ if exc_tb:
174
+ tb_entries = traceback.extract_tb(exc_tb)
175
+ if tb_entries:
176
+ last = tb_entries[-1]
177
+ record["context"] = {"function": last.name, "file": os.path.basename(last.filename), "line": last.lineno}
178
+ line = json.dumps(record, ensure_ascii=False) + "\n"
179
+ if _crash_log_path:
180
+ try:
181
+ with open(_crash_log_path, "a", encoding="utf-8") as f:
182
+ f.write(line)
183
+ except Exception:
184
+ pass
185
+ if _log_dir:
186
+ try:
187
+ today = datetime.now().strftime("%Y-%m-%d")
188
+ archive_dir = os.path.join(_log_dir, "crashes", today[:7])
189
+ os.makedirs(archive_dir, exist_ok=True)
190
+ with open(os.path.join(archive_dir, f"{today}.jsonl"), "a", encoding="utf-8") as f:
191
+ f.write(line)
192
+ except Exception:
193
+ pass
194
+
195
+ def _setup_exception_hooks():
196
+ _orig = sys.excepthook
197
+ def _excepthook(exc_type, exc_value, exc_tb):
198
+ _write_crash(exc_type, exc_value, exc_tb, severity="critical", handled=False)
199
+ _orig(exc_type, exc_value, exc_tb)
200
+ sys.excepthook = _excepthook
201
+ if hasattr(threading, "excepthook"):
202
+ def _thread_excepthook(args):
203
+ _write_crash(args.exc_type, args.exc_value, args.exc_traceback,
204
+ thread_name=args.thread.name if args.thread else "unknown",
205
+ severity="error", handled=False)
206
+ threading.excepthook = _thread_excepthook
207
+
208
+ def _tprint(*args, **kwargs):
209
+ global _last_ts
210
+ now = time.monotonic()
211
+ elapsed = now - _start_ts
212
+ delta = now - _last_ts
213
+ _last_ts = now
214
+ elapsed_str = f"{elapsed*1000:.0f}ms" if elapsed < 1 else (f"{elapsed:.1f}s" if elapsed < 100 else f"{elapsed:.0f}s")
215
+ delta_str = "" if delta < 0.001 else (f"+{delta*1000:.0f}ms" if delta < 1 else (f"+{delta:.1f}s" if delta < 100 else f"+{delta:.0f}s"))
216
+ _builtin_print(*args, **kwargs)
217
+ if _log_latest_path or _log_daily_path:
218
+ sep = kwargs.get("sep", " ")
219
+ end = kwargs.get("end", "\n")
220
+ text = sep.join(str(a) for a in args)
221
+ ts = datetime.now().strftime("%H:%M:%S.%f")[:-3]
222
+ prefix = f"[{elapsed_str:>6}] {ts} {delta_str:>8} "
223
+ _write_log(prefix + _strip_ansi(text) + end)
224
+
225
+ builtins.print = _tprint
226
+
227
+ _project_root = os.environ.get("KITE_PROJECT") or os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
228
+ if _project_root not in sys.path:
229
+ sys.path.insert(0, _project_root)
230
+
231
+
232
+ def _fmt_elapsed(t0: float) -> str:
233
+ d = time.monotonic() - t0
234
+ if d < 1: return f"{d*1000:.0f}ms"
235
+ if d < 10: return f"{d:.1f}s"
236
+ return f"{d:.0f}s"
237
+
238
+
239
+ def _read_stdin_kite_message(expected_type: str, timeout: float = 10) -> dict | None:
240
+ result = [None]
241
+ def _read():
242
+ try:
243
+ line = sys.stdin.readline().strip()
244
+ if line:
245
+ msg = json.loads(line)
246
+ if isinstance(msg, dict) and msg.get("kite") == expected_type:
247
+ result[0] = msg
248
+ except Exception:
249
+ pass
250
+ t = threading.Thread(target=_read, daemon=True)
251
+ t.start()
252
+ t.join(timeout=timeout)
253
+ return result[0]
254
+
255
+
256
+ # ── Global state ──
257
+
258
+ _ws_global = None
259
+ _shutting_down = False
260
+ _exit_code = 0
261
+ _gateway_ws_server = None
262
+ _pending_rpc: dict[str, asyncio.Future] = {} # id -> Future for RPC responses
263
+
264
+ _has_registered = False
265
+
266
+ # 弹性多连接
267
+ _extra_ws: dict = {} # slot → WebSocket(附加连接)
268
+ _extra_ws_tasks: dict = {} # slot → recv loop Task
269
+ _kernel_port_cached = "" # 缓存 kernel_port,供 offer handler 使用
270
+
271
+
272
+ # ── RPC call with response awaiting ──
273
+
274
+ async def _rpc_call(ws, method: str, params: dict = None,
275
+ wait_response: bool = True, timeout: float = 3.0) -> dict:
276
+ """JSON-RPC 2.0 request。默认等待响应。"""
277
+ rpc_id = str(uuid.uuid4())
278
+ msg = {"jsonrpc": "2.0", "id": rpc_id, "method": method}
279
+ if params:
280
+ msg["params"] = params
281
+ if not wait_response:
282
+ await ws.send(json.dumps(msg))
283
+ return {}
284
+ future = asyncio.get_event_loop().create_future()
285
+ _pending_rpc[rpc_id] = future
286
+ await ws.send(json.dumps(msg))
287
+ try:
288
+ return await asyncio.wait_for(future, timeout=timeout)
289
+ except asyncio.TimeoutError:
290
+ _pending_rpc.pop(rpc_id, None)
291
+ return {"error": {"code": -32000, "message": f"RPC timeout: {method} ({timeout}s)"}}
292
+
293
+
294
+ async def _rpc_call_await(method: str, params: dict = None, timeout: float = 10) -> dict:
295
+ """RPC call that waits for response. Used by ws_server to call Auth/Launcher.
296
+ Returns unwrapped result dict; raises on error."""
297
+ if not _ws_global:
298
+ raise Exception("Not connected to Kernel")
299
+ rpc_id = str(uuid.uuid4())
300
+ msg = {"jsonrpc": "2.0", "id": rpc_id, "method": method}
301
+ if params:
302
+ msg["params"] = params
303
+
304
+ fut = asyncio.get_event_loop().create_future()
305
+ _pending_rpc[rpc_id] = fut
306
+ try:
307
+ await _ws_global.send(json.dumps(msg))
308
+ resp = await asyncio.wait_for(fut, timeout=timeout)
309
+ # _handle_rpc_response sets the whole message; extract result or raise
310
+ if "error" in resp:
311
+ err = resp["error"]
312
+ raise Exception(f"[{err.get('code', -32603)}] {err.get('message', 'RPC error')}")
313
+ return resp.get("result", {})
314
+ except asyncio.TimeoutError:
315
+ print(f"[gateway] RPC timeout: {method} (id={rpc_id[:8]}..., timeout={timeout}s)")
316
+ raise
317
+ finally:
318
+ _pending_rpc.pop(rpc_id, None)
319
+
320
+
321
+ def _handle_rpc_response(msg: dict):
322
+ """处理 RPC 响应,resolve 对应的 pending future。"""
323
+ rpc_id = msg.get("id")
324
+ future = _pending_rpc.pop(rpc_id, None)
325
+ if future and not future.done():
326
+ future.set_result(msg)
327
+
328
+
329
+ async def _do_init(ws):
330
+ """收到 system.require_init 后执行:subscribe + register + module.ready"""
331
+ global _has_registered, _gateway_ws_server
332
+ reason = "startup" if not _has_registered else "recovery"
333
+ print(f"[gateway] Received system.require_init (reason={reason})")
334
+
335
+ # 1. Subscribe
336
+ await _rpc_call(ws, "event.subscribe", {
337
+ "events": ["module.ready", "module.shutdown", "auth.token.revoked"],
338
+ }, wait_response=False)
339
+ print(f"[gateway] Subscribed to events")
340
+
341
+ # 2. Start WS server BEFORE register (need actual port for registration)
342
+ if _gateway_ws_server is None:
343
+ from ws_server import GatewayWSServer
344
+ listen_port = int(os.environ.get("KITE_MODULE_PORT", "0")) or PREFERRED_PORT
345
+ _gateway_ws_server = GatewayWSServer(
346
+ host="0.0.0.0",
347
+ port=listen_port,
348
+ kernel_port=_kernel_port_cached,
349
+ rpc_call_fn=_rpc_call_await,
350
+ publish_event_fn=_publish_event_global,
351
+ )
352
+ await _gateway_ws_server.start()
353
+ print(f"[gateway] WS server started on port {listen_port}")
354
+ else:
355
+ listen_port = _gateway_ws_server.port
356
+
357
+ # 3. Register with endpoint info
358
+ await _rpc_call(ws, "registry.register", {
359
+ "module_id": "gateway",
360
+ "module_type": "service",
361
+ "launcher_id": "launcher",
362
+ "base_url": f"ws://{ADVERTISE_IP}:{listen_port}",
363
+ "display": {
364
+ "urls": {
365
+ "Gateway WS": f"ws://127.0.0.1:{listen_port}",
366
+ }
367
+ },
368
+ "tools": {
369
+ "rpc": {
370
+ "module": {
371
+ "health": {"method": "health", "description": "健康检查"},
372
+ "status": {"method": "status", "description": "状态查询"},
373
+ }
374
+ }
375
+ },
376
+ "events_publish": {},
377
+ "events_subscribe": ["module.ready", "module.shutdown", "auth.token.revoked"],
378
+ }, wait_response=False)
379
+ print(f"[gateway] Registered to Kernel")
380
+
381
+ # 4. module.ready
382
+ if not _shutting_down:
383
+ await _publish_event(ws, "module.ready", {
384
+ "module_id": "gateway",
385
+ "graceful_shutdown": True,
386
+ "startup_time": time.monotonic() - _start_ts,
387
+ "reason": reason,
388
+ })
389
+ print(f"[gateway] module.ready published (reason={reason})")
390
+
391
+ _has_registered = True
392
+
393
+
394
+ async def _publish_event(ws, event: str, data: dict = None):
395
+ """发布事件到 Kernel(fire-and-forget)。"""
396
+ await _rpc_call(ws, "event.publish", {
397
+ "event_id": str(uuid.uuid4()),
398
+ "event": event,
399
+ "data": data or {},
400
+ }, wait_response=False)
401
+
402
+
403
+ async def _publish_event_global(event: str, data: dict = None):
404
+ """供 ws_server 使用的事件发布。"""
405
+ if _ws_global:
406
+ await _publish_event(_ws_global, event, data)
407
+
408
+
409
+ # ── Event + RPC handlers ──
410
+
411
+ async def _handle_ping_event(data: dict):
412
+ if _ws_global:
413
+ await _publish_event(_ws_global, "system.pong", {
414
+ "module_id": MODULE_NAME, "ping_time": data.get("ping_time"), "pong_time": time.time(),
415
+ })
416
+
417
+
418
+ async def _handle_event_notification(msg: dict):
419
+ params = msg.get("params", {})
420
+ event_type = params.get("event", "")
421
+ data = params.get("data", {})
422
+
423
+ if event_type == "system.ping":
424
+ await _handle_ping_event(data)
425
+ return
426
+
427
+ # 弹性连接 offer/release
428
+ if event_type == "system.connection.offer":
429
+ asyncio.create_task(_handle_connection_offer(data))
430
+ return
431
+ if event_type == "system.connection.release":
432
+ asyncio.create_task(_handle_connection_release(data))
433
+ return
434
+
435
+ if event_type == "module.shutdown":
436
+ target = data.get("module_id", "")
437
+ reason = data.get("reason", "")
438
+ if target == "gateway" or not target or reason == "launcher_lost":
439
+ await _handle_shutdown()
440
+ return
441
+
442
+ # auth.token.revoked → 踢掉对应会话
443
+ if event_type == "auth.token.revoked" and _gateway_ws_server:
444
+ token_prefix = data.get("token_prefix", "")
445
+ if token_prefix:
446
+ _gateway_ws_server.remove_session_by_token_prefix(token_prefix)
447
+ return
448
+
449
+ if event_type in SYSTEM_BROADCAST_EVENTS:
450
+ return
451
+
452
+
453
+ async def _handle_rpc_request(ws, msg: dict):
454
+ rpc_id = msg.get("id", "")
455
+ method = msg.get("method", "")
456
+ params = msg.get("params", {})
457
+
458
+ handlers = {
459
+ "health": lambda p: _rpc_health(),
460
+ "status": lambda p: _rpc_status(),
461
+ }
462
+ handler = handlers.get(method)
463
+ if handler:
464
+ try:
465
+ result = await handler(params)
466
+ await ws.send(json.dumps({"jsonrpc": "2.0", "id": rpc_id, "result": result}))
467
+ except Exception as e:
468
+ await ws.send(json.dumps({
469
+ "jsonrpc": "2.0", "id": rpc_id,
470
+ "error": {"code": -32603, "message": str(e)},
471
+ }))
472
+ else:
473
+ await ws.send(json.dumps({
474
+ "jsonrpc": "2.0", "id": rpc_id,
475
+ "error": {"code": -32601, "message": f"Method not found: {method}"},
476
+ }))
477
+
478
+
479
+ async def _rpc_health() -> dict:
480
+ sessions = len(_gateway_ws_server._sessions) if _gateway_ws_server else 0
481
+ return {"status": "healthy", "details": {"uptime_seconds": round(time.monotonic() - _start_ts), "active_sessions": sessions}}
482
+
483
+
484
+ async def _rpc_status() -> dict:
485
+ sessions = len(_gateway_ws_server._sessions) if _gateway_ws_server else 0
486
+ return {"module": "gateway", "status": "running", "uptime_seconds": round(time.monotonic() - _start_ts), "active_sessions": sessions}
487
+
488
+
489
+ # ── WebSocket connection + message loop ──
490
+
491
+ def _print_crash_summary_sync(exc_type, exc_tb, thread_name=None):
492
+ """Print crash summary to console (red highlight)."""
493
+ RED = "\033[91m"
494
+ RESET = "\033[0m"
495
+ if exc_tb:
496
+ tb_entries = traceback.extract_tb(exc_tb)
497
+ if tb_entries:
498
+ last = tb_entries[-1]
499
+ location = f"{os.path.basename(last.filename)}:{last.lineno}"
500
+ else:
501
+ location = "unknown"
502
+ else:
503
+ location = "unknown"
504
+ prefix = f"[{MODULE_NAME}]"
505
+ if thread_name:
506
+ _builtin_print(f"{prefix} {RED}线程 {thread_name} 崩溃: {exc_type.__name__} in {location}{RESET}")
507
+ else:
508
+ _builtin_print(f"{prefix} {RED}崩溃: {exc_type.__name__} in {location}{RESET}")
509
+ if _crash_log_path:
510
+ _builtin_print(f"{prefix} 崩溃日志: {_crash_log_path}")
511
+
512
+
513
+ async def _ws_loop(token: str, kernel_port: int, _t0: float):
514
+ global _shutting_down, _exit_code
515
+ retry_delay = 0.5
516
+ max_delay = 10.0
517
+ attempt = 0
518
+ cooldown_attempts = 0
519
+ conn_refused_count = 0
520
+
521
+ while not _shutting_down:
522
+ try:
523
+ await _ws_connect(token, kernel_port, _t0)
524
+ retry_delay = 0.5
525
+ attempt = 0
526
+ cooldown_attempts = 0
527
+ conn_refused_count = 0
528
+ except asyncio.CancelledError:
529
+ return
530
+ except Exception as e:
531
+ if _shutting_down:
532
+ return
533
+ code = _get_close_code(e)
534
+ if code in (4001, 4003, 4004, 1008, 4010):
535
+ print(f"[gateway] 致命错误 (code {code}),退出")
536
+ _exit_code = 1
537
+ _shutting_down = True
538
+ return
539
+ if code == 4020:
540
+ cooldown_attempts += 1
541
+ if cooldown_attempts >= 5:
542
+ print(f"[gateway] 速率限制重试 5 次,退出")
543
+ _exit_code = 1
544
+ _shutting_down = True
545
+ return
546
+ print(f"[gateway] 速率限制,10s 后重试 ({cooldown_attempts}/5)")
547
+ await asyncio.sleep(10.0)
548
+ continue
549
+
550
+ # 连接被拒绝/重置 — Kernel 可能正在关闭
551
+ # Windows 的 [WinError 1225] 是 OSError 不是 ConnectionRefusedError
552
+ _is_conn_refused = isinstance(e, (ConnectionRefusedError, ConnectionResetError))
553
+ if not _is_conn_refused and isinstance(e, OSError) and getattr(e, 'winerror', None) == 1225:
554
+ _is_conn_refused = True
555
+ if _is_conn_refused:
556
+ conn_refused_count += 1
557
+ if conn_refused_count >= 3:
558
+ print(f"[gateway] Kernel 持续不可达 ({conn_refused_count} 次),正常退出")
559
+ _exit_code = 0
560
+ _shutting_down = True
561
+ return
562
+ jitter = retry_delay * 0.2 * random.random()
563
+ sleep_time = retry_delay + jitter
564
+ print(f"[gateway] Kernel 连接失败: {type(e).__name__}, {sleep_time:.1f}s 后重试 ({conn_refused_count}/3)")
565
+ else:
566
+ conn_refused_count = 0
567
+ attempt += 1
568
+ jitter = retry_delay * 0.2 * random.random()
569
+ sleep_time = retry_delay + jitter
570
+ _write_crash(type(e), e, e.__traceback__, severity="error", handled=True)
571
+ print(f"[gateway] 连接错误: {e}, {sleep_time:.1f}s 后重试 (attempt {attempt})")
572
+ if attempt >= 10:
573
+ print(f"[gateway] 连续 {attempt} 次连接失败,正常退出")
574
+ _exit_code = 0
575
+ _shutting_down = True
576
+ return
577
+
578
+ _ws_global_clear()
579
+ if _shutting_down:
580
+ return
581
+ await asyncio.sleep(sleep_time if 'sleep_time' in locals() else retry_delay)
582
+ retry_delay = min(retry_delay * 2, max_delay)
583
+
584
+
585
+ def _get_close_code(e: Exception) -> int:
586
+ if hasattr(e, 'rcvd') and e.rcvd is not None:
587
+ return getattr(e.rcvd, 'code', 0)
588
+ return 0
589
+
590
+
591
+ def _ws_global_clear():
592
+ global _ws_global
593
+ _ws_global = None
594
+ # 清理所有 pending RPC futures
595
+ for fut in _pending_rpc.values():
596
+ if not fut.done():
597
+ fut.set_exception(Exception("Connection lost"))
598
+ _pending_rpc.clear()
599
+
600
+
601
+ async def _ws_connect(token: str, kernel_port: int, _t0: float):
602
+ global _ws_global, _gateway_ws_server, _kernel_port_cached
603
+ _kernel_port_cached = kernel_port
604
+
605
+ ws_url = f"ws://127.0.0.1:{kernel_port}/ws?id=gateway"
606
+ print(f"[gateway] Connecting to Kernel: {ws_url}")
607
+
608
+ async with websockets.connect(ws_url, open_timeout=5, ping_interval=None, close_timeout=10) as ws:
609
+ # Auth
610
+ await ws.send(json.dumps({
611
+ "jsonrpc": "2.0", "id": "auth", "method": "auth",
612
+ "params": {"token": token}
613
+ }))
614
+ auth_resp = json.loads(await asyncio.wait_for(ws.recv(), timeout=5))
615
+ if "error" in auth_resp:
616
+ raise Exception(f"Auth failed: {auth_resp['error']}")
617
+
618
+ _ws_global = ws
619
+ print(f"[gateway] Connected to Kernel ({_fmt_elapsed(_t0)})")
620
+
621
+ # Message loop — wait for system.require_init to trigger _do_init
622
+ async for raw in ws:
623
+ try:
624
+ msg = json.loads(raw)
625
+ except (json.JSONDecodeError, TypeError):
626
+ continue
627
+ try:
628
+ has_method = "method" in msg
629
+ has_id = "id" in msg
630
+ has_result = "result" in msg or "error" in msg
631
+
632
+ if has_method and not has_id:
633
+ # 检测 system.require_init 事件
634
+ params = msg.get("params", {})
635
+ event_type = params.get("event", "")
636
+ if event_type == "system.require_init":
637
+ asyncio.create_task(_do_init(ws))
638
+ continue
639
+ asyncio.create_task(_handle_event_notification(msg))
640
+ elif has_method and has_id:
641
+ asyncio.create_task(_handle_rpc_request(ws, msg))
642
+ elif has_id and has_result:
643
+ _handle_rpc_response(msg)
644
+ except Exception as e:
645
+ print(f"[gateway] 消息处理异常(已忽略): {e}")
646
+
647
+
648
+ async def _handle_connection_offer(data):
649
+ """处理 Kernel 下发的 slot token,建立附加连接。"""
650
+ slots = data.get("slots", {})
651
+ for slot_str, info in slots.items():
652
+ slot = int(slot_str)
653
+ token = info.get("token", "")
654
+ if not token or slot in _extra_ws:
655
+ continue
656
+ asyncio.create_task(_connect_slot(slot, token))
657
+
658
+
659
+ async def _connect_slot(slot, token):
660
+ """建立单个 slot 附加连接。"""
661
+ ws_url = f"ws://127.0.0.1:{_kernel_port_cached}/ws"
662
+ try:
663
+ ws = await websockets.connect(ws_url, open_timeout=5, ping_interval=None, close_timeout=5)
664
+ auth_req = {"jsonrpc": "2.0", "id": f"auth-slot-{slot}", "method": "auth", "params": {"token": token}}
665
+ await ws.send(json.dumps(auth_req))
666
+ resp = json.loads(await asyncio.wait_for(ws.recv(), timeout=5))
667
+ if "error" in resp:
668
+ await ws.close()
669
+ return
670
+ _extra_ws[slot] = ws
671
+ _extra_ws_tasks[slot] = asyncio.create_task(_slot_recv_loop(slot, ws))
672
+ print(f"[gateway] Slot {slot} connected")
673
+ except Exception as e:
674
+ print(f"[gateway] Slot {slot} connect failed: {e}")
675
+
676
+
677
+ async def _slot_recv_loop(slot, ws):
678
+ """附加连接的接收循环:与主连接平等处理所有消息。"""
679
+ try:
680
+ async for raw in ws:
681
+ try:
682
+ msg = json.loads(raw)
683
+ except (json.JSONDecodeError, TypeError):
684
+ continue
685
+ try:
686
+ has_method = "method" in msg
687
+ has_id = "id" in msg
688
+ has_result = "result" in msg or "error" in msg
689
+
690
+ if has_method and not has_id:
691
+ asyncio.create_task(_handle_event_notification(msg))
692
+ elif has_method and has_id:
693
+ asyncio.create_task(_handle_rpc_request(ws, msg))
694
+ elif has_id and has_result:
695
+ _handle_rpc_response(msg)
696
+ except Exception as e:
697
+ print(f"[gateway] Slot {slot} 消息处理异常(已忽略): {e}")
698
+ except Exception as e:
699
+ print(f"[gateway] Slot {slot} 接收循环异常: {e}")
700
+ finally:
701
+ _extra_ws.pop(slot, None)
702
+ _extra_ws_tasks.pop(slot, None)
703
+
704
+
705
+ async def _handle_connection_release(data):
706
+ """Kernel 请求释放 slot,优雅关闭。"""
707
+ for slot in data.get("slots", []):
708
+ ws = _extra_ws.pop(slot, None)
709
+ task = _extra_ws_tasks.pop(slot, None)
710
+ if ws:
711
+ try:
712
+ await ws.close(code=1000, reason="release")
713
+ except Exception:
714
+ pass
715
+ if task:
716
+ task.cancel()
717
+
718
+
719
+ async def _handle_shutdown():
720
+ global _shutting_down
721
+ print("[gateway] Received shutdown request")
722
+ _shutting_down = True
723
+
724
+ # 停止 WS 服务器
725
+ if _gateway_ws_server:
726
+ await _gateway_ws_server.stop()
727
+
728
+ # 关闭所有附加连接
729
+ for _s, _w in list(_extra_ws.items()):
730
+ try:
731
+ await _w.close(code=1000, reason="shutdown")
732
+ except Exception:
733
+ pass
734
+ for _t in _extra_ws_tasks.values():
735
+ _t.cancel()
736
+ _extra_ws.clear()
737
+ _extra_ws_tasks.clear()
738
+
739
+ await _publish_event(_ws_global, "module.shutdown.ack", {"module_id": "gateway"})
740
+ await _publish_event(_ws_global, "module.exiting", {
741
+ "module_id": "gateway", "type": "passive",
742
+ "reason": "shutdown_requested", "restart": "auto",
743
+ "action": "none", "timeout": 5.0, "restart_delay": 0.0,
744
+ })
745
+ await _publish_event(_ws_global, "module.shutdown.ready", {"module_id": "gateway"})
746
+ print("[gateway] Shutdown ready, exiting")
747
+ await asyncio.sleep(0.1)
748
+ if _ws_global:
749
+ try:
750
+ await _ws_global.close(code=1000, reason="Graceful shutdown")
751
+ except Exception:
752
+ pass
753
+
754
+
755
+ # ── Startup ──
756
+
757
+ def _init_logs(log_base_dir: str = None, suffix: str = ""):
758
+ """初始化日志系统(本地/远程共用)。"""
759
+ global _log_dir, _log_latest_path, _crash_log_path
760
+
761
+ if log_base_dir:
762
+ _log_dir = os.path.join(log_base_dir, "log")
763
+ os.makedirs(_log_dir, exist_ok=True)
764
+ _log_latest_path = os.path.join(_log_dir, f"latest{suffix}.log")
765
+ try:
766
+ with open(_log_latest_path, "w", encoding="utf-8") as f: pass
767
+ except Exception: _log_latest_path = None
768
+ _crash_log_path = os.path.join(_log_dir, f"crashes{suffix}.jsonl")
769
+ try:
770
+ with open(_crash_log_path, "w", encoding="utf-8") as f: pass
771
+ except Exception: _crash_log_path = None
772
+ _resolve_daily_log_path()
773
+
774
+ _setup_exception_hooks()
775
+
776
+
777
+ def _run_local_mode(kernel_port: int):
778
+ """本地模式:从 stdin 读 boot_info,连接 Kernel。"""
779
+ module_data = os.environ.get("KITE_MODULE_DATA")
780
+ suffix = os.environ.get("KITE_INSTANCE_SUFFIX", "")
781
+ _init_logs(log_base_dir=module_data, suffix=suffix)
782
+
783
+ _t0 = time.monotonic()
784
+ line = sys.stdin.readline().strip()
785
+ if not line:
786
+ print(f"[{MODULE_NAME}] ERROR: stdin closed"); sys.exit(1)
787
+ try: msg = json.loads(line)
788
+ except json.JSONDecodeError as e:
789
+ print(f"[{MODULE_NAME}] ERROR: Invalid JSON: {e}"); sys.exit(1)
790
+ if "error" in msg:
791
+ print(f"[{MODULE_NAME}] 启动失败: {msg.get('message')}"); sys.exit(1)
792
+ token = msg.get("token", "")
793
+ if not token:
794
+ print(f"[{MODULE_NAME}] ERROR: No token"); sys.exit(1)
795
+
796
+ print(f"[{MODULE_NAME}] Local mode: port={kernel_port}")
797
+ try:
798
+ asyncio.run(_ws_loop(token, kernel_port, _t0))
799
+ except (ConnectionRefusedError, ConnectionResetError, OSError) as e:
800
+ if isinstance(e, OSError) and getattr(e, 'winerror', None) != 1225 and not isinstance(e, (ConnectionRefusedError, ConnectionResetError)):
801
+ raise
802
+ print(f"[{MODULE_NAME}] Kernel 不可达,正常退出")
803
+ sys.exit(0)
804
+ except Exception as e:
805
+ _write_crash(type(e), e, e.__traceback__, severity="critical", handled=True)
806
+ _print_crash_summary_sync(type(e), e.__traceback__)
807
+ sys.exit(1)
808
+ sys.exit(_exit_code)
809
+
810
+
811
+ def _run_remote_mode(gateway_url: str):
812
+ """远程模式:通过 Gateway 连接 Kernel。"""
813
+ home = os.environ.get("HOME") or os.environ.get("USERPROFILE") or os.path.expanduser("~")
814
+ data_dir = os.path.join(home, ".kite", "remote", MODULE_NAME)
815
+ os.makedirs(data_dir, exist_ok=True)
816
+ _init_logs(log_base_dir=data_dir)
817
+
818
+ _t0 = time.monotonic()
819
+ kite_token = _get_kite_token(MODULE_NAME, gateway_url)
820
+ print(f"[{MODULE_NAME}] Remote mode: gateway={gateway_url}")
821
+
822
+ try:
823
+ asyncio.run(_remote_ws_loop(gateway_url, kite_token, _t0))
824
+ except Exception as e:
825
+ _write_crash(type(e), e, e.__traceback__, severity="critical", handled=True)
826
+ _print_crash_summary_sync(type(e), e.__traceback__)
827
+ sys.exit(1)
828
+ sys.exit(_exit_code)
829
+
830
+
831
+ async def _remote_ws_loop(gateway_url: str, kite_token: str, _t0: float):
832
+ """远程模式重连循环。"""
833
+ global _shutting_down, _exit_code
834
+ retry_delay = 0.5
835
+ max_delay = 10.0
836
+
837
+ while not _shutting_down:
838
+ try:
839
+ await _remote_connect(gateway_url, kite_token, _t0)
840
+ retry_delay = 0.5
841
+ except asyncio.CancelledError:
842
+ return
843
+ except Exception as e:
844
+ if _shutting_down: return
845
+ _write_crash(type(e), e, e.__traceback__, severity="error", handled=True)
846
+ jitter = retry_delay * 0.2 * random.random()
847
+ print(f"[{MODULE_NAME}] 远程连接错误: {e}, {retry_delay + jitter:.1f}s 后重试")
848
+ await asyncio.sleep(retry_delay + jitter)
849
+ retry_delay = min(retry_delay * 2, max_delay)
850
+
851
+ _ws_global_clear()
852
+ if _shutting_down: return
853
+
854
+
855
+ async def _remote_connect(gateway_url: str, kite_token: str, _t0: float):
856
+ """远程模式:连接 Gateway 并走认证+注册+启动 WS 服务器流程。"""
857
+ global _ws_global, _gateway_ws_server
858
+
859
+ print(f"[{MODULE_NAME}] Connecting to Gateway: {gateway_url}")
860
+ async with websockets.connect(gateway_url, open_timeout=10, ping_interval=None, close_timeout=10) as ws:
861
+ # 1. 接收 challenge
862
+ challenge = json.loads(await asyncio.wait_for(ws.recv(), timeout=10))
863
+ nonce = challenge.get("params", {}).get("nonce", "")
864
+
865
+ # 2. 发送 auth.connect
866
+ await ws.send(json.dumps({
867
+ "jsonrpc": "2.0", "id": "auth-connect",
868
+ "method": "auth.connect",
869
+ "params": {
870
+ "nonce": nonce,
871
+ "module_id": MODULE_NAME,
872
+ "auth": {"method": "kite_token", "token": kite_token},
873
+ "client": {"type": "module"}
874
+ }
875
+ }))
876
+
877
+ # 3. 等待认证响应
878
+ resp = json.loads(await asyncio.wait_for(ws.recv(), timeout=10))
879
+ if "error" in resp:
880
+ error = resp["error"]
881
+ code = error.get("code", 0)
882
+ if code in (4001, 4010, 4011):
883
+ _clear_token_cache(MODULE_NAME, gateway_url)
884
+ print(f"[{MODULE_NAME}] Token 无效,请重新配对")
885
+ sys.exit(1)
886
+ raise Exception(f"Gateway 认证失败: {error}")
887
+
888
+ _ws_global = ws
889
+ print(f"[{MODULE_NAME}] Connected via Gateway ({_fmt_elapsed(_t0)})")
890
+
891
+ # Message loop — wait for system.require_init to trigger _do_init
892
+ async for raw in ws:
893
+ try:
894
+ msg = json.loads(raw)
895
+ except (json.JSONDecodeError, TypeError):
896
+ continue
897
+ try:
898
+ has_method = "method" in msg
899
+ has_id = "id" in msg
900
+ has_result = "result" in msg or "error" in msg
901
+
902
+ if has_method and not has_id:
903
+ # 检测 system.require_init 事件
904
+ params = msg.get("params", {})
905
+ event_type = params.get("event", "")
906
+ if event_type == "system.require_init":
907
+ asyncio.create_task(_do_init(ws))
908
+ continue
909
+ asyncio.create_task(_handle_event_notification(msg))
910
+ elif has_method and has_id:
911
+ asyncio.create_task(_handle_rpc_request(ws, msg))
912
+ elif has_id and has_result:
913
+ _handle_rpc_response(msg)
914
+ except Exception as e:
915
+ print(f"[{MODULE_NAME}] 消息处理异常: {e}")
916
+
917
+
918
+ # ── Token 管理(远程模式)──
919
+
920
+ def _gateway_to_filename(gateway_url: str) -> str:
921
+ try:
922
+ from urllib.parse import urlparse
923
+ parsed = urlparse(gateway_url)
924
+ host = parsed.hostname or "unknown"
925
+ port = parsed.port or (443 if parsed.scheme == "wss" else 80)
926
+ return f"{host}-{port}.json".replace(":", "-").replace("/", "-")
927
+ except Exception: return "default.json"
928
+
929
+ def _load_token_cache(module_name: str, gateway_url: str) -> dict | None:
930
+ home = os.environ.get("HOME") or os.environ.get("USERPROFILE") or os.path.expanduser("~")
931
+ token_file = os.path.join(home, ".kite", "remote", module_name, "tokens", _gateway_to_filename(gateway_url))
932
+ if not os.path.exists(token_file): return None
933
+ try:
934
+ with open(token_file, "r") as f: return json.load(f)
935
+ except Exception: return None
936
+
937
+ def _clear_token_cache(module_name: str, gateway_url: str):
938
+ home = os.environ.get("HOME") or os.environ.get("USERPROFILE") or os.path.expanduser("~")
939
+ token_file = os.path.join(home, ".kite", "remote", module_name, "tokens", _gateway_to_filename(gateway_url))
940
+ try: os.remove(token_file)
941
+ except Exception: pass
942
+
943
+ def _get_kite_token(module_name: str, gateway_url: str) -> str:
944
+ token = os.environ.get("KITE_TOKEN")
945
+ if token: return token
946
+ cache = _load_token_cache(module_name, gateway_url)
947
+ if cache: return cache["token"]
948
+ print(f"[{module_name}] No token for {gateway_url}")
949
+ print(f" export KITE_TOKEN=<token>")
950
+ sys.exit(1)
951
+
952
+
953
+ if __name__ == "__main__":
954
+ kernel_port = os.environ.get("KITE_KERNEL_PORT")
955
+ if kernel_port:
956
+ _run_local_mode(int(kernel_port))
957
+ else:
958
+ config = _load_module_config()
959
+ gateway_url = config.get("gateway_url") or os.environ.get("KITE_GATEWAY_URL")
960
+ if gateway_url:
961
+ _run_remote_mode(gateway_url)
962
+ else:
963
+ print(f"[{MODULE_NAME}] ERROR: No KITE_KERNEL_PORT and no gateway_url")
964
+ sys.exit(1)