@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
@@ -8,6 +8,7 @@ stdio lifecycle:
8
8
  - Structured messages: JSON lines with "kite" field, dispatched via callback
9
9
  """
10
10
 
11
+ import collections
11
12
  import glob
12
13
  import json
13
14
  import os
@@ -16,6 +17,7 @@ import subprocess
16
17
  import sys
17
18
  import threading
18
19
  import time
20
+ from concurrent.futures import ThreadPoolExecutor, as_completed
19
21
  from dataclasses import dataclass, asdict
20
22
  from typing import Callable
21
23
 
@@ -34,21 +36,48 @@ class ProcessRecord:
34
36
  cmd: list
35
37
  module_dir: str
36
38
  started_at: float
39
+ instance_num: int = 1
37
40
 
38
41
 
39
42
  class ProcessManager:
40
43
  """Manage child processes for all Kite modules."""
41
44
 
45
+ @staticmethod
46
+ def _instance_key(name: str, instance_num: int = 1) -> str:
47
+ """Build internal dict key: 'name' for instance 1, 'name#N' for N>1."""
48
+ return name if instance_num <= 1 else f"{name}#{instance_num}"
49
+
50
+ @staticmethod
51
+ def parse_instance_key(key: str) -> tuple[str, int]:
52
+ """Parse internal key back to (module_name, instance_num)."""
53
+ if "#" in key:
54
+ name, num_str = key.rsplit("#", 1)
55
+ try:
56
+ return name, int(num_str)
57
+ except ValueError:
58
+ pass
59
+ return key, 1
60
+
61
+ LOG_BUFFER_SIZE = 1000 # lines per module
62
+
42
63
  def __init__(self, kite_token: str, instance_id: str = "",
43
- on_kite_message: Callable[[str, dict], None] | None = None):
64
+ on_kite_message: Callable[[str, dict], None] | None = None,
65
+ on_log_line: Callable[[str, float, str], None] | None = None):
44
66
  """
45
67
  Args:
46
68
  on_kite_message: callback(module_name, msg_dict) for structured stdout messages.
47
69
  Called from stdout reader thread — must be thread-safe.
70
+ on_log_line: callback(module_name, timestamp, line) for every log line.
71
+ Called from stdout reader thread — must be thread-safe.
48
72
  """
49
73
  self.kite_token = kite_token
50
74
  self.instance_id = instance_id or str(os.getpid())
51
75
  self._on_kite_message = on_kite_message
76
+ self._on_log_line = on_log_line
77
+ # Per-module ring buffers: name -> deque of (seq, ts, line)
78
+ self._log_buffers: dict[str, collections.deque] = {}
79
+ self._log_seq: dict[str, int] = {} # name -> next seq number
80
+ self._log_lock = threading.Lock()
52
81
  # Use KITE_MODULE_DATA (set by Launcher for itself)
53
82
  launcher_dir = os.environ.get("KITE_MODULE_DATA") or os.path.join(os.environ["KITE_INSTANCE_DIR"], "launcher")
54
83
  self.data_dir = os.path.join(launcher_dir, "state")
@@ -249,10 +278,24 @@ class ProcessManager:
249
278
  """
250
279
  my_pid = os.getpid()
251
280
  inst_name = os.path.basename(os.environ.get("KITE_INSTANCE_DIR", "")) or "unknown"
252
- killed = 0
281
+
282
+ # Collect all processes*.json files
253
283
  pattern = os.path.join(self.data_dir, "processes*.json")
254
- for filepath in glob.glob(pattern):
255
- killed += self._cleanup_one_leftover_file(filepath, my_pid)
284
+ files_to_cleanup = list(glob.glob(pattern))
285
+
286
+ if not files_to_cleanup:
287
+ return {}
288
+
289
+ # Parallel cleanup: each file runs its own 3-phase cleanup independently
290
+ killed = 0
291
+ with ThreadPoolExecutor(max_workers=len(files_to_cleanup)) as executor:
292
+ futures = [executor.submit(self._cleanup_one_leftover_file, filepath, my_pid) for filepath in files_to_cleanup]
293
+ for future in as_completed(futures):
294
+ try:
295
+ killed += future.result()
296
+ except Exception as e:
297
+ print(f"[launcher] 清理残留文件时出错: {e}")
298
+
256
299
  return {inst_name: killed} if killed else {}
257
300
 
258
301
  def cleanup_global_leftovers(self) -> dict[str, int]:
@@ -274,15 +317,35 @@ class ProcessManager:
274
317
  except OSError:
275
318
  return {}
276
319
 
320
+ # Collect all processes*.json files
321
+ files_to_cleanup = []
277
322
  for entry in entries:
278
323
  state_dir = os.path.join(workspace, entry, "launcher", "state")
279
324
  if not os.path.isdir(state_dir):
280
325
  continue
281
326
  pattern = os.path.join(state_dir, "processes*.json")
282
327
  for filepath in glob.glob(pattern):
283
- killed = self._cleanup_one_leftover_file(filepath, my_pid)
284
- if killed:
285
- result[entry] = result.get(entry, 0) + killed
328
+ files_to_cleanup.append((filepath, entry))
329
+
330
+ # Parallel cleanup: each file runs its own 3-phase cleanup independently
331
+ if not files_to_cleanup:
332
+ return result
333
+
334
+ with ThreadPoolExecutor(max_workers=len(files_to_cleanup)) as executor:
335
+ futures = {}
336
+ for filepath, entry in files_to_cleanup:
337
+ future = executor.submit(self._cleanup_one_leftover_file, filepath, my_pid)
338
+ futures[future] = entry
339
+
340
+ for future in as_completed(futures):
341
+ entry = futures[future]
342
+ try:
343
+ killed = future.result()
344
+ if killed:
345
+ result[entry] = result.get(entry, 0) + killed
346
+ except Exception as e:
347
+ print(f"[launcher] 清理实例 {entry} 时出错: {e}")
348
+
286
349
  return result
287
350
 
288
351
  def _cleanup_one_leftover_file(self, filepath: str, my_pid: int) -> int:
@@ -290,7 +353,10 @@ class ProcessManager:
290
353
 
291
354
  - Skip if launcher_pid matches my_pid (our own records).
292
355
  - Skip if launcher_pid is still alive (parallel instance).
293
- - Otherwise clean up child processes and delete the file.
356
+ - Otherwise clean up child processes in 3 phases:
357
+ 1. Kill all watchdog processes (serial)
358
+ 2. Kill all middle-tier processes (parallel)
359
+ 3. Kill all kernel processes (serial)
294
360
  Returns number of processes killed.
295
361
  """
296
362
  try:
@@ -327,30 +393,87 @@ class ProcessManager:
327
393
  return 0
328
394
 
329
395
  # Dead launcher (or old format) — clean up its child processes
330
- # Sort: watchdog first, kernel last, others in middle (prevents cascading issues)
331
- def _cleanup_sort_key(entry):
332
- name = entry.get("name", "")
333
- if name == "watchdog":
334
- return (0, name)
335
- if name == "kernel":
336
- return (2, name)
337
- return (1, name)
396
+ # New approach: All processes start cleanup in parallel with dependency checks
397
+ all_procs = records
398
+ if not all_procs:
399
+ try:
400
+ os.remove(filepath)
401
+ except OSError:
402
+ pass
403
+ return 0
338
404
 
339
- records_sorted = sorted(records, key=_cleanup_sort_key)
405
+ # Shared state for dependency tracking (instance-local)
406
+ killed_names = set() # Track which process names have been killed
407
+ killed_lock = threading.Lock()
408
+ killed_condition = threading.Condition(killed_lock) # Notify when any process is killed
340
409
 
341
- killed = 0
342
- for entry in records_sorted:
410
+ def cleanup_with_deps(entry: dict) -> bool:
411
+ """Cleanup a single process with dependency checking."""
412
+ name = entry.get("name", "")
343
413
  pid = entry.get("pid", 0)
344
414
  cmd = entry.get("cmd", [])
345
- name = entry.get("name", "?")
415
+
346
416
  if not pid:
347
- continue
348
- if self._is_pid_alive(pid) and self._cmd_matches(pid, cmd):
349
- print(f"[launcher] 正在清理残留进程: {name} (PID {pid}) [{os.path.basename(filepath)}]")
350
- self._force_kill(pid)
351
- killed += 1
352
- else:
417
+ return False
418
+
419
+ # Step 1: Verify process is alive
420
+ if not self._is_pid_alive(pid):
353
421
  print(f"[launcher] 残留进程 {name} (PID {pid}) 已不存在")
422
+ with killed_condition:
423
+ killed_names.add(name)
424
+ killed_condition.notify_all() # Notify all waiters
425
+ return False
426
+
427
+ # Step 2: Verify command line (防止 PID 复用误杀)
428
+ if not self._cmd_matches(pid, cmd):
429
+ print(f"[launcher] 残留进程 {name} (PID {pid}) 命令行不匹配,跳过")
430
+ with killed_condition:
431
+ killed_names.add(name) # Mark as "handled" to unblock dependents
432
+ killed_condition.notify_all()
433
+ return False
434
+
435
+ # Step 3: Wait for dependencies (instance-local, event-driven)
436
+ dependencies = self._get_process_dependencies(name, all_procs)
437
+ if dependencies:
438
+ with killed_condition:
439
+ while True:
440
+ # Check if all dependencies are satisfied
441
+ remaining = dependencies - killed_names
442
+ if not remaining:
443
+ break
444
+ # Wait for notification (releases lock, reacquires on wake)
445
+ killed_condition.wait()
446
+
447
+ # Step 4: Kill the process
448
+ print(f"[launcher] 正在清理残留进程: {name} (PID {pid}) [{os.path.basename(filepath)}]")
449
+ self._force_kill(pid)
450
+
451
+ # Step 5: Verify process is dead (wait up to 100ms)
452
+ for i in range(10):
453
+ if not self._is_pid_alive(pid):
454
+ break
455
+ import time
456
+ time.sleep(0.01)
457
+ else:
458
+ print(f"[launcher] 警告: 进程 {name} (PID {pid}) 在 100ms 后仍未退出")
459
+
460
+ # Step 6: Mark as killed and notify waiters
461
+ with killed_condition:
462
+ killed_names.add(name)
463
+ killed_condition.notify_all() # Wake up all waiting threads
464
+
465
+ return True
466
+
467
+ # Launch all cleanup tasks in parallel
468
+ killed = 0
469
+ with ThreadPoolExecutor(max_workers=len(all_procs)) as executor:
470
+ futures = [executor.submit(cleanup_with_deps, entry) for entry in all_procs]
471
+ for future in as_completed(futures):
472
+ try:
473
+ if future.result():
474
+ killed += 1
475
+ except Exception as e:
476
+ print(f"[launcher] 并行清理进程时出错: {e}")
354
477
 
355
478
  try:
356
479
  os.remove(filepath)
@@ -358,6 +481,61 @@ class ProcessManager:
358
481
  pass
359
482
  return killed
360
483
 
484
+ def _get_process_dependencies(self, name: str, all_procs: list) -> set:
485
+ """Get the set of process names that must be killed before this one.
486
+
487
+ Dependency rules (instance-local):
488
+ - watchdog: no dependencies
489
+ - kernel: depends on all other processes in this instance
490
+ - others: depend on watchdog (if exists)
491
+ """
492
+ if name == "watchdog":
493
+ return set()
494
+ elif name == "kernel":
495
+ # Kernel depends on all other processes in this instance
496
+ return {p.get("name", "") for p in all_procs if p.get("name") != "kernel"}
497
+ else:
498
+ # Middle-tier processes depend on watchdog (if exists in this instance)
499
+ watchdog_exists = any(p.get("name") == "watchdog" for p in all_procs)
500
+ return {"watchdog"} if watchdog_exists else set()
501
+
502
+ def _kill_one_process(self, entry: dict, filepath: str, skip_cmd_check: bool = False) -> bool:
503
+ """Kill a single process. Returns True if killed, False otherwise.
504
+
505
+ Args:
506
+ entry: Process record dict with pid, cmd, name
507
+ filepath: Path to processes*.json (for logging)
508
+ skip_cmd_check: If True, skip command line verification (faster, for leftover cleanup)
509
+ """
510
+ import time
511
+ pid = entry.get("pid", 0)
512
+ cmd = entry.get("cmd", [])
513
+ name = entry.get("name", "?")
514
+ if not pid:
515
+ return False
516
+
517
+ # Check if process is alive
518
+ if not self._is_pid_alive(pid):
519
+ print(f"[launcher] 残留进程 {name} (PID {pid}) 已不存在")
520
+ return False
521
+
522
+ # Verify command line (unless skipped for performance)
523
+ if not skip_cmd_check and not self._cmd_matches(pid, cmd):
524
+ print(f"[launcher] 残留进程 {name} (PID {pid}) 命令行不匹配,跳过")
525
+ return False
526
+
527
+ print(f"[launcher] 正在清理残留进程: {name} (PID {pid}) [{os.path.basename(filepath)}]")
528
+ self._force_kill(pid)
529
+
530
+ # Verify the process is actually dead (wait up to 100ms)
531
+ for i in range(10):
532
+ if not self._is_pid_alive(pid):
533
+ return True
534
+ time.sleep(0.01)
535
+
536
+ print(f"[launcher] 警告: 进程 {name} (PID {pid}) 在 100ms 后仍未退出")
537
+ return True
538
+
361
539
  def _is_pid_alive(self, pid: int) -> bool:
362
540
  """Check if a process with given PID exists.
363
541
 
@@ -604,8 +782,18 @@ class ProcessManager:
604
782
  """Force kill a process by PID."""
605
783
  try:
606
784
  if IS_WINDOWS:
607
- subprocess.run(["taskkill", "/F", "/PID", str(pid)],
608
- capture_output=True, timeout=5)
785
+ # Use TerminateProcess API directly (faster than taskkill)
786
+ PROCESS_TERMINATE = 0x0001
787
+ handle = ctypes.windll.kernel32.OpenProcess(PROCESS_TERMINATE, False, pid)
788
+ if handle:
789
+ try:
790
+ ctypes.windll.kernel32.TerminateProcess(handle, 1)
791
+ finally:
792
+ ctypes.windll.kernel32.CloseHandle(handle)
793
+ else:
794
+ # Fallback to taskkill if OpenProcess fails
795
+ subprocess.run(["taskkill", "/F", "/PID", str(pid)],
796
+ capture_output=True, timeout=5)
609
797
  else:
610
798
  import signal
611
799
  os.kill(pid, signal.SIGKILL)
@@ -614,29 +802,37 @@ class ProcessManager:
614
802
 
615
803
  # ── Start module ──
616
804
 
617
- def start_module(self, info, boot_info: dict = None) -> bool:
805
+ def start_module(self, info, boot_info: dict = None, instance_num: int = 1) -> bool:
618
806
  """Start a module as a subprocess. Returns True on success.
619
807
  If boot_info is provided, it is written as JSON to the child's stdin pipe.
620
808
  stdin is kept open after boot_info for Launcher to send additional messages.
809
+
810
+ Args:
811
+ instance_num: Instance number (1=primary, >1=extra instance).
621
812
  """
622
813
  from .module_scanner import ModuleInfo
623
814
  info: ModuleInfo
624
815
 
625
- if info.name in self._processes:
626
- proc = self._processes[info.name]
816
+ key = self._instance_key(info.name, instance_num)
817
+ label = info.name if instance_num <= 1 else f"{info.name}#{instance_num}"
818
+
819
+ if key in self._processes:
820
+ proc = self._processes[key]
627
821
  if proc.poll() is None:
628
- print(f"[launcher] {info.name} 已在运行 (PID {proc.pid})")
822
+ print(f"[launcher] {label} 已在运行 (PID {proc.pid})")
629
823
  return True
630
824
 
631
825
  cmd = self._build_cmd(info)
632
826
  if not cmd:
633
- print(f"[launcher] 错误: 无法构建 {info.name} 的启动命令")
827
+ print(f"[launcher] 错误: 无法构建 {label} 的启动命令")
634
828
  return False
635
829
 
636
830
  env = os.environ.copy()
637
831
  env["PYTHONUTF8"] = "1" # Force UTF-8 in child Python processes
638
832
  env["PYTHONUNBUFFERED"] = "1" # Disable output buffering for real-time logs
639
833
  env["KITE_MODULE_DATA"] = os.path.join(os.environ["KITE_INSTANCE_DIR"], info.name)
834
+ if instance_num > 1:
835
+ env["KITE_INSTANCE_NUM"] = str(instance_num)
640
836
  if info.launch.env:
641
837
  env.update(info.launch.env)
642
838
 
@@ -644,8 +840,6 @@ class ProcessManager:
644
840
  if IS_WINDOWS:
645
841
  creation_flags = subprocess.CREATE_NO_WINDOW
646
842
 
647
- use_stdin = boot_info is not None and info.launch.boot_stdin
648
-
649
843
  cwd = info.module_dir
650
844
  if info.launch.cwd:
651
845
  cwd = os.path.normpath(os.path.join(info.module_dir, info.launch.cwd))
@@ -655,48 +849,50 @@ class ProcessManager:
655
849
  cmd,
656
850
  cwd=cwd,
657
851
  env=env,
658
- stdin=subprocess.PIPE if use_stdin else None,
852
+ stdin=subprocess.PIPE, # stdin 管道始终创建,解耦 boot_info
659
853
  stdout=subprocess.PIPE,
660
854
  stderr=subprocess.STDOUT,
661
855
  creationflags=creation_flags,
662
856
  )
663
857
  except Exception as e:
664
- print(f"[launcher] 错误: 启动 {info.name} 失败: {e}")
858
+ print(f"[launcher] 错误: 启动 {label} 失败: {e}")
665
859
  return False
666
860
 
667
861
  # Write boot_info to stdin — keep stdin open for additional messages
668
- if use_stdin and proc.stdin:
862
+ if boot_info is not None and info.launch.boot_stdin and proc.stdin:
669
863
  try:
670
864
  proc.stdin.write(json.dumps(boot_info).encode() + b"\n")
671
865
  proc.stdin.flush()
672
866
  except Exception as e:
673
- print(f"[launcher] 警告: 向 {info.name} 写入 boot_info 失败: {e}")
867
+ print(f"[launcher] 警告: 向 {label} 写入 boot_info 失败: {e}")
674
868
 
675
- self._processes[info.name] = proc
676
- self._records[info.name] = ProcessRecord(
869
+ self._processes[key] = proc
870
+ self._records[key] = ProcessRecord(
677
871
  name=info.name,
678
872
  pid=proc.pid,
679
873
  cmd=cmd,
680
874
  module_dir=info.module_dir,
681
875
  started_at=time.time(),
876
+ instance_num=instance_num,
682
877
  )
683
878
 
684
879
  # Daemon thread to read stdout: structured messages + log lines
685
880
  t = threading.Thread(
686
- target=self._read_stdout, args=(info.name, proc),
881
+ target=self._read_stdout, args=(label, proc),
687
882
  daemon=True,
688
883
  )
689
884
  t.start()
690
885
 
691
- print(f"[launcher] 已启动 {info.name} (PID {proc.pid})")
886
+ print(f"[launcher] 已启动 {label} (PID {proc.pid})")
692
887
  return True
693
888
 
694
- def write_stdin(self, name: str, data: dict) -> bool:
889
+ def write_stdin(self, name: str, data: dict, instance_num: int = 1) -> bool:
695
890
  """Write a structured JSON message to a module's stdin.
696
891
  Used by Launcher to send additional messages after boot_info (e.g. launcher_ws_token).
697
892
  Returns True on success.
698
893
  """
699
- proc = self._processes.get(name)
894
+ key = self._instance_key(name, instance_num)
895
+ proc = self._processes.get(key)
700
896
  if not proc or not proc.stdin or proc.stdin.closed:
701
897
  return False
702
898
  try:
@@ -707,13 +903,14 @@ class ProcessManager:
707
903
  print(f"[launcher] 警告: 向 {name} 写入 stdin 失败: {e}")
708
904
  return False
709
905
 
710
- def close_stdio(self, name: str):
906
+ def close_stdio(self, name: str, instance_num: int = 1):
711
907
  """Close stdin for a module. Called by Launcher after module.ready → module.started.
712
908
  Only closes stdin (no more messages to send). stdout is left open so the reader
713
909
  thread can continue relaying logs — it exits naturally when the process dies.
714
910
  On Windows, closing stdout while a reader thread is blocked on readline() can deadlock.
715
911
  """
716
- proc = self._processes.get(name)
912
+ key = self._instance_key(name, instance_num)
913
+ proc = self._processes.get(key)
717
914
  if not proc:
718
915
  return
719
916
  if proc.stdin and not proc.stdin.closed:
@@ -769,37 +966,94 @@ class ProcessManager:
769
966
  print(text)
770
967
  else:
771
968
  print(f"[{name}] {text}")
969
+ # Note: terminal buffering is handled by _tprint hook in logging_setup,
970
+ # so the buffer contains the full timestamped+colored output line.
772
971
  except Exception:
773
972
  pass
774
973
 
974
+ def get_log_history(self, name: str, offset: int = 0, count: int = 200) -> dict:
975
+ """Return buffered log lines for a module.
976
+
977
+ Args:
978
+ name: module name (label)
979
+ offset: return lines with seq >= offset; -1 means last `count` lines
980
+ count: max lines to return
981
+ Returns:
982
+ {"lines": [{"seq", "ts", "text"}], "total": int, "module": name}
983
+ """
984
+ with self._log_lock:
985
+ buf = self._log_buffers.get(name)
986
+ if buf is None:
987
+ return {"lines": [], "total": 0, "module": name}
988
+ all_lines = list(buf)
989
+ if offset < 0:
990
+ selected = all_lines[-count:]
991
+ else:
992
+ selected = [e for e in all_lines if e[0] >= offset][:count]
993
+ return {
994
+ "lines": [{"seq": e[0], "ts": e[1], "text": e[2]} for e in selected],
995
+ "total": len(all_lines),
996
+ "module": name,
997
+ }
998
+
999
+ def list_log_modules(self) -> list[str]:
1000
+ """Return list of modules that have log buffer entries."""
1001
+ with self._log_lock:
1002
+ return list(self._log_buffers.keys())
1003
+
775
1004
  # ── Stop module ──
776
1005
 
777
- def stop_module(self, name: str, timeout: float = 5) -> bool:
1006
+ def stop_module(self, name: str, timeout: float = 5, instance_num: int = 1) -> bool:
778
1007
  """Stop a module by name. Returns True if stopped successfully."""
779
- proc = self._processes.get(name)
1008
+ key = self._instance_key(name, instance_num)
1009
+ label = name if instance_num <= 1 else f"{name}#{instance_num}"
1010
+ proc = self._processes.get(key)
780
1011
  if not proc or proc.poll() is not None:
781
- self._processes.pop(name, None)
782
- self._records.pop(name, None)
1012
+ self._processes.pop(key, None)
1013
+ self._records.pop(key, None)
783
1014
  return True
784
1015
 
785
1016
  # Close stdio before terminating
786
- self.close_stdio(name)
1017
+ self.close_stdio(name, instance_num)
787
1018
 
788
- print(f"[launcher] 正在停止 {name} (PID {proc.pid})...")
1019
+ print(f"[launcher] 正在停止 {label} (PID {proc.pid})...")
789
1020
  proc.terminate()
790
1021
  try:
791
1022
  proc.wait(timeout=timeout)
792
1023
  except subprocess.TimeoutExpired:
793
- print(f"[launcher] {name} 在 {timeout}s 内未退出,强制终止")
1024
+ print(f"[launcher] {label} 在 {timeout}s 内未退出,强制终止")
794
1025
  proc.kill()
795
1026
  try:
796
1027
  proc.wait(timeout=3)
797
1028
  except subprocess.TimeoutExpired:
798
1029
  self._force_kill(proc.pid)
799
1030
 
800
- self._processes.pop(name, None)
801
- self._records.pop(name, None)
802
- print(f"[launcher] 已停止 {name}")
1031
+ self._processes.pop(key, None)
1032
+ self._records.pop(key, None)
1033
+ print(f"[launcher] 已停止 {label}")
1034
+ return True
1035
+
1036
+ def ensure_exited(self, name: str, timeout: float = 3, instance_num: int = 1) -> bool:
1037
+ """确保进程已完全退出(用于崩溃后确认端口释放)。"""
1038
+ key = self._instance_key(name, instance_num)
1039
+ proc = self._processes.get(key)
1040
+ if not proc:
1041
+ return True
1042
+ if proc.poll() is not None:
1043
+ self._processes.pop(key, None)
1044
+ self._records.pop(key, None)
1045
+ return True
1046
+ # 还活着,等待或强杀
1047
+ try:
1048
+ proc.wait(timeout=timeout)
1049
+ except subprocess.TimeoutExpired:
1050
+ proc.kill()
1051
+ try:
1052
+ proc.wait(timeout=2)
1053
+ except subprocess.TimeoutExpired:
1054
+ self._force_kill(proc.pid)
1055
+ self._processes.pop(key, None)
1056
+ self._records.pop(key, None)
803
1057
  return True
804
1058
 
805
1059
  def stop_all(self, timeout: float = 10):
@@ -808,7 +1062,7 @@ class ProcessManager:
808
1062
  return
809
1063
 
810
1064
  # Filter to only still-running processes
811
- alive = [n for n, p in self._processes.items() if p.poll() is None]
1065
+ alive = [k for k, p in self._processes.items() if p.poll() is None]
812
1066
  if not alive:
813
1067
  # All already exited — just clean up bookkeeping
814
1068
  self._processes.clear()
@@ -818,16 +1072,17 @@ class ProcessManager:
818
1072
  print(f"[launcher] 正在停止所有模块: {', '.join(alive)}")
819
1073
 
820
1074
  # Phase 1: close stdio and send terminate to all
821
- for name in alive:
822
- self.close_stdio(name)
823
- proc = self._processes.get(name)
1075
+ for key in alive:
1076
+ mod_name, inst_num = self.parse_instance_key(key)
1077
+ self.close_stdio(mod_name, inst_num)
1078
+ proc = self._processes.get(key)
824
1079
  if proc and proc.poll() is None:
825
1080
  proc.terminate()
826
1081
 
827
1082
  # Phase 2: wait for all to exit
828
1083
  deadline = time.time() + timeout
829
- for name in alive:
830
- proc = self._processes.get(name)
1084
+ for key in alive:
1085
+ proc = self._processes.get(key)
831
1086
  if not proc:
832
1087
  continue
833
1088
  remaining = max(0.1, deadline - time.time())
@@ -837,10 +1092,10 @@ class ProcessManager:
837
1092
  pass
838
1093
 
839
1094
  # Phase 3: force kill survivors
840
- for name in alive:
841
- proc = self._processes.get(name)
1095
+ for key in alive:
1096
+ proc = self._processes.get(key)
842
1097
  if proc and proc.poll() is None:
843
- print(f"[launcher] 强制终止 {name} (PID {proc.pid})")
1098
+ print(f"[launcher] 强制终止 {key} (PID {proc.pid})")
844
1099
  proc.kill()
845
1100
  try:
846
1101
  proc.wait(timeout=3)
@@ -855,33 +1110,57 @@ class ProcessManager:
855
1110
 
856
1111
  def persist_records(self):
857
1112
  """Write current process records to processes.json (with launcher_pid for multi-instance)."""
1113
+ import time as _time
1114
+ t0 = _time.monotonic()
858
1115
  data = {
859
1116
  "launcher_pid": os.getpid(),
860
1117
  "debug": os.environ.get("KITE_DEBUG") == "1",
861
1118
  "cwd": os.environ.get("KITE_CWD", ""),
862
1119
  "records": [asdict(r) for r in self._records.values()],
863
1120
  }
1121
+ t1 = _time.monotonic()
864
1122
  self._write_records_file(data)
1123
+ t2 = _time.monotonic()
1124
+ serialize_ms = (t1 - t0) * 1000
1125
+ write_ms = (t2 - t1) * 1000
1126
+ if serialize_ms + write_ms > 50:
1127
+ print(f"[launcher] persist_records 耗时: serialize={serialize_ms:.0f}ms, write={write_ms:.0f}ms")
865
1128
 
866
1129
  def check_exited(self) -> list[tuple[str, int]]:
867
- """Non-blocking check for exited child processes. Returns [(name, returncode)]."""
1130
+ """Non-blocking check for exited child processes. Returns [(key, returncode)].
1131
+ Key is 'name' for primary instances, 'name#N' for extra instances.
1132
+ Use parse_instance_key() to extract (module_name, instance_num).
1133
+ """
868
1134
  exited = []
869
- for name in list(self._processes.keys()):
870
- proc = self._processes[name]
1135
+ for key in list(self._processes.keys()):
1136
+ proc = self._processes[key]
871
1137
  rc = proc.poll()
872
1138
  if rc is not None:
873
- exited.append((name, rc))
874
- self._processes.pop(name, None)
875
- self._records.pop(name, None)
1139
+ exited.append((key, rc))
1140
+ self._processes.pop(key, None)
1141
+ self._records.pop(key, None)
876
1142
  return exited
877
1143
 
878
- def get_record(self, name: str) -> ProcessRecord | None:
879
- return self._records.get(name)
1144
+ def get_record(self, name: str, instance_num: int = 1) -> ProcessRecord | None:
1145
+ key = self._instance_key(name, instance_num)
1146
+ return self._records.get(key)
880
1147
 
881
- def is_running(self, name: str) -> bool:
882
- proc = self._processes.get(name)
1148
+ def is_running(self, name: str, instance_num: int = 1) -> bool:
1149
+ key = self._instance_key(name, instance_num)
1150
+ proc = self._processes.get(key)
883
1151
  return proc is not None and proc.poll() is None
884
1152
 
1153
+ def get_module_instance_keys(self, name: str) -> list[str]:
1154
+ """Return all active instance keys for a given module name."""
1155
+ keys = []
1156
+ for key in self._processes:
1157
+ mod_name, _ = self.parse_instance_key(key)
1158
+ if mod_name == name:
1159
+ proc = self._processes[key]
1160
+ if proc.poll() is None:
1161
+ keys.append(key)
1162
+ return keys
1163
+
885
1164
  def _write_records_file(self, data):
886
1165
  """Write data to the instance's processes JSON file."""
887
1166
  try: