@agentunion/kite 1.4.0 → 1.6.0

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 (718) 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/CHANGELOG.md +102 -0
  23. package/cli.js +78 -5
  24. package/core/dependency_checker.py +250 -0
  25. package/core/env_checker.py +586 -0
  26. package/dependencies_lock.json +128 -0
  27. 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
  28. package/docs/ACP/345/215/217/350/256/256/345/205/274/345/256/271/346/226/271/346/241/210.md +138 -0
  29. 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
  30. package/docs/CLI/345/274/200/345/217/221/350/256/241/345/210/222.md +595 -0
  31. 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
  32. 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
  33. 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
  34. 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
  35. 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
  36. package/docs/Evol/346/250/241/345/235/227/350/256/276/350/256/241/346/226/271/346/241/210.md +1154 -0
  37. 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
  38. 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
  39. package/docs/HTTP-RPC/350/277/201/347/247/273/345/210/260WebSocket/350/256/241/345/210/222.md +318 -0
  40. package/docs/INDEX.md +388 -0
  41. package/docs/KITE_DOCS_GUIDE.md +33 -0
  42. 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
  43. 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
  44. 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
  45. 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
  46. 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
  47. 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
  48. 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
  49. 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
  50. 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
  51. 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
  52. 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
  53. 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
  54. 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
  55. 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
  56. 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
  57. 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
  58. package/docs/Kite/346/241/206/346/236/266/350/256/276/350/256/241/README.md +46 -0
  59. package/docs/Kite/347/263/273/347/273/237/345/220/257/345/212/250/346/265/201/347/250/213.md +567 -0
  60. package/docs/Launcher/345/220/257/345/212/250/345/231/250/346/226/207/346/241/243.md +745 -0
  61. 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
  62. 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
  63. 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
  64. 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
  65. 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
  66. package/docs/Watchdog/350/265/204/346/272/220/347/233/221/346/216/247/347/255/226/347/225/245.md +92 -0
  67. 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
  68. 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
  69. package/docs/WebSocket/350/277/236/346/216/245/351/237/247/346/200/247/346/226/271/346/241/210.md +169 -0
  70. 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
  71. 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
  72. 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
  73. package/docs/audit-api-guide.md +68 -0
  74. package/docs/audit-module-design.md +315 -0
  75. package/docs/audit-module-implementation-summary.md +149 -0
  76. package/docs/llm-context-design.md +52 -0
  77. package/docs/llm-test-enhancement-plan.md +970 -0
  78. package/docs/logs-api-guide.md +42 -0
  79. 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
  80. 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
  81. 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
  82. 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
  83. package/docs//344/272/213/344/273/266/345/244/204/347/220/206/346/234/272/345/210/266.md +388 -0
  84. package/docs//344/272/213/344/273/266/345/244/204/347/220/206/350/247/204/350/214/203.md +113 -0
  85. 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
  86. 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
  87. 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
  88. 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
  89. 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
  90. package/docs//344/274/230/351/233/205/351/200/200/345/207/272/350/247/204/350/214/203.md +362 -0
  91. package/docs//344/276/235/350/265/226/347/256/241/347/220/206/350/257/264/346/230/216.md +141 -0
  92. 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
  93. package/docs//345/210/240/351/231/244kernel-client-example/345/256/214/346/210/220.md +309 -0
  94. package/docs//345/210/240/351/231/244ws-management/345/256/214/346/210/220.md +418 -0
  95. package/docs//345/220/257/345/212/250/344/274/230/345/214/226/346/226/271/346/241/210.md +522 -0
  96. 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
  97. 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
  98. 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
  99. package/docs//345/256/236/347/216/260/350/247/204/345/210/222.md +195 -0
  100. 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
  101. 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
  102. package/docs//346/217/241/346/211/213/350/256/244/350/257/201/346/226/271/346/241/210.md +908 -0
  103. package/docs//346/226/207/346/241/243/346/233/264/346/226/260/346/270/205/345/215/225.md +83 -0
  104. 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
  105. 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
  106. package/docs//346/236/266/346/236/204/345/200/237/351/211/264/346/214/207/345/215/227.md +977 -0
  107. 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
  108. 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
  109. 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
  110. 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
  111. package/docs//346/250/241/345/235/227/345/274/200/345/217/221/346/214/207/345/215/227.md +1824 -0
  112. package/docs//346/250/241/345/235/227/347/203/255/346/233/264/346/226/260.md +89 -0
  113. 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
  114. 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
  115. 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
  116. 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
  117. 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
  118. 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
  119. 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
  120. 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
  121. 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
  122. 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
  123. 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
  124. 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
  125. package/docs//350/277/234/347/250/213/346/250/241/345/235/227/350/256/276/350/256/241.md +451 -0
  126. package/docs//351/207/215/346/236/204/346/234/272/345/210/266/346/270/205/345/215/225.md +192 -0
  127. package/docs//351/223/276/350/267/257/350/277/275/350/270/252/346/226/271/346/241/210.md +242 -0
  128. 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
  129. package/extensions/agents/assistant/entry.py +113 -14
  130. package/extensions/agents/assistant/module.md +27 -22
  131. package/extensions/agents/assistant/server.py +308 -106
  132. package/extensions/channels/acp_channel/entry.py +114 -16
  133. package/extensions/channels/acp_channel/module.md +4 -0
  134. package/extensions/channels/acp_channel/server.py +412 -105
  135. package/extensions/channels/phone_channel/__init__.py +1 -0
  136. package/extensions/channels/phone_channel/entry.py +503 -0
  137. package/extensions/channels/phone_channel/module.md +31 -0
  138. package/extensions/channels/phone_channel/server.py +686 -0
  139. package/extensions/event_hub_bench/entry.py +55 -12
  140. package/extensions/event_hub_bench/module.md +27 -27
  141. package/extensions/services/audit/README.md +134 -0
  142. package/extensions/services/audit/collector.py +73 -0
  143. package/extensions/services/audit/entry.py +444 -0
  144. package/extensions/services/audit/module.md +66 -0
  145. package/extensions/services/audit/query_audit.py +111 -0
  146. package/extensions/services/audit/routes/__init__.py +1 -0
  147. package/extensions/services/audit/routes/routes_audit.py +113 -0
  148. package/extensions/services/audit/schemas/__init__.py +5 -0
  149. package/extensions/services/audit/schemas/audit_event.py +92 -0
  150. package/extensions/services/audit/server.py +542 -0
  151. package/extensions/services/audit/storage.py +95 -0
  152. package/extensions/services/auth/entry.py +1054 -0
  153. package/extensions/services/auth/module.md +31 -0
  154. package/extensions/services/auth/token_store.py +185 -0
  155. package/extensions/services/auth/verifiers/evol_account.py +101 -0
  156. package/extensions/services/auth/verifiers/kite_token.py +38 -0
  157. package/extensions/services/auth/verifiers/pairing_code.py +71 -0
  158. package/extensions/services/backup/entry.py +505 -201
  159. package/extensions/services/backup/module.md +4 -2
  160. package/extensions/services/dataclaw/api/__init__.py +0 -0
  161. package/extensions/services/dataclaw/api/admin.py +367 -0
  162. package/extensions/services/dataclaw/api/copyright.py +175 -0
  163. package/extensions/services/dataclaw/api/credits.py +177 -0
  164. package/extensions/services/dataclaw/api/data.py +179 -0
  165. package/extensions/services/dataclaw/api/demands.py +269 -0
  166. package/extensions/services/dataclaw/api/feeds.py +262 -0
  167. package/extensions/services/dataclaw/api/identity.py +505 -0
  168. package/extensions/services/dataclaw/api/notifications.py +104 -0
  169. package/extensions/services/dataclaw/api/reviews.py +138 -0
  170. package/extensions/services/dataclaw/api/search.py +153 -0
  171. package/extensions/services/dataclaw/api/subscriptions.py +157 -0
  172. package/extensions/services/dataclaw/config.json5 +96 -0
  173. package/extensions/services/dataclaw/core/__init__.py +0 -0
  174. package/extensions/services/dataclaw/core/auth.py +95 -0
  175. package/extensions/services/dataclaw/core/config.py +50 -0
  176. package/extensions/services/dataclaw/core/database.py +70 -0
  177. package/extensions/services/dataclaw/entry.py +416 -0
  178. 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
  179. package/extensions/services/dataclaw/migrate.py +283 -0
  180. package/extensions/services/dataclaw/models/__init__.py +0 -0
  181. package/extensions/services/dataclaw/module.md +49 -0
  182. package/extensions/services/dataclaw/requirements.txt +18 -0
  183. package/extensions/services/dataclaw/server.py +759 -0
  184. package/extensions/services/dataclaw/services/__init__.py +0 -0
  185. package/extensions/services/dataclaw/services/agent_service.py +132 -0
  186. package/extensions/services/dataclaw/services/credit_service.py +235 -0
  187. package/extensions/services/dataclaw/services/email_service.py +140 -0
  188. package/extensions/services/dataclaw/services/feed_service.py +259 -0
  189. package/extensions/services/dataclaw/services/notification_service.py +209 -0
  190. package/extensions/services/dataclaw/services/oauth_service.py +275 -0
  191. package/extensions/services/dataclaw/services/pricing.py +102 -0
  192. package/extensions/services/dataclaw/services/quality.py +79 -0
  193. package/extensions/services/dataclaw/services/reputation.py +142 -0
  194. package/extensions/services/dataclaw/services/sms_service.py +174 -0
  195. package/extensions/services/dataclaw/static/css/common.css +853 -0
  196. package/extensions/services/dataclaw/static/css/themes/blue.css +42 -0
  197. package/extensions/services/dataclaw/static/css/themes/dark.css +42 -0
  198. package/extensions/services/dataclaw/static/css/themes/light.css +35 -0
  199. package/extensions/services/dataclaw/static/js/api.js +103 -0
  200. package/extensions/services/dataclaw/static/js/common.js +321 -0
  201. package/extensions/services/dataclaw/static/js/i18n.js +95 -0
  202. package/extensions/services/dataclaw/static/js/pages/admin.js +152 -0
  203. package/extensions/services/dataclaw/static/js/pages/dashboard.js +82 -0
  204. package/extensions/services/dataclaw/static/js/pages/feed-detail.js +180 -0
  205. package/extensions/services/dataclaw/static/js/pages/feed-manage.js +158 -0
  206. package/extensions/services/dataclaw/static/js/theme.js +46 -0
  207. package/extensions/services/dataclaw/static/locales/en-US.json +464 -0
  208. package/extensions/services/dataclaw/static/locales/ja-JP.json +464 -0
  209. package/extensions/services/dataclaw/static/locales/zh-CN.json +464 -0
  210. package/extensions/services/dataclaw/templates/admin/index.html +90 -0
  211. package/extensions/services/dataclaw/templates/base.html +136 -0
  212. package/extensions/services/dataclaw/templates/credits/balance.html +106 -0
  213. package/extensions/services/dataclaw/templates/credits/deposit.html +164 -0
  214. package/extensions/services/dataclaw/templates/credits/history.html +90 -0
  215. package/extensions/services/dataclaw/templates/dashboard.html +52 -0
  216. package/extensions/services/dataclaw/templates/demands/create.html +78 -0
  217. package/extensions/services/dataclaw/templates/demands/detail.html +136 -0
  218. package/extensions/services/dataclaw/templates/demands/list.html +94 -0
  219. package/extensions/services/dataclaw/templates/feeds/create.html +95 -0
  220. package/extensions/services/dataclaw/templates/feeds/detail.html +110 -0
  221. package/extensions/services/dataclaw/templates/feeds/list.html +110 -0
  222. package/extensions/services/dataclaw/templates/feeds/manage.html +88 -0
  223. package/extensions/services/dataclaw/templates/index.html +185 -0
  224. package/extensions/services/dataclaw/templates/login.html +246 -0
  225. package/extensions/services/dataclaw/templates/register.html +164 -0
  226. package/extensions/services/dataclaw/templates/settings/notifications.html +96 -0
  227. package/extensions/services/dataclaw/templates/settings/profile.html +167 -0
  228. package/extensions/services/dataclaw/templates/subscriptions/list.html +64 -0
  229. package/extensions/services/dataclaw/tests/__init__.py +0 -0
  230. package/extensions/services/dataclaw/tests/conftest.py +68 -0
  231. package/extensions/services/dataclaw/tests/integration/__init__.py +0 -0
  232. package/extensions/services/dataclaw/tests/integration/test_workflows.py +239 -0
  233. package/extensions/services/dataclaw/tests/unit/__init__.py +0 -0
  234. package/extensions/services/dataclaw/tests/unit/test_admin.py +70 -0
  235. package/extensions/services/dataclaw/tests/unit/test_copyright.py +63 -0
  236. package/extensions/services/dataclaw/tests/unit/test_credits.py +80 -0
  237. package/extensions/services/dataclaw/tests/unit/test_data.py +98 -0
  238. package/extensions/services/dataclaw/tests/unit/test_demands.py +106 -0
  239. package/extensions/services/dataclaw/tests/unit/test_feeds.py +98 -0
  240. package/extensions/services/dataclaw/tests/unit/test_identity.py +88 -0
  241. package/extensions/services/dataclaw/tests/unit/test_notifications.py +36 -0
  242. package/extensions/services/dataclaw/tests/unit/test_reviews.py +68 -0
  243. package/extensions/services/dataclaw/tests/unit/test_search.py +64 -0
  244. package/extensions/services/dataclaw/tests/unit/test_subscriptions.py +65 -0
  245. package/extensions/services/dataclaw/tests/unit/test_system.py +106 -0
  246. package/extensions/services/dataclaw/utils/__init__.py +0 -0
  247. package/extensions/services/dataclaw/utils/crypto.py +38 -0
  248. package/extensions/services/dataclaw/utils/id_generator.py +52 -0
  249. package/extensions/services/dataclaw/ws/__init__.py +0 -0
  250. package/extensions/services/dataclaw/ws/handler.py +163 -0
  251. 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
  252. 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
  253. package/extensions/services/evol/__init__.py +1 -0
  254. package/extensions/services/evol/async_http.py +551 -0
  255. package/extensions/services/evol/auth_manager.py +602 -0
  256. package/extensions/services/evol/config.json5 +16 -0
  257. package/extensions/services/evol/config_loader.py +117 -0
  258. package/extensions/services/evol/entry.py +568 -0
  259. package/extensions/services/evol/evol_api.py +969 -0
  260. package/extensions/services/evol/evol_config.json5 +29 -0
  261. package/extensions/services/evol/mfa_totp.py +77 -0
  262. package/extensions/services/evol/migrate_tokens.py +122 -0
  263. package/extensions/services/evol/module.md +150 -0
  264. package/extensions/services/evol/nonce_pool.py +113 -0
  265. package/extensions/services/evol/oauth_manager.py +223 -0
  266. package/extensions/services/evol/pairing.py +251 -0
  267. package/extensions/services/evol/pairing_codes.jsonl +2 -0
  268. package/extensions/services/evol/relay.py +1031 -0
  269. package/extensions/services/evol/relay_config.json5 +85 -0
  270. package/extensions/services/evol/routes/__init__.py +1 -0
  271. package/extensions/services/evol/routes/routes_llm.py +231 -0
  272. package/extensions/services/evol/routes/routes_rpc.py +90 -0
  273. package/extensions/services/evol/routes/routes_test.py +68 -0
  274. package/extensions/services/evol/server.py +2426 -0
  275. package/extensions/services/evol/static/assets/CommissionView-Cs_ys6Gm.js +1 -0
  276. package/extensions/services/evol/static/assets/CommissionView-DACet_Oo.css +1 -0
  277. package/extensions/services/evol/static/assets/IframePage-DbO11U9G.js +1 -0
  278. package/extensions/services/evol/static/assets/IframePage-c572lT8i.css +1 -0
  279. package/extensions/services/evol/static/assets/TeamDetailView-DULrGD7k.css +1 -0
  280. package/extensions/services/evol/static/assets/TeamDetailView-gy_MBEqG.js +139 -0
  281. package/extensions/services/evol/static/assets/element-plus-Bd7pZkkM.js +63 -0
  282. package/extensions/services/evol/static/assets/index-CmMONKzG.css +1 -0
  283. package/extensions/services/evol/static/assets/index-D44bBe__.js +2 -0
  284. package/extensions/services/evol/static/assets/vue-vendor-DtF-__I4.js +29 -0
  285. package/extensions/services/evol/static/index.html +16 -0
  286. package/extensions/services/evol/static/logo.png +0 -0
  287. package/extensions/services/evol/stats_manager.py +243 -0
  288. package/extensions/services/evol/web/README.md +89 -0
  289. package/extensions/services/evol/web/build.bat +44 -0
  290. package/extensions/services/evol/web/index.html +13 -0
  291. package/extensions/services/evol/web/package-lock.json +1718 -0
  292. package/extensions/services/evol/web/package.json +26 -0
  293. package/extensions/services/evol/web/public/logo.png +0 -0
  294. package/extensions/services/evol/web/src/App.vue +7 -0
  295. package/extensions/services/evol/web/src/components/layout/AppHeader.vue +202 -0
  296. package/extensions/services/evol/web/src/components/layout/AppLayout.vue +61 -0
  297. package/extensions/services/evol/web/src/components/layout/AppSidebar.vue +115 -0
  298. package/extensions/services/evol/web/src/components/login/LoginPage.vue +271 -0
  299. package/extensions/services/evol/web/src/components/team/AddMemberModal.vue +181 -0
  300. package/extensions/services/evol/web/src/components/team/GroupTreeNode.vue +156 -0
  301. package/extensions/services/evol/web/src/components/team/TeamAlertConfig.vue +221 -0
  302. package/extensions/services/evol/web/src/components/team/TeamBillModal.vue +165 -0
  303. package/extensions/services/evol/web/src/components/team/TeamMembersAndGroups.vue +499 -0
  304. package/extensions/services/evol/web/src/components/team/TeamStatsPanel.vue +907 -0
  305. package/extensions/services/evol/web/src/components/team/TreeNode.vue +331 -0
  306. package/extensions/services/evol/web/src/components/team/stats/StatsExportProgress.vue +44 -0
  307. package/extensions/services/evol/web/src/components/team/stats/StatsHeader.vue +89 -0
  308. package/extensions/services/evol/web/src/components/team/stats/StatsMemberDetail.vue +415 -0
  309. package/extensions/services/evol/web/src/components/team/stats/StatsSummary.vue +42 -0
  310. package/extensions/services/evol/web/src/components/team/stats/helpers.ts +195 -0
  311. package/extensions/services/evol/web/src/components/team/stats/stats.css +741 -0
  312. package/extensions/services/evol/web/src/components/team/stats/useStatsApi.ts +114 -0
  313. package/extensions/services/evol/web/src/components/team/stats/useStatsCharts.ts +242 -0
  314. package/extensions/services/evol/web/src/components/team/stats/useStatsExport.ts +232 -0
  315. package/extensions/services/evol/web/src/composables/useFormatters.ts +42 -0
  316. package/extensions/services/evol/web/src/composables/useTheme.ts +52 -0
  317. package/extensions/services/evol/web/src/env.d.ts +7 -0
  318. package/extensions/services/evol/web/src/i18n/en.ts +361 -0
  319. package/extensions/services/evol/web/src/i18n/index.ts +36 -0
  320. package/extensions/services/evol/web/src/i18n/zh.ts +379 -0
  321. package/extensions/services/evol/web/src/main.ts +21 -0
  322. package/extensions/services/evol/web/src/router/index.ts +81 -0
  323. package/extensions/services/evol/web/src/services/kernel-client.ts +406 -0
  324. package/extensions/services/evol/web/src/stores/auth.ts +189 -0
  325. package/extensions/services/evol/web/src/stores/connection.ts +134 -0
  326. package/extensions/services/evol/web/src/stores/pages.ts +79 -0
  327. package/extensions/services/evol/web/src/styles/base.css +213 -0
  328. package/extensions/services/evol/web/src/styles/variables.css +138 -0
  329. package/extensions/services/evol/web/src/types/rpc.ts +35 -0
  330. package/extensions/services/evol/web/src/types/token.ts +87 -0
  331. package/extensions/services/evol/web/src/views/AccountView.vue +1532 -0
  332. package/extensions/services/evol/web/src/views/AiServiceView.vue +219 -0
  333. package/extensions/services/evol/web/src/views/CommissionView.vue +1220 -0
  334. package/extensions/services/evol/web/src/views/CreditsView.vue +131 -0
  335. package/extensions/services/evol/web/src/views/EndpointView.vue +163 -0
  336. package/extensions/services/evol/web/src/views/IframePage.vue +120 -0
  337. package/extensions/services/evol/web/src/views/TeamDetailView.vue +473 -0
  338. package/extensions/services/evol/web/src/views/TeamView.vue +332 -0
  339. package/extensions/services/evol/web/tsconfig.json +31 -0
  340. package/extensions/services/evol/web/tsconfig.node.json +10 -0
  341. package/extensions/services/evol/web/vite.config.ts +49 -0
  342. package/extensions/services/evolmem/__init__.py +0 -0
  343. package/extensions/services/evolmem/entry.py +387 -0
  344. package/extensions/services/evolmem/hooks/__init__.py +0 -0
  345. package/extensions/services/evolmem/hooks/assistant_stop.py +228 -0
  346. package/extensions/services/evolmem/hooks/common.py +76 -0
  347. package/extensions/services/evolmem/hooks/pre_tool_use.py +56 -0
  348. package/extensions/services/evolmem/hooks/session_end.py +133 -0
  349. package/extensions/services/evolmem/hooks/session_start.py +229 -0
  350. package/extensions/services/evolmem/hooks/user_prompt.py +122 -0
  351. package/extensions/services/evolmem/module.md +48 -0
  352. package/extensions/services/evolmem/prompts/00-server-info.md +28 -0
  353. package/extensions/services/evolmem/prompts/01-behavior.md +46 -0
  354. package/extensions/services/evolmem/prompts/02-summary-format.md +112 -0
  355. package/extensions/services/evolmem/prompts/03-file-query.md +92 -0
  356. package/extensions/services/evolmem/prompts/04-topic-stats.md +11 -0
  357. package/extensions/services/evolmem/prompts/05-recent-topics.md +84 -0
  358. package/extensions/services/evolmem/scripts/__init__.py +0 -0
  359. package/extensions/services/evolmem/scripts/extract_keywords.py +40 -0
  360. package/extensions/services/evolmem/scripts/search_topics.py +91 -0
  361. package/extensions/services/evolmem/server.py +641 -0
  362. package/extensions/services/gateway/entry.py +964 -0
  363. package/extensions/services/gateway/module.md +29 -0
  364. package/extensions/services/gateway/nonce_pool.py +65 -0
  365. package/extensions/services/gateway/relay.py +133 -0
  366. package/extensions/services/gateway/ws_server.py +285 -0
  367. package/extensions/services/kite_console/auth_manager.py +603 -0
  368. package/extensions/services/kite_console/config.json5 +19 -0
  369. package/extensions/services/kite_console/config_loader.py +117 -0
  370. package/extensions/services/kite_console/entry.py +528 -0
  371. package/extensions/services/kite_console/evol_api.py +179 -0
  372. package/extensions/services/kite_console/evol_config.json5 +29 -0
  373. package/extensions/services/kite_console/mfa_totp.py +77 -0
  374. package/extensions/services/kite_console/migrate_tokens.py +122 -0
  375. package/extensions/services/kite_console/module.md +37 -0
  376. package/extensions/services/kite_console/nonce_pool.py +113 -0
  377. package/extensions/services/kite_console/oauth_manager.py +223 -0
  378. package/extensions/services/kite_console/pairing.py +280 -0
  379. package/extensions/services/kite_console/pairing_codes.jsonl +2 -0
  380. package/extensions/services/kite_console/relay.py +1350 -0
  381. package/extensions/services/kite_console/relay_config.json5 +96 -0
  382. package/extensions/services/kite_console/routes/__init__.py +1 -0
  383. package/extensions/services/kite_console/routes/routes_llm.py +231 -0
  384. package/extensions/services/kite_console/routes/routes_proxy.py +115 -0
  385. package/extensions/services/kite_console/routes/routes_rpc.py +89 -0
  386. package/extensions/services/kite_console/routes/routes_test.py +68 -0
  387. package/extensions/services/kite_console/server.py +1742 -0
  388. package/extensions/services/kite_console/static/css/style.css +1854 -0
  389. package/extensions/services/kite_console/static/index.html +1524 -0
  390. package/extensions/services/kite_console/static/js/dialog.js +292 -0
  391. package/extensions/services/kite_console/static/js/evol-app.js +7740 -0
  392. package/extensions/services/kite_console/static/js/evol-app.js.backup +2777 -0
  393. package/extensions/services/kite_console/static/js/kernel-client.js +560 -0
  394. package/extensions/services/kite_console/static/js/kernel-client.js.backup +434 -0
  395. package/extensions/services/kite_console/static/js/registry-tests.js +592 -0
  396. package/extensions/services/kite_console/static/js/tests/ARCHITECTURE.md +67 -0
  397. package/extensions/services/kite_console/static/js/tests/README.md +140 -0
  398. package/extensions/services/kite_console/static/js/tests/index.js +161 -0
  399. package/extensions/services/kite_console/static/js/tests/integration/auth.js +120 -0
  400. package/extensions/services/kite_console/static/js/tests/integration/channel-interaction.js +188 -0
  401. package/extensions/services/kite_console/static/js/tests/integration/elastic-connection.js +115 -0
  402. package/extensions/services/kite_console/static/js/tests/integration/full-workflow.js +43 -0
  403. package/extensions/services/kite_console/static/js/tests/integration/multi-instance.js +304 -0
  404. package/extensions/services/kite_console/static/js/tests/integration/nested-rpc.js +266 -0
  405. package/extensions/services/kite_console/static/js/tests/integration/pingpong.js +25 -0
  406. package/extensions/services/kite_console/static/js/tests/integration/redis.js +227 -0
  407. package/extensions/services/kite_console/static/js/tests/integration/registry-core.js +52 -0
  408. package/extensions/services/kite_console/static/js/tests/integration/remote-deploy.js +85 -0
  409. package/extensions/services/kite_console/static/js/tests/integration/require-init.js +96 -0
  410. package/extensions/services/kite_console/static/js/tests/integration/scaling-control.js +193 -0
  411. package/extensions/services/kite_console/static/js/tests/integration/trace.js +109 -0
  412. package/extensions/services/kite_console/static/js/tests/modules/acp_channel.js +339 -0
  413. package/extensions/services/kite_console/static/js/tests/modules/auth.js +96 -0
  414. package/extensions/services/kite_console/static/js/tests/modules/backup.js +49 -0
  415. package/extensions/services/kite_console/static/js/tests/modules/gateway.js +41 -0
  416. package/extensions/services/kite_console/static/js/tests/modules/kernel.js +90 -0
  417. package/extensions/services/kite_console/static/js/tests/modules/launcher.js +75 -0
  418. package/extensions/services/kite_console/static/js/tests/modules/multi_instance.js +129 -0
  419. package/extensions/services/kite_console/static/js/tests/modules/phone_channel.js +364 -0
  420. package/extensions/services/kite_console/static/js/tests/modules/redis.js +178 -0
  421. package/extensions/services/kite_console/static/js/tests/modules/watchdog.js +60 -0
  422. package/extensions/services/kite_console/static/js/tests/modules/web.js +70 -0
  423. package/extensions/services/kite_console/static/js/tests/test-runner.js +123 -0
  424. package/extensions/services/kite_console/static/js/virtual-list.js +200 -0
  425. package/extensions/services/kite_console/static/pairing.html +248 -0
  426. package/extensions/services/kite_console/static/test_kernel_client_token.html +352 -0
  427. package/extensions/services/kite_console/static/test_registry.html +262 -0
  428. package/extensions/services/kite_console/static/test_relay.html +462 -0
  429. package/extensions/services/kite_console/stats_manager.py +247 -0
  430. package/extensions/services/logs/README.md +215 -0
  431. package/extensions/services/logs/api_logger.py +37 -0
  432. package/extensions/services/logs/baseline.py +121 -0
  433. package/extensions/services/logs/cleaner.py +76 -0
  434. package/extensions/services/logs/entry.py +449 -0
  435. package/extensions/services/logs/formatter.py +129 -0
  436. package/extensions/services/logs/module.md +38 -0
  437. package/extensions/services/logs/quick_diagnostic.py +128 -0
  438. package/extensions/services/logs/routes/__init__.py +1 -0
  439. package/extensions/services/logs/routes/routes_logs.py +218 -0
  440. package/extensions/services/logs/routes/routes_logs.py.backup +173 -0
  441. package/extensions/services/logs/scanner.py +100 -0
  442. package/extensions/services/logs/searcher.py +263 -0
  443. package/extensions/services/logs/server.py +553 -0
  444. package/extensions/services/logs.zip +0 -0
  445. package/extensions/services/model_service/config.json5 +30 -0
  446. package/extensions/services/model_service/entry.py +633 -162
  447. package/extensions/services/model_service/module.md +11 -2
  448. package/extensions/services/proxy/.claude/settings.local.json +13 -0
  449. package/extensions/services/proxy/__init__.py +0 -0
  450. package/extensions/services/proxy/agentcp/LICENCE +178 -0
  451. package/extensions/services/proxy/agentcp/README copy.md +85 -0
  452. package/extensions/services/proxy/agentcp/README.md +260 -0
  453. package/extensions/services/proxy/agentcp/__init__.py +16 -0
  454. package/extensions/services/proxy/agentcp/agent.py +4 -0
  455. package/extensions/services/proxy/agentcp/agentcp.py +2494 -0
  456. package/extensions/services/proxy/agentcp/agentprofile.json +89 -0
  457. package/extensions/services/proxy/agentcp/ap/__init__.py +16 -0
  458. package/extensions/services/proxy/agentcp/ap/ap_client.py +316 -0
  459. package/extensions/services/proxy/agentcp/assets/images/wechat_qr.png +0 -0
  460. package/extensions/services/proxy/agentcp/backup/metrics.json +31 -0
  461. package/extensions/services/proxy/agentcp/base/__init__.py +20 -0
  462. package/extensions/services/proxy/agentcp/base/auth_client.py +257 -0
  463. package/extensions/services/proxy/agentcp/base/client.py +112 -0
  464. package/extensions/services/proxy/agentcp/base/env.py +34 -0
  465. package/extensions/services/proxy/agentcp/base/html_util.py +336 -0
  466. package/extensions/services/proxy/agentcp/base/log.py +98 -0
  467. package/extensions/services/proxy/agentcp/ca/__init__.py +17 -0
  468. package/extensions/services/proxy/agentcp/ca/ca_client.py +414 -0
  469. package/extensions/services/proxy/agentcp/ca/ca_root.py +74 -0
  470. package/extensions/services/proxy/agentcp/context/__init__.py +20 -0
  471. package/extensions/services/proxy/agentcp/context/context.py +73 -0
  472. package/extensions/services/proxy/agentcp/context/exceptions.py +114 -0
  473. package/extensions/services/proxy/agentcp/create_profile.py +125 -0
  474. package/extensions/services/proxy/agentcp/create_profile_weather.py +125 -0
  475. package/extensions/services/proxy/agentcp/db/__init__.py +15 -0
  476. package/extensions/services/proxy/agentcp/db/db_mananger.py +550 -0
  477. package/extensions/services/proxy/agentcp/docs/UDP_HEARTBEAT_FIX_REPORT.md +265 -0
  478. package/extensions/services/proxy/agentcp/docs/heartbeat_issue_analysis.md +291 -0
  479. package/extensions/services/proxy/agentcp/file/__init__.py +16 -0
  480. package/extensions/services/proxy/agentcp/file/file_client.py +141 -0
  481. package/extensions/services/proxy/agentcp/file/wss_binary_message.py +137 -0
  482. package/extensions/services/proxy/agentcp/hcp.py +299 -0
  483. package/extensions/services/proxy/agentcp/heartbeat/__init__.py +16 -0
  484. package/extensions/services/proxy/agentcp/heartbeat/heartbeat_client.py +360 -0
  485. package/extensions/services/proxy/agentcp/improved_scheduler.py +498 -0
  486. package/extensions/services/proxy/agentcp/llm_agent_utils.py +249 -0
  487. package/extensions/services/proxy/agentcp/llm_server.py +172 -0
  488. package/extensions/services/proxy/agentcp/mermaid.py +210 -0
  489. package/extensions/services/proxy/agentcp/message.py +149 -0
  490. package/extensions/services/proxy/agentcp/metrics.py +256 -0
  491. package/extensions/services/proxy/agentcp/monitoring/__init__.py +20 -0
  492. package/extensions/services/proxy/agentcp/monitoring/global_monitor.py +27 -0
  493. package/extensions/services/proxy/agentcp/monitoring/metrics_store.py +325 -0
  494. package/extensions/services/proxy/agentcp/monitoring/monitoring_service.py +269 -0
  495. package/extensions/services/proxy/agentcp/monitoring/sliding_window.py +222 -0
  496. package/extensions/services/proxy/agentcp/monitoring/standalone_reader.py +224 -0
  497. package/extensions/services/proxy/agentcp/msg/__init__.py +21 -0
  498. package/extensions/services/proxy/agentcp/msg/connection_manager.py +456 -0
  499. package/extensions/services/proxy/agentcp/msg/message_client.py +2058 -0
  500. package/extensions/services/proxy/agentcp/msg/message_serialize.py +263 -0
  501. package/extensions/services/proxy/agentcp/msg/open_ai_message.py +88 -0
  502. package/extensions/services/proxy/agentcp/msg/session_manager.py +1062 -0
  503. package/extensions/services/proxy/agentcp/msg/stream_client.py +267 -0
  504. package/extensions/services/proxy/agentcp/msg/websocket_file_receiver.py +89 -0
  505. package/extensions/services/proxy/agentcp/msg/ws_logger.py +685 -0
  506. package/extensions/services/proxy/agentcp/msg/wss_binary_message.py +137 -0
  507. package/extensions/services/proxy/agentcp/requirements.txt +7 -0
  508. package/extensions/services/proxy/agentcp/samples/agent_graph/README.md +37 -0
  509. package/extensions/services/proxy/agentcp/samples/agent_graph/agentprofile.json +89 -0
  510. package/extensions/services/proxy/agentcp/samples/agent_graph/create_profile.py +138 -0
  511. package/extensions/services/proxy/agentcp/samples/agent_graph/main.py +164 -0
  512. package/extensions/services/proxy/agentcp/samples/agent_use/create_profile.py +123 -0
  513. package/extensions/services/proxy/agentcp/samples/agent_use/llm/create_profile.py +129 -0
  514. package/extensions/services/proxy/agentcp/samples/agent_use/llm/env.json +5 -0
  515. package/extensions/services/proxy/agentcp/samples/agent_use/llm/main.py +146 -0
  516. package/extensions/services/proxy/agentcp/samples/agent_use/main.py +123 -0
  517. package/extensions/services/proxy/agentcp/samples/agent_use/readme.md +379 -0
  518. package/extensions/services/proxy/agentcp/samples/agent_use/search/create_profile.py +129 -0
  519. package/extensions/services/proxy/agentcp/samples/agent_use/search/main.py +28 -0
  520. package/extensions/services/proxy/agentcp/samples/agent_use/tool/create_profile.py +129 -0
  521. package/extensions/services/proxy/agentcp/samples/agent_use/tool/main.py +20 -0
  522. package/extensions/services/proxy/agentcp/samples/ali_amap/README.md +97 -0
  523. package/extensions/services/proxy/agentcp/samples/ali_amap/amap_agent.py +88 -0
  524. package/extensions/services/proxy/agentcp/samples/ali_amap/create_profile.py +125 -0
  525. package/extensions/services/proxy/agentcp/samples/compute_agent/agent/powershell.py +228 -0
  526. package/extensions/services/proxy/agentcp/samples/compute_agent/agent/software.py +63 -0
  527. package/extensions/services/proxy/agentcp/samples/compute_agent/agent/tools.py +36 -0
  528. package/extensions/services/proxy/agentcp/samples/compute_agent/browser_user.py +41 -0
  529. package/extensions/services/proxy/agentcp/samples/deepseek/README.md +79 -0
  530. package/extensions/services/proxy/agentcp/samples/deepseek/create_profile.py +126 -0
  531. package/extensions/services/proxy/agentcp/samples/deepseek/deepseek.py +42 -0
  532. package/extensions/services/proxy/agentcp/samples/dify_chat/README.md +78 -0
  533. package/extensions/services/proxy/agentcp/samples/dify_chat/create_profile.py +126 -0
  534. package/extensions/services/proxy/agentcp/samples/dify_chat/dify_chat.py +47 -0
  535. package/extensions/services/proxy/agentcp/samples/dify_workflow/README.md +78 -0
  536. package/extensions/services/proxy/agentcp/samples/dify_workflow/create_profile.py +126 -0
  537. package/extensions/services/proxy/agentcp/samples/dify_workflow/dify_workflow.py +46 -0
  538. package/extensions/services/proxy/agentcp/samples/executor/README.md +44 -0
  539. package/extensions/services/proxy/agentcp/samples/executor/agentprofile.json +89 -0
  540. package/extensions/services/proxy/agentcp/samples/executor/create_profile.py +139 -0
  541. package/extensions/services/proxy/agentcp/samples/executor/main.py +160 -0
  542. package/extensions/services/proxy/agentcp/samples/filereader/README.md +45 -0
  543. package/extensions/services/proxy/agentcp/samples/filereader/agentprofile.json +90 -0
  544. package/extensions/services/proxy/agentcp/samples/filereader/create_profile.py +137 -0
  545. package/extensions/services/proxy/agentcp/samples/filereader/main.py +253 -0
  546. package/extensions/services/proxy/agentcp/samples/filewriter/README.md +38 -0
  547. package/extensions/services/proxy/agentcp/samples/filewriter/agentprofile.json +91 -0
  548. package/extensions/services/proxy/agentcp/samples/filewriter/create_profile.py +138 -0
  549. package/extensions/services/proxy/agentcp/samples/filewriter/main.py +289 -0
  550. package/extensions/services/proxy/agentcp/samples/hcp/README.md +85 -0
  551. package/extensions/services/proxy/agentcp/samples/hcp/acp_weather_agent.zip +0 -0
  552. package/extensions/services/proxy/agentcp/samples/hcp/create_profile.py +125 -0
  553. package/extensions/services/proxy/agentcp/samples/hcp/hcp.py +237 -0
  554. package/extensions/services/proxy/agentcp/samples/helloworld/README.md +68 -0
  555. package/extensions/services/proxy/agentcp/samples/helloworld/hello_world.py +40 -0
  556. package/extensions/services/proxy/agentcp/samples/llm_agent/MEADME.md +117 -0
  557. package/extensions/services/proxy/agentcp/samples/llm_agent/create_profile.py +125 -0
  558. package/extensions/services/proxy/agentcp/samples/llm_agent/qwen_agent.py +136 -0
  559. package/extensions/services/proxy/agentcp/samples/local_llm_agent/README.md +90 -0
  560. package/extensions/services/proxy/agentcp/samples/local_llm_agent/create_profile.py +125 -0
  561. package/extensions/services/proxy/agentcp/samples/local_llm_agent/main.py +49 -0
  562. package/extensions/services/proxy/agentcp/samples/query_llm_from_agent/README.md +55 -0
  563. package/extensions/services/proxy/agentcp/samples/query_llm_from_agent/create_profile.py +125 -0
  564. package/extensions/services/proxy/agentcp/samples/query_llm_from_agent/main.py +23 -0
  565. package/extensions/services/proxy/agentcp/samples/query_weather_api_agent/README.md +103 -0
  566. package/extensions/services/proxy/agentcp/samples/query_weather_api_agent/create_profile.py +125 -0
  567. package/extensions/services/proxy/agentcp/samples/query_weather_api_agent/main.py +69 -0
  568. package/extensions/services/proxy/agentcp/samples/query_weather_from_agent/README.md +58 -0
  569. package/extensions/services/proxy/agentcp/samples/query_weather_from_agent/create_profile.py +125 -0
  570. package/extensions/services/proxy/agentcp/samples/query_weather_from_agent/main.py +25 -0
  571. package/extensions/services/proxy/agentcp/samples/qwen3/README.md +71 -0
  572. package/extensions/services/proxy/agentcp/samples/qwen3/create_profile.py +126 -0
  573. package/extensions/services/proxy/agentcp/samples/qwen3/qwen3.py +37 -0
  574. package/extensions/services/proxy/agentcp/samples/qwen3_tools/README.md +133 -0
  575. package/extensions/services/proxy/agentcp/samples/qwen3_tools/create_profile.py +126 -0
  576. package/extensions/services/proxy/agentcp/samples/qwen3_tools/qwen3_tools.py +98 -0
  577. package/extensions/services/proxy/agentcp/samples/search/create_profile_qwen.py +125 -0
  578. package/extensions/services/proxy/agentcp/samples/search/create_profile_search.py +125 -0
  579. package/extensions/services/proxy/agentcp/samples/search/qwen_agent.py +136 -0
  580. package/extensions/services/proxy/agentcp/samples/search/search_agent.py +170 -0
  581. package/extensions/services/proxy/agentcp/samples/wrapper_agently_to_agent/README.md +89 -0
  582. package/extensions/services/proxy/agentcp/samples/wrapper_agently_to_agent/create_profile.py +125 -0
  583. package/extensions/services/proxy/agentcp/samples/wrapper_agently_to_agent/main.py +44 -0
  584. package/extensions/services/proxy/agentcp/utils/__init__.py +15 -0
  585. package/extensions/services/proxy/agentcp/utils/file_util.py +117 -0
  586. package/extensions/services/proxy/agentcp/utils/proxy_bypass.py +99 -0
  587. package/extensions/services/proxy/agentcp/workflow.py +203 -0
  588. package/extensions/services/proxy/aid_manager.py +419 -0
  589. package/extensions/services/proxy/auth_bridge.py +182 -0
  590. package/extensions/services/proxy/config_store.py +79 -0
  591. package/extensions/services/proxy/entry.py +528 -0
  592. package/extensions/services/proxy/evol/__init__.py +1 -0
  593. package/extensions/services/proxy/evol/config.py +37 -0
  594. package/extensions/services/proxy/evol/http/__init__.py +1 -0
  595. package/extensions/services/proxy/evol/http/async_http.py +551 -0
  596. package/extensions/services/proxy/evol/log.py +28 -0
  597. package/extensions/services/proxy/evol/presenter/__init__.py +2 -0
  598. package/extensions/services/proxy/evol/presenter/agentIdPresenter.py +1031 -0
  599. package/extensions/services/proxy/evol/presenter/apikeyPresenter.py +96 -0
  600. package/extensions/services/proxy/evol/presenter/configPresenter.py +234 -0
  601. package/extensions/services/proxy/evol/presenter/userPresenter.py +71 -0
  602. package/extensions/services/proxy/evol/server/__init__.py +1 -0
  603. package/extensions/services/proxy/evol/server/claude_proxy_async.py +3434 -0
  604. package/extensions/services/proxy/evol/server/openclaw_proxy.py +1861 -0
  605. package/extensions/services/proxy/evol/server/proxy_config.py +15 -0
  606. package/extensions/services/proxy/evol/server/proxy_engine.py +501 -0
  607. package/extensions/services/proxy/evol/version.py +24 -0
  608. package/extensions/services/proxy/module.md +151 -0
  609. package/extensions/services/proxy/server.py +952 -0
  610. package/extensions/services/redis/ALIGNMENT_CHECKLIST.md +121 -0
  611. package/extensions/services/redis/ALIGNMENT_STATUS.md +548 -0
  612. package/extensions/services/redis/config.json5 +8 -0
  613. package/extensions/services/redis/entry.py +1509 -0
  614. package/extensions/services/redis/entry.py.backup +405 -0
  615. package/extensions/services/redis/module.md +48 -0
  616. package/extensions/services/redis/redis_builtin.py +332 -0
  617. package/extensions/services/redis/redis_external.py +164 -0
  618. package/extensions/services/testUi/entry.py +446 -0
  619. package/extensions/services/testUi/module.md +18 -0
  620. package/extensions/services/testUi/ui/cards.html +131 -0
  621. package/extensions/services/testUi/ui/index.html +22 -0
  622. package/extensions/services/testUi/ui/particles.html +143 -0
  623. package/extensions/services/watchdog/entry.py +1258 -767
  624. package/extensions/services/watchdog/module.md +3 -0
  625. package/extensions/services/watchdog/monitor.py +483 -75
  626. package/extensions/services/web/auth_manager.py +602 -0
  627. package/extensions/services/web/config.json5 +11 -0
  628. package/extensions/services/web/entry.py +598 -478
  629. package/extensions/services/web/mfa_totp.py +77 -0
  630. package/extensions/services/web/module.md +17 -14
  631. package/extensions/services/web/nonce_pool.py +113 -0
  632. package/extensions/services/web/oauth_manager.py +223 -0
  633. package/extensions/services/web/pairing.py +3 -2
  634. package/extensions/services/web/pairing_codes.jsonl +1 -0
  635. package/extensions/services/web/relay.py +442 -63
  636. package/extensions/services/web/relay_config.json5 +1 -2
  637. package/extensions/services/web/routes/routes_rpc.py +6 -6
  638. package/extensions/services/web/server.py +380 -181
  639. package/extensions/services/web/static/index.html +1752 -1738
  640. package/extensions/services/web/static/js/app.js +32 -0
  641. package/extensions/services/web/static/js/kernel-client.js +48 -9
  642. package/extensions/services/web/static/js/token-manager.js +10 -10
  643. package/extensions/services/web/vendor/bluetooth/audio.py +1 -1
  644. package/extensions/services/web/vendor/config.py +2 -2
  645. package/extensions/services/web/vendor/storage/identity.py +1 -1
  646. package/kernel/entry.py +77 -23
  647. package/kernel/event_hub.py +1122 -74
  648. package/kernel/module.md +26 -1
  649. package/kernel/registry_store.py +209 -36
  650. package/kernel/rpc_router.py +1400 -465
  651. package/kernel/server.py +1084 -108
  652. package/kite_cli/builders/__init__.py +4 -0
  653. package/kite_cli/builders/base.py +67 -0
  654. package/kite_cli/builders/custom.py +31 -0
  655. package/kite_cli/builders/detector.py +56 -0
  656. package/kite_cli/builders/go.py +34 -0
  657. package/kite_cli/builders/gradle.py +41 -0
  658. package/kite_cli/builders/maven.py +36 -0
  659. package/kite_cli/builders/npm.py +44 -0
  660. package/kite_cli/builders/python.py +37 -0
  661. package/kite_cli/commands/BUILD_GUIDE.md +109 -0
  662. package/kite_cli/commands/build.py +142 -0
  663. package/kite_cli/commands/check.py +60 -0
  664. package/kite_cli/commands/config.py +156 -0
  665. package/kite_cli/commands/deps.py +58 -0
  666. package/kite_cli/commands/deps_install.py +67 -0
  667. package/kite_cli/commands/disable.py +162 -0
  668. package/kite_cli/commands/enable.py +162 -0
  669. package/kite_cli/commands/env_check.py +45 -0
  670. package/kite_cli/commands/export.py +96 -0
  671. package/kite_cli/commands/import_cmd.py +110 -0
  672. package/kite_cli/commands/install.py +50 -23
  673. package/kite_cli/commands/install_skill.py +107 -0
  674. package/kite_cli/commands/list.py +128 -31
  675. package/kite_cli/commands/outdated.py +202 -0
  676. package/kite_cli/commands/prepare.py +49 -0
  677. package/kite_cli/commands/search.py +33 -17
  678. package/kite_cli/commands/update.py +115 -2
  679. package/kite_cli/commands/venv_setup.py +56 -0
  680. package/kite_cli/commands/why.py +48 -0
  681. package/kite_cli/core/config_manager.py +145 -0
  682. package/kite_cli/core/downloader.py +32 -2
  683. package/kite_cli/main.py +179 -5
  684. package/kite_cli/utils/colors.py +153 -0
  685. package/kite_cli/utils/dependency_graph.py +209 -0
  686. package/kite_cli/utils/process.py +55 -0
  687. package/kite_cli/utils/progress.py +207 -0
  688. package/kite_cli/utils/table.py +101 -0
  689. package/launcher/count_lines.py +192 -43
  690. package/launcher/entry.py +4543 -2517
  691. package/launcher/logging_setup.py +54 -1
  692. package/launcher/module.md +37 -2
  693. package/launcher/module_scanner.py +103 -20
  694. package/launcher/process_manager.py +355 -76
  695. package/main.py +10 -1
  696. package/package.json +11 -1
  697. package/python_version.json +4 -0
  698. package/requirements.txt +41 -0
  699. package/scripts/auto-fix-deps.py +128 -0
  700. package/scripts/env-manager.js +351 -0
  701. package/scripts/final-test.js +78 -0
  702. package/scripts/python-env.js +79 -0
  703. package/scripts/scan_dependencies.py +461 -0
  704. package/scripts/setup-python-env.js +700 -0
  705. package/scripts/test-alluser.js +48 -0
  706. package/scripts/test-different-version.js +86 -0
  707. package/scripts/test-direct.js +63 -0
  708. package/scripts/test-extract-installer.js +28 -0
  709. package/scripts/test-install-log.js +54 -0
  710. package/scripts/test-installer.js +39 -0
  711. package/scripts/test-integration.js +250 -0
  712. package/scripts/test-real-install.js +210 -0
  713. package/scripts/test-targetdir.js +49 -0
  714. package/scripts/test-venv-real.js +47 -0
  715. package/scripts/test-venv-simple.js +57 -0
  716. package/scripts/test-wait.js +49 -0
  717. package/scripts/test-with-log.js +63 -0
  718. package/extensions/services/web/config.yaml +0 -149
@@ -1,478 +1,598 @@
1
- """
2
- Web Management entry point.
3
- Reads boot_info from stdin, registers to Registry, starts web service.
4
- Serves the full AI Phone Agent web UI and all API endpoints.
5
- """
6
-
7
- import builtins
8
- import json
9
- import os
10
- import re
11
- import signal
12
- import socket
13
- import sys
14
- import threading
15
- import time
16
- import traceback
17
- import uuid
18
- from datetime import datetime, timezone
19
-
20
- import asyncio
21
- import websockets
22
- import uvicorn
23
-
24
-
25
- # ── Safe stdout/stderr: ignore BrokenPipeError after Launcher closes stdio ──
26
-
27
-
28
- # ── Module configuration ──
29
-
30
- def _load_module_config() -> dict:
31
- """Load module configuration from module.md frontmatter.
32
-
33
- Returns:
34
- Dict with keys: name, preferred_port, advertise_ip
35
-
36
- Raises:
37
- SystemExit: If module.md is invalid or name is non-compliant
38
- """
39
- _this_dir = os.path.dirname(os.path.abspath(__file__))
40
- module_md = os.path.join(_this_dir, "module.md")
41
-
42
- # Calculate relative path for error messages
43
- project_root = os.environ.get("KITE_PROJECT", "")
44
- if project_root and _this_dir.startswith(project_root):
45
- rel_path = os.path.relpath(_this_dir, project_root)
46
- else:
47
- rel_path = _this_dir
48
-
49
- # Default values (will be overridden if valid config exists)
50
- result = {
51
- "name": "",
52
- "preferred_port": 0,
53
- "advertise_ip": "0.0.0.0"
54
- }
55
-
56
- # Check if module.md exists
57
- if not os.path.exists(module_md):
58
- print(f"[{rel_path}] ERROR: Invalid module configuration in module.md")
59
- print(f" Path: {rel_path}/module.md")
60
- print(f" Reason: File not found")
61
- sys.exit(1)
62
-
63
- try:
64
- with open(module_md, encoding="utf-8") as f:
65
- text = f.read()
66
-
67
- # Extract YAML frontmatter (between --- markers)
68
- import re
69
- m = re.match(r'^---\s*\n(.*?)\n---', text, re.DOTALL)
70
- if not m:
71
- print(f"[{rel_path}] ERROR: Invalid module configuration in module.md")
72
- print(f" Path: {rel_path}/module.md")
73
- print(f" Reason: Missing YAML frontmatter")
74
- sys.exit(1)
75
-
76
- # Parse YAML frontmatter
77
- try:
78
- import yaml
79
- fm = yaml.safe_load(m.group(1)) or {}
80
- except ImportError:
81
- print(f"[{rel_path}] ERROR: PyYAML not installed, cannot parse module.md")
82
- sys.exit(1)
83
- except Exception as e:
84
- print(f"[{rel_path}] ERROR: Invalid module configuration in module.md")
85
- print(f" Path: {rel_path}/module.md")
86
- print(f" Reason: YAML parse error: {e}")
87
- sys.exit(1)
88
-
89
- # Validate 'name' field (required)
90
- if "name" not in fm:
91
- print(f"[{rel_path}] ERROR: Invalid module configuration in module.md")
92
- print(f" Path: {rel_path}/module.md")
93
- print(f" Reason: Missing 'name' field")
94
- sys.exit(1)
95
-
96
- raw_name = str(fm["name"]).strip()
97
-
98
- if not raw_name:
99
- print(f"[{rel_path}] ERROR: Invalid module configuration in module.md")
100
- print(f" Path: {rel_path}/module.md")
101
- print(f" Reason: Empty module name")
102
- sys.exit(1)
103
-
104
- # Validate name characters
105
- sanitized = re.sub(r'[^a-zA-Z0-9_\-]', '', raw_name)
106
-
107
- if sanitized != raw_name:
108
- invalid_chars = ''.join(sorted(set(c for c in raw_name if c not in sanitized)))
109
- print(f"[{rel_path}] ERROR: Invalid module configuration in module.md")
110
- print(f" Path: {rel_path}/module.md")
111
- print(f" Reason: Invalid characters in name '{raw_name}': {repr(invalid_chars)}")
112
- sys.exit(1)
113
-
114
- result["name"] = sanitized
115
-
116
- # Extract optional fields
117
- if "preferred_port" in fm:
118
- try:
119
- result["preferred_port"] = int(fm["preferred_port"])
120
- except (ValueError, TypeError):
121
- pass
122
-
123
- if "advertise_ip" in fm:
124
- result["advertise_ip"] = str(fm["advertise_ip"])
125
-
126
- except SystemExit:
127
- raise # Re-raise exit to prevent catching by outer except
128
- except Exception as e:
129
- print(f"[{rel_path}] ERROR: Failed to read module.md: {e}")
130
- sys.exit(1)
131
-
132
- return result
133
-
134
- _module_config = _load_module_config()
135
- MODULE_NAME = _module_config["name"]
136
-
137
-
138
- class _SafeWriter:
139
- """Wraps a stream to silently swallow BrokenPipeError on write/flush."""
140
- def __init__(self, stream):
141
- self._stream = stream
142
-
143
- def write(self, s):
144
- try:
145
- self._stream.write(s)
146
- except (BrokenPipeError, OSError):
147
- pass
148
-
149
- def flush(self):
150
- try:
151
- self._stream.flush()
152
- except (BrokenPipeError, OSError):
153
- pass
154
-
155
- def __getattr__(self, name):
156
- return getattr(self._stream, name)
157
-
158
- sys.stdout = _SafeWriter(sys.stdout)
159
- sys.stderr = _SafeWriter(sys.stderr)
160
-
161
-
162
- # ── Timestamped print + log file writer ──
163
- # Independent implementation per module (no shared code dependency)
164
-
165
- _builtin_print = builtins.print
166
- _start_ts = time.monotonic()
167
- _last_ts = time.monotonic()
168
- _ANSI_RE = re.compile(r"\033\[[0-9;]*m")
169
- _log_lock = threading.Lock()
170
- _log_latest_path = None
171
- _log_daily_path = None
172
- _log_daily_date = ""
173
- _log_dir = None
174
- _crash_log_path = None
175
-
176
- def _strip_ansi(s: str) -> str:
177
- return _ANSI_RE.sub("", s)
178
-
179
- def _resolve_daily_log_path():
180
- """Resolve daily log path based on current date."""
181
- global _log_daily_path, _log_daily_date
182
- if not _log_dir:
183
- return
184
- today = datetime.now().strftime("%Y-%m-%d")
185
- if today == _log_daily_date and _log_daily_path:
186
- return
187
- month_dir = os.path.join(_log_dir, today[:7])
188
- os.makedirs(month_dir, exist_ok=True)
189
- _log_daily_path = os.path.join(month_dir, f"{today}.log")
190
- _log_daily_date = today
191
-
192
- def _write_log(plain_line: str):
193
- """Write a plain-text line to both latest.log and daily log."""
194
- with _log_lock:
195
- if _log_latest_path:
196
- try:
197
- with open(_log_latest_path, "a", encoding="utf-8") as f:
198
- f.write(plain_line)
199
- except Exception:
200
- pass
201
- _resolve_daily_log_path()
202
- if _log_daily_path:
203
- try:
204
- with open(_log_daily_path, "a", encoding="utf-8") as f:
205
- f.write(plain_line)
206
- except Exception:
207
- pass
208
-
209
- def _write_crash(exc_type, exc_value, exc_tb, thread_name=None, severity="critical", handled=False):
210
- """Write crash record to crashes.jsonl + daily crash archive."""
211
- record = {
212
- "timestamp": datetime.now(timezone.utc).isoformat(),
213
- "module": MODULE_NAME,
214
- "thread": thread_name or threading.current_thread().name,
215
- "exception_type": exc_type.__name__ if exc_type else "Unknown",
216
- "exception_message": str(exc_value),
217
- "traceback": "".join(traceback.format_exception(exc_type, exc_value, exc_tb)),
218
- "severity": severity,
219
- "handled": handled,
220
- "process_id": os.getpid(),
221
- "platform": sys.platform,
222
- "runtime_version": f"Python {sys.version.split()[0]}",
223
- }
224
-
225
- if exc_tb:
226
- tb_entries = traceback.extract_tb(exc_tb)
227
- if tb_entries:
228
- last = tb_entries[-1]
229
- record["context"] = {
230
- "function": last.name,
231
- "file": os.path.basename(last.filename),
232
- "line": last.lineno,
233
- }
234
-
235
- line = json.dumps(record, ensure_ascii=False) + "\n"
236
-
237
- if _crash_log_path:
238
- try:
239
- with open(_crash_log_path, "a", encoding="utf-8") as f:
240
- f.write(line)
241
- except Exception:
242
- pass
243
-
244
- if _log_dir:
245
- try:
246
- today = datetime.now().strftime("%Y-%m-%d")
247
- archive_dir = os.path.join(_log_dir, "crashes", today[:7])
248
- os.makedirs(archive_dir, exist_ok=True)
249
- archive_path = os.path.join(archive_dir, f"{today}.jsonl")
250
- with open(archive_path, "a", encoding="utf-8") as f:
251
- f.write(line)
252
- except Exception:
253
- pass
254
-
255
- def _print_crash_summary(exc_type, exc_tb, thread_name=None):
256
- """Print crash summary to console (red highlight)."""
257
- RED = "\033[91m"
258
- RESET = "\033[0m"
259
-
260
- if exc_tb:
261
- tb_entries = traceback.extract_tb(exc_tb)
262
- if tb_entries:
263
- last = tb_entries[-1]
264
- location = f"{os.path.basename(last.filename)}:{last.lineno}"
265
- else:
266
- location = "unknown"
267
- else:
268
- location = "unknown"
269
-
270
- prefix = f"[{MODULE_NAME}]"
271
- if thread_name:
272
- _builtin_print(f"{prefix} {RED}线程 {thread_name} 崩溃: "
273
- f"{exc_type.__name__} in {location}{RESET}")
274
- else:
275
- _builtin_print(f"{prefix} {RED}崩溃: {exc_type.__name__} in {location}{RESET}")
276
- if _crash_log_path:
277
- _builtin_print(f"{prefix} 崩溃日志: {_crash_log_path}")
278
-
279
- def _setup_exception_hooks():
280
- """Set up global exception hooks."""
281
- _orig_excepthook = sys.excepthook
282
-
283
- def _excepthook(exc_type, exc_value, exc_tb):
284
- _write_crash(exc_type, exc_value, exc_tb, severity="critical", handled=False)
285
- _print_crash_summary(exc_type, exc_tb)
286
- _orig_excepthook(exc_type, exc_value, exc_tb)
287
-
288
- sys.excepthook = _excepthook
289
-
290
- if hasattr(threading, "excepthook"):
291
- def _thread_excepthook(args):
292
- _write_crash(args.exc_type, args.exc_value, args.exc_traceback,
293
- thread_name=args.thread.name if args.thread else "unknown",
294
- severity="error", handled=False)
295
- _print_crash_summary(args.exc_type, args.exc_traceback,
296
- thread_name=args.thread.name if args.thread else None)
297
-
298
- threading.excepthook = _thread_excepthook
299
-
300
- def _tprint(*args, **kwargs):
301
- """Timestamped print that adds [timestamp] HH:MM:SS.mmm +delta prefix."""
302
- global _last_ts
303
- now = time.monotonic()
304
- elapsed = now - _start_ts
305
- delta = now - _last_ts
306
- _last_ts = now
307
-
308
- if elapsed < 1:
309
- elapsed_str = f"{elapsed * 1000:.0f}ms"
310
- elif elapsed < 100:
311
- elapsed_str = f"{elapsed:.1f}s"
312
- else:
313
- elapsed_str = f"{elapsed:.0f}s"
314
-
315
- if delta < 0.001:
316
- delta_str = ""
317
- elif delta < 1:
318
- delta_str = f"+{delta * 1000:.0f}ms"
319
- elif delta < 100:
320
- delta_str = f"+{delta:.1f}s"
321
- else:
322
- delta_str = f"+{delta:.0f}s"
323
-
324
- ts = datetime.now().strftime("%H:%M:%S.%f")[:-3]
325
-
326
- _builtin_print(*args, **kwargs)
327
-
328
- if _log_latest_path or _log_daily_path:
329
- sep = kwargs.get("sep", " ")
330
- end = kwargs.get("end", "\n")
331
- text = sep.join(str(a) for a in args)
332
- prefix = f"[{elapsed_str:>6}] {ts} {delta_str:>8} "
333
- _write_log(prefix + _strip_ansi(text) + end)
334
-
335
- builtins.print = _tprint
336
-
337
- # Ensure project root (Kite/) is on sys.path
338
- _this_dir = os.path.dirname(os.path.abspath(__file__))
339
- _project_root = os.environ.get("KITE_PROJECT") or os.path.dirname(os.path.dirname(os.path.dirname(_this_dir)))
340
- if _project_root not in sys.path:
341
- sys.path.insert(0, _project_root)
342
-
343
- # Also add ai-phone-agent root so we can import config, storage, conversation, etc.
344
- _agent_root = os.path.dirname(_project_root)
345
- if _agent_root not in sys.path:
346
- sys.path.insert(0, _agent_root)
347
-
348
- from extensions.services.web.server import WebServer
349
-
350
-
351
- def _fmt_elapsed(t0: float) -> str:
352
- d = time.monotonic() - t0
353
- if d < 1:
354
- return f"{d * 1000:.0f}ms"
355
- if d < 10:
356
- return f"{d:.1f}s"
357
- return f"{d:.0f}s"
358
-
359
-
360
- def _bind_port(preferred: int, host: str, max_attempts: int = 10) -> int | None:
361
- """
362
- Try to bind to preferred port, then port+1, port+2, ... up to max_attempts.
363
- Returns bound port on success, None on failure.
364
- """
365
- if not preferred:
366
- # No preferred port, use OS-assigned
367
- with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
368
- s.bind((host, 0))
369
- return s.getsockname()[1]
370
-
371
- for attempt in range(max_attempts):
372
- port = preferred + attempt
373
- try:
374
- with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
375
- s.bind((host, port))
376
- if attempt > 0:
377
- print(f"[web] Bound to port {port} (preferred {preferred} was occupied)")
378
- return port
379
- except OSError:
380
- if attempt < max_attempts - 1:
381
- continue
382
- else:
383
- print(f"[web] ERROR: Failed to bind port after {max_attempts} attempts ({preferred}-{port})")
384
- return None
385
-
386
- return None
387
-
388
-
389
-
390
-
391
- def main():
392
- # Initialize log file paths
393
- global _log_dir, _log_latest_path, _crash_log_path
394
- module_data = os.environ.get("KITE_MODULE_DATA")
395
- if module_data:
396
- _log_dir = os.path.join(module_data, "log")
397
- os.makedirs(_log_dir, exist_ok=True)
398
- suffix = os.environ.get("KITE_INSTANCE_SUFFIX", "")
399
-
400
- _log_latest_path = os.path.join(_log_dir, f"latest{suffix}.log")
401
- try:
402
- with open(_log_latest_path, "w", encoding="utf-8") as f:
403
- pass
404
- except Exception:
405
- _log_latest_path = None
406
-
407
- _crash_log_path = os.path.join(_log_dir, f"crashes{suffix}.jsonl")
408
- try:
409
- with open(_crash_log_path, "w", encoding="utf-8") as f:
410
- pass
411
- except Exception:
412
- _crash_log_path = None
413
-
414
- _resolve_daily_log_path()
415
-
416
- _setup_exception_hooks()
417
-
418
- _t0 = time.monotonic()
419
-
420
- # Read boot_info from stdin (only token)
421
- token = ""
422
- try:
423
- line = sys.stdin.readline().strip()
424
- if line:
425
- boot_info = json.loads(line)
426
- token = boot_info.get("token", "")
427
- except Exception:
428
- pass
429
-
430
- # Read kernel_port from environment variable
431
- kernel_port = int(os.environ.get("KITE_KERNEL_PORT", "0"))
432
-
433
- if not token or not kernel_port:
434
- print("[web] ERROR: Missing token or KITE_KERNEL_PORT")
435
- sys.exit(1)
436
-
437
- print(f"[web] Token received ({len(token)} chars), kernel port: {kernel_port} ({_fmt_elapsed(_t0)})")
438
-
439
- # Use cached module config (already loaded at module level)
440
- host = _module_config["advertise_ip"]
441
- port = _bind_port(_module_config["preferred_port"], host)
442
-
443
- # If port binding failed after 10 attempts, exit gracefully
444
- if port is None:
445
- print("[web] ERROR: Cannot bind to any port, exiting")
446
- sys.exit(1)
447
-
448
- server = WebServer(
449
- token=token,
450
- kernel_port=kernel_port,
451
- host=host,
452
- port=port,
453
- boot_t0=_t0,
454
- )
455
-
456
- # Display access URL in green
457
- display_host = "localhost" if host == "0.0.0.0" else host
458
- url = f"http://{display_host}:{port}"
459
- print(f"[web] Starting on {host}:{port} ({_fmt_elapsed(_t0)})")
460
- print(f"[web] \033[32m✓ Web UI ready: {url}\033[0m")
461
-
462
- try:
463
- config = uvicorn.Config(server.app, host=host, port=port, log_level="warning")
464
- uvi_server = uvicorn.Server(config)
465
- server._uvicorn_server = uvi_server
466
- uvi_server.run()
467
- except Exception as e:
468
- _write_crash(type(e), e, e.__traceback__, severity="critical", handled=True)
469
- _print_crash_summary(type(e), e.__traceback__)
470
- sys.exit(1)
471
-
472
- # Check if server requested exit with non-zero code
473
- if server._exit_code != 0:
474
- sys.exit(server._exit_code)
475
-
476
-
477
- if __name__ == "__main__":
478
- main()
1
+ """
2
+ Web Management entry point.
3
+ Reads boot_info from stdin, registers to Registry, starts web service.
4
+ Serves the full AI Phone Agent web UI and all API endpoints.
5
+ """
6
+
7
+ import builtins
8
+ import json
9
+ import os
10
+ import re
11
+ import signal
12
+ import socket
13
+ import sys
14
+ import threading
15
+ import time
16
+ import traceback
17
+ import uuid
18
+ from datetime import datetime, timezone
19
+
20
+ import asyncio
21
+ import websockets
22
+ import uvicorn
23
+
24
+
25
+ # ── Safe stdout/stderr: ignore BrokenPipeError after Launcher closes stdio ──
26
+
27
+
28
+ # ── Module configuration ──
29
+
30
+ def _load_module_config() -> dict:
31
+ """Load module configuration from module.md frontmatter.
32
+
33
+ Returns:
34
+ Dict with keys: name, preferred_port, advertise_ip
35
+
36
+ Raises:
37
+ SystemExit: If module.md is invalid or name is non-compliant
38
+ """
39
+ _this_dir = os.path.dirname(os.path.abspath(__file__))
40
+ module_md = os.path.join(_this_dir, "module.md")
41
+
42
+ # Calculate relative path for error messages
43
+ project_root = os.environ.get("KITE_PROJECT", "")
44
+ if project_root and _this_dir.startswith(project_root):
45
+ rel_path = os.path.relpath(_this_dir, project_root)
46
+ else:
47
+ rel_path = _this_dir
48
+
49
+ # Default values (will be overridden if valid config exists)
50
+ result = {
51
+ "name": "",
52
+ "preferred_port": 0,
53
+ "advertise_ip": "0.0.0.0"
54
+ }
55
+
56
+ # Check if module.md exists
57
+ if not os.path.exists(module_md):
58
+ print(f"[{rel_path}] ERROR: Invalid module configuration in module.md")
59
+ print(f" Path: {rel_path}/module.md")
60
+ print(f" Reason: File not found")
61
+ sys.exit(1)
62
+
63
+ try:
64
+ with open(module_md, encoding="utf-8") as f:
65
+ text = f.read()
66
+
67
+ # Extract YAML frontmatter (between --- markers)
68
+ import re
69
+ m = re.match(r'^---\s*\n(.*?)\n---', text, re.DOTALL)
70
+ if not m:
71
+ print(f"[{rel_path}] ERROR: Invalid module configuration in module.md")
72
+ print(f" Path: {rel_path}/module.md")
73
+ print(f" Reason: Missing YAML frontmatter")
74
+ sys.exit(1)
75
+
76
+ # Parse YAML frontmatter
77
+ try:
78
+ import yaml
79
+ fm = yaml.safe_load(m.group(1)) or {}
80
+ except ImportError:
81
+ print(f"[{rel_path}] ERROR: PyYAML not installed, cannot parse module.md")
82
+ sys.exit(1)
83
+ except Exception as e:
84
+ print(f"[{rel_path}] ERROR: Invalid module configuration in module.md")
85
+ print(f" Path: {rel_path}/module.md")
86
+ print(f" Reason: YAML parse error: {e}")
87
+ sys.exit(1)
88
+
89
+ # Validate 'name' field (required)
90
+ if "name" not in fm:
91
+ print(f"[{rel_path}] ERROR: Invalid module configuration in module.md")
92
+ print(f" Path: {rel_path}/module.md")
93
+ print(f" Reason: Missing 'name' field")
94
+ sys.exit(1)
95
+
96
+ raw_name = str(fm["name"]).strip()
97
+
98
+ if not raw_name:
99
+ print(f"[{rel_path}] ERROR: Invalid module configuration in module.md")
100
+ print(f" Path: {rel_path}/module.md")
101
+ print(f" Reason: Empty module name")
102
+ sys.exit(1)
103
+
104
+ # Validate name characters
105
+ sanitized = re.sub(r'[^a-zA-Z0-9_\-]', '', raw_name)
106
+
107
+ if sanitized != raw_name:
108
+ invalid_chars = ''.join(sorted(set(c for c in raw_name if c not in sanitized)))
109
+ print(f"[{rel_path}] ERROR: Invalid module configuration in module.md")
110
+ print(f" Path: {rel_path}/module.md")
111
+ print(f" Reason: Invalid characters in name '{raw_name}': {repr(invalid_chars)}")
112
+ sys.exit(1)
113
+
114
+ result["name"] = sanitized
115
+
116
+ # Extract optional fields
117
+ if "preferred_port" in fm:
118
+ try:
119
+ result["preferred_port"] = int(fm["preferred_port"])
120
+ except (ValueError, TypeError):
121
+ pass
122
+
123
+ if "advertise_ip" in fm:
124
+ result["advertise_ip"] = str(fm["advertise_ip"])
125
+
126
+ # max_connections(弹性连接上限)
127
+ try:
128
+ result["max_connections"] = max(1, min(10, int(fm.get("max_connections", 1))))
129
+ except (ValueError, TypeError):
130
+ result["max_connections"] = 1
131
+ # business_config(从 businesses 数组取第一个 config_file)
132
+ businesses = fm.get("businesses")
133
+ if isinstance(businesses, list) and businesses:
134
+ cfg_file = businesses[0].get("config_file") if isinstance(businesses[0], dict) else None
135
+ if cfg_file:
136
+ result["business_config"] = str(cfg_file).strip()
137
+
138
+ except SystemExit:
139
+ raise # Re-raise exit to prevent catching by outer except
140
+ except Exception as e:
141
+ print(f"[{rel_path}] ERROR: Failed to read module.md: {e}")
142
+ sys.exit(1)
143
+
144
+ return result
145
+
146
+ _module_config = _load_module_config()
147
+ MODULE_NAME = _module_config["name"]
148
+
149
+
150
+ class _SafeWriter:
151
+ """Wraps a stream to silently swallow BrokenPipeError on write/flush."""
152
+ def __init__(self, stream):
153
+ self._stream = stream
154
+
155
+ def write(self, s):
156
+ try:
157
+ self._stream.write(s)
158
+ except (BrokenPipeError, OSError):
159
+ pass
160
+
161
+ def flush(self):
162
+ try:
163
+ self._stream.flush()
164
+ except (BrokenPipeError, OSError):
165
+ pass
166
+
167
+ def __getattr__(self, name):
168
+ return getattr(self._stream, name)
169
+
170
+ sys.stdout = _SafeWriter(sys.stdout)
171
+ sys.stderr = _SafeWriter(sys.stderr)
172
+
173
+
174
+ # ── Timestamped print + log file writer ──
175
+ # Independent implementation per module (no shared code dependency)
176
+
177
+ _builtin_print = builtins.print
178
+ _start_ts = time.monotonic()
179
+ _last_ts = time.monotonic()
180
+ _ANSI_RE = re.compile(r"\033\[[0-9;]*m")
181
+ _log_lock = threading.Lock()
182
+ _log_latest_path = None
183
+ _log_daily_path = None
184
+ _log_daily_date = ""
185
+ _log_dir = None
186
+ _crash_log_path = None
187
+
188
+ def _strip_ansi(s: str) -> str:
189
+ return _ANSI_RE.sub("", s)
190
+
191
+ def _resolve_daily_log_path():
192
+ """Resolve daily log path based on current date."""
193
+ global _log_daily_path, _log_daily_date
194
+ if not _log_dir:
195
+ return
196
+ today = datetime.now().strftime("%Y-%m-%d")
197
+ if today == _log_daily_date and _log_daily_path:
198
+ return
199
+ month_dir = os.path.join(_log_dir, today[:7])
200
+ os.makedirs(month_dir, exist_ok=True)
201
+ _log_daily_path = os.path.join(month_dir, f"{today}.log")
202
+ _log_daily_date = today
203
+
204
+ def _write_log(plain_line: str):
205
+ """Write a plain-text line to both latest.log and daily log."""
206
+ with _log_lock:
207
+ if _log_latest_path:
208
+ try:
209
+ with open(_log_latest_path, "a", encoding="utf-8") as f:
210
+ f.write(plain_line)
211
+ except Exception:
212
+ pass
213
+ _resolve_daily_log_path()
214
+ if _log_daily_path:
215
+ try:
216
+ with open(_log_daily_path, "a", encoding="utf-8") as f:
217
+ f.write(plain_line)
218
+ except Exception:
219
+ pass
220
+
221
+ def _write_crash(exc_type, exc_value, exc_tb, thread_name=None, severity="critical", handled=False):
222
+ """Write crash record to crashes.jsonl + daily crash archive."""
223
+ record = {
224
+ "timestamp": datetime.now(timezone.utc).isoformat(),
225
+ "module": MODULE_NAME,
226
+ "thread": thread_name or threading.current_thread().name,
227
+ "exception_type": exc_type.__name__ if exc_type else "Unknown",
228
+ "exception_message": str(exc_value),
229
+ "traceback": "".join(traceback.format_exception(exc_type, exc_value, exc_tb)),
230
+ "severity": severity,
231
+ "handled": handled,
232
+ "process_id": os.getpid(),
233
+ "platform": sys.platform,
234
+ "runtime_version": f"Python {sys.version.split()[0]}",
235
+ }
236
+
237
+ if exc_tb:
238
+ tb_entries = traceback.extract_tb(exc_tb)
239
+ if tb_entries:
240
+ last = tb_entries[-1]
241
+ record["context"] = {
242
+ "function": last.name,
243
+ "file": os.path.basename(last.filename),
244
+ "line": last.lineno,
245
+ }
246
+
247
+ line = json.dumps(record, ensure_ascii=False) + "\n"
248
+
249
+ if _crash_log_path:
250
+ try:
251
+ with open(_crash_log_path, "a", encoding="utf-8") as f:
252
+ f.write(line)
253
+ except Exception:
254
+ pass
255
+
256
+ if _log_dir:
257
+ try:
258
+ today = datetime.now().strftime("%Y-%m-%d")
259
+ archive_dir = os.path.join(_log_dir, "crashes", today[:7])
260
+ os.makedirs(archive_dir, exist_ok=True)
261
+ archive_path = os.path.join(archive_dir, f"{today}.jsonl")
262
+ with open(archive_path, "a", encoding="utf-8") as f:
263
+ f.write(line)
264
+ except Exception:
265
+ pass
266
+
267
+ def _print_crash_summary(exc_type, exc_tb, thread_name=None):
268
+ """Print crash summary to console (red highlight)."""
269
+ RED = "\033[91m"
270
+ RESET = "\033[0m"
271
+
272
+ if exc_tb:
273
+ tb_entries = traceback.extract_tb(exc_tb)
274
+ if tb_entries:
275
+ last = tb_entries[-1]
276
+ location = f"{os.path.basename(last.filename)}:{last.lineno}"
277
+ else:
278
+ location = "unknown"
279
+ else:
280
+ location = "unknown"
281
+
282
+ prefix = f"[{MODULE_NAME}]"
283
+ if thread_name:
284
+ _builtin_print(f"{prefix} {RED}线程 {thread_name} 崩溃: "
285
+ f"{exc_type.__name__} in {location}{RESET}")
286
+ else:
287
+ _builtin_print(f"{prefix} {RED}崩溃: {exc_type.__name__} in {location}{RESET}")
288
+ if _crash_log_path:
289
+ _builtin_print(f"{prefix} 崩溃日志: {_crash_log_path}")
290
+
291
+ def _setup_exception_hooks():
292
+ """Set up global exception hooks."""
293
+ _orig_excepthook = sys.excepthook
294
+
295
+ def _excepthook(exc_type, exc_value, exc_tb):
296
+ _write_crash(exc_type, exc_value, exc_tb, severity="critical", handled=False)
297
+ _print_crash_summary(exc_type, exc_tb)
298
+ _orig_excepthook(exc_type, exc_value, exc_tb)
299
+
300
+ sys.excepthook = _excepthook
301
+
302
+ if hasattr(threading, "excepthook"):
303
+ def _thread_excepthook(args):
304
+ _write_crash(args.exc_type, args.exc_value, args.exc_traceback,
305
+ thread_name=args.thread.name if args.thread else "unknown",
306
+ severity="error", handled=False)
307
+ _print_crash_summary(args.exc_type, args.exc_traceback,
308
+ thread_name=args.thread.name if args.thread else None)
309
+
310
+ threading.excepthook = _thread_excepthook
311
+
312
+ def _tprint(*args, **kwargs):
313
+ """Timestamped print that adds [timestamp] HH:MM:SS.mmm +delta prefix."""
314
+ global _last_ts
315
+ now = time.monotonic()
316
+ elapsed = now - _start_ts
317
+ delta = now - _last_ts
318
+ _last_ts = now
319
+
320
+ if elapsed < 1:
321
+ elapsed_str = f"{elapsed * 1000:.0f}ms"
322
+ elif elapsed < 100:
323
+ elapsed_str = f"{elapsed:.1f}s"
324
+ else:
325
+ elapsed_str = f"{elapsed:.0f}s"
326
+
327
+ if delta < 0.001:
328
+ delta_str = ""
329
+ elif delta < 1:
330
+ delta_str = f"+{delta * 1000:.0f}ms"
331
+ elif delta < 100:
332
+ delta_str = f"+{delta:.1f}s"
333
+ else:
334
+ delta_str = f"+{delta:.0f}s"
335
+
336
+ ts = datetime.now().strftime("%H:%M:%S.%f")[:-3]
337
+
338
+ _builtin_print(*args, **kwargs)
339
+
340
+ if _log_latest_path or _log_daily_path:
341
+ sep = kwargs.get("sep", " ")
342
+ end = kwargs.get("end", "\n")
343
+ text = sep.join(str(a) for a in args)
344
+ prefix = f"[{elapsed_str:>6}] {ts} {delta_str:>8} "
345
+ _write_log(prefix + _strip_ansi(text) + end)
346
+
347
+ builtins.print = _tprint
348
+
349
+ # Ensure project root (Kite/) is on sys.path
350
+ _this_dir = os.path.dirname(os.path.abspath(__file__))
351
+ _project_root = os.environ.get("KITE_PROJECT") or os.path.dirname(os.path.dirname(os.path.dirname(_this_dir)))
352
+ if _project_root not in sys.path:
353
+ sys.path.insert(0, _project_root)
354
+
355
+ # Also add ai-phone-agent root so we can import config, storage, conversation, etc.
356
+ _agent_root = os.path.dirname(_project_root)
357
+ if _agent_root not in sys.path:
358
+ sys.path.insert(0, _agent_root)
359
+
360
+ from extensions.services.web.server import WebServer
361
+
362
+
363
+ def _fmt_elapsed(t0: float) -> str:
364
+ d = time.monotonic() - t0
365
+ if d < 1:
366
+ return f"{d * 1000:.0f}ms"
367
+ if d < 10:
368
+ return f"{d:.1f}s"
369
+ return f"{d:.0f}s"
370
+
371
+
372
+ def _bind_port(preferred: int, host: str, max_attempts: int = 3) -> int | None:
373
+ """
374
+ Try to bind to preferred port, then port+1, port+2, ... up to max_attempts.
375
+ Returns bound port on success, None on failure.
376
+ """
377
+ if not preferred:
378
+ # No preferred port, use OS-assigned
379
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
380
+ s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
381
+ s.bind((host, 0))
382
+ return s.getsockname()[1]
383
+
384
+ for attempt in range(max_attempts):
385
+ port = preferred + attempt
386
+ try:
387
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
388
+ s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
389
+ s.bind((host, port))
390
+ if attempt > 0:
391
+ print(f"[web] Bound to port {port} (preferred {preferred} was occupied)")
392
+ return port
393
+ except OSError as e:
394
+ if attempt < max_attempts - 1:
395
+ print(f"[web] Port {port} occupied, trying next port...")
396
+ continue
397
+ else:
398
+ print(f"[web] ERROR: Failed to bind port after {max_attempts} attempts ({preferred}-{preferred + max_attempts - 1})")
399
+ return None
400
+
401
+ return None
402
+
403
+
404
+
405
+
406
+ def _run_local_mode(kernel_port: int):
407
+ # Initialize log file paths
408
+ global _log_dir, _log_latest_path, _crash_log_path
409
+ module_data = os.environ.get("KITE_MODULE_DATA")
410
+ if module_data:
411
+ _log_dir = os.path.join(module_data, "log")
412
+ os.makedirs(_log_dir, exist_ok=True)
413
+ suffix = os.environ.get("KITE_INSTANCE_SUFFIX", "")
414
+
415
+ _log_latest_path = os.path.join(_log_dir, f"latest{suffix}.log")
416
+ try:
417
+ with open(_log_latest_path, "w", encoding="utf-8") as f:
418
+ pass
419
+ except Exception:
420
+ _log_latest_path = None
421
+
422
+ _crash_log_path = os.path.join(_log_dir, f"crashes{suffix}.jsonl")
423
+ try:
424
+ with open(_crash_log_path, "w", encoding="utf-8") as f:
425
+ pass
426
+ except Exception:
427
+ _crash_log_path = None
428
+
429
+ _resolve_daily_log_path()
430
+
431
+ _setup_exception_hooks()
432
+
433
+ _t0 = time.monotonic()
434
+
435
+ print(f"[web] Kernel port: {kernel_port} ({_fmt_elapsed(_t0)})")
436
+
437
+ # Use cached module config (already loaded at module level)
438
+ host = _module_config["advertise_ip"]
439
+ port = _bind_port(_module_config["preferred_port"], host)
440
+
441
+ # If port binding failed after 10 attempts, exit gracefully
442
+ if port is None:
443
+ print("[web] ERROR: Cannot bind to any port, exiting")
444
+ sys.exit(1)
445
+
446
+ # Read token from stdin before creating server
447
+ line = sys.stdin.readline().strip()
448
+ if not line:
449
+ print("[web] ERROR: stdin closed")
450
+ sys.exit(1)
451
+
452
+ try:
453
+ msg = json.loads(line)
454
+ except json.JSONDecodeError as e:
455
+ print(f"[web] ERROR: Invalid JSON from stdin: {e}")
456
+ sys.exit(1)
457
+
458
+ if "error" in msg:
459
+ print(f"[web] 启动失败: {msg.get('message', 'unknown')}")
460
+ sys.exit(1)
461
+
462
+ token = msg.get("token", "")
463
+ if not token:
464
+ print("[web] ERROR: No token in stdin message")
465
+ sys.exit(1)
466
+
467
+ # Create server with token
468
+ server = WebServer(
469
+ token=token,
470
+ kernel_port=kernel_port,
471
+ host=host,
472
+ port=port,
473
+ boot_t0=_t0,
474
+ max_connections=_module_config.get("max_connections", 1),
475
+ )
476
+
477
+ # Display access URL in green
478
+ display_host = "localhost" if host == "0.0.0.0" else host
479
+ url = f"http://{display_host}:{port}"
480
+ print(f"[web] Starting on {host}:{port} ({_fmt_elapsed(_t0)})")
481
+ print(f"[web] \033[32m✓ Web UI ready: {url}\033[0m")
482
+
483
+ try:
484
+ config = uvicorn.Config(server.app, host=host, port=port, log_level="warning")
485
+ uvi_server = uvicorn.Server(config)
486
+ server._uvicorn_server = uvi_server
487
+ uvi_server.run()
488
+ except Exception as e:
489
+ _write_crash(type(e), e, e.__traceback__, severity="critical", handled=True)
490
+ _print_crash_summary(type(e), e.__traceback__)
491
+ sys.exit(1)
492
+
493
+ # Check if server requested exit with non-zero code
494
+ if server._exit_code != 0:
495
+ sys.exit(server._exit_code)
496
+
497
+
498
+ def _run_remote_mode(gateway_url: str):
499
+ global _log_dir, _log_latest_path, _crash_log_path
500
+ home = os.environ.get("HOME") or os.environ.get("USERPROFILE") or os.path.expanduser("~")
501
+ data_dir = os.path.join(home, ".kite", "remote", MODULE_NAME)
502
+ os.makedirs(data_dir, exist_ok=True)
503
+ _log_dir = os.path.join(data_dir, "log")
504
+ os.makedirs(_log_dir, exist_ok=True)
505
+ _log_latest_path = os.path.join(_log_dir, "latest.log")
506
+ try:
507
+ with open(_log_latest_path, "w", encoding="utf-8") as f: pass
508
+ except Exception: _log_latest_path = None
509
+ _crash_log_path = os.path.join(_log_dir, "crashes.jsonl")
510
+ try:
511
+ with open(_crash_log_path, "w", encoding="utf-8") as f: pass
512
+ except Exception: _crash_log_path = None
513
+ _resolve_daily_log_path()
514
+ _setup_exception_hooks()
515
+
516
+ _t0 = time.monotonic()
517
+ kite_token = _get_kite_token(MODULE_NAME, gateway_url)
518
+ print(f"[{MODULE_NAME}] Remote mode: gateway={gateway_url}")
519
+
520
+ host = _module_config["advertise_ip"]
521
+ port = _bind_port(_module_config["preferred_port"], host)
522
+ if port is None:
523
+ print(f"[{MODULE_NAME}] ERROR: Cannot bind to any port")
524
+ sys.exit(1)
525
+
526
+ server = WebServer(
527
+ token="",
528
+ kernel_port=0,
529
+ host=host,
530
+ port=port,
531
+ boot_t0=_t0,
532
+ max_connections=_module_config.get("max_connections", 1),
533
+ gateway_url=gateway_url,
534
+ kite_token=kite_token,
535
+ )
536
+
537
+ try:
538
+ config = uvicorn.Config(server.app, host=host, port=port, log_level="warning")
539
+ uvi_server = uvicorn.Server(config)
540
+ server._uvicorn_server = uvi_server
541
+ uvi_server.run()
542
+ except Exception as e:
543
+ _write_crash(type(e), e, e.__traceback__, severity="critical", handled=True)
544
+ _print_crash_summary(type(e), e.__traceback__)
545
+ sys.exit(1)
546
+ if hasattr(server, '_auth_failed') and server._auth_failed:
547
+ _clear_token_cache(MODULE_NAME, gateway_url)
548
+ if server._exit_code != 0:
549
+ sys.exit(server._exit_code)
550
+
551
+
552
+ # ── Token management ──
553
+
554
+ def _gateway_to_filename(gateway_url: str) -> str:
555
+ try:
556
+ from urllib.parse import urlparse
557
+ parsed = urlparse(gateway_url)
558
+ host = parsed.hostname or "unknown"
559
+ port = parsed.port or (443 if parsed.scheme == "wss" else 80)
560
+ return f"{host}-{port}.json".replace(":", "-").replace("/", "-")
561
+ except Exception: return "default.json"
562
+
563
+ def _load_token_cache(module_name: str, gateway_url: str) -> dict | None:
564
+ home = os.environ.get("HOME") or os.environ.get("USERPROFILE") or os.path.expanduser("~")
565
+ token_file = os.path.join(home, ".kite", "remote", module_name, "tokens", _gateway_to_filename(gateway_url))
566
+ if not os.path.exists(token_file): return None
567
+ try:
568
+ with open(token_file, "r") as f: return json.load(f)
569
+ except Exception: return None
570
+
571
+ def _clear_token_cache(module_name: str, gateway_url: str):
572
+ home = os.environ.get("HOME") or os.environ.get("USERPROFILE") or os.path.expanduser("~")
573
+ token_file = os.path.join(home, ".kite", "remote", module_name, "tokens", _gateway_to_filename(gateway_url))
574
+ try: os.remove(token_file)
575
+ except Exception: pass
576
+
577
+ def _get_kite_token(module_name: str, gateway_url: str) -> str:
578
+ token = os.environ.get("KITE_TOKEN")
579
+ if token: return token
580
+ cache = _load_token_cache(module_name, gateway_url)
581
+ if cache: return cache["token"]
582
+ print(f"[{module_name}] No token for {gateway_url}")
583
+ print(f" export KITE_TOKEN=<token>")
584
+ sys.exit(1)
585
+
586
+
587
+ if __name__ == "__main__":
588
+ kernel_port = os.environ.get("KITE_KERNEL_PORT")
589
+ if kernel_port:
590
+ _run_local_mode(int(kernel_port))
591
+ else:
592
+ config = _load_module_config()
593
+ gateway_url = config.get("gateway_url") or os.environ.get("KITE_GATEWAY_URL")
594
+ if gateway_url:
595
+ _run_remote_mode(gateway_url)
596
+ else:
597
+ print(f"[{MODULE_NAME}] ERROR: No KITE_KERNEL_PORT and no gateway_url")
598
+ sys.exit(1)