aws-runtime-bridge 1.0.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 (462) hide show
  1. package/README.md +56 -0
  2. package/dist/adapter/AdapterRegistry.d.ts +53 -0
  3. package/dist/adapter/AdapterRegistry.d.ts.map +1 -0
  4. package/dist/adapter/AdapterRegistry.js +100 -0
  5. package/dist/adapter/AdapterRegistry.test.d.ts +5 -0
  6. package/dist/adapter/AdapterRegistry.test.d.ts.map +1 -0
  7. package/dist/adapter/AdapterRegistry.test.js +109 -0
  8. package/dist/adapter/ClaudeSdkAdapter.d.ts +120 -0
  9. package/dist/adapter/ClaudeSdkAdapter.d.ts.map +1 -0
  10. package/dist/adapter/ClaudeSdkAdapter.js +1140 -0
  11. package/dist/adapter/ClaudeSdkAdapter.test.d.ts +2 -0
  12. package/dist/adapter/ClaudeSdkAdapter.test.d.ts.map +1 -0
  13. package/dist/adapter/ClaudeSdkAdapter.test.js +95 -0
  14. package/dist/adapter/CodexSdkAdapter.d.ts +48 -0
  15. package/dist/adapter/CodexSdkAdapter.d.ts.map +1 -0
  16. package/dist/adapter/CodexSdkAdapter.js +750 -0
  17. package/dist/adapter/CodexSdkAdapter.test.d.ts +2 -0
  18. package/dist/adapter/CodexSdkAdapter.test.d.ts.map +1 -0
  19. package/dist/adapter/CodexSdkAdapter.test.js +245 -0
  20. package/dist/adapter/OpencodeSdkAdapter.d.ts +45 -0
  21. package/dist/adapter/OpencodeSdkAdapter.d.ts.map +1 -0
  22. package/dist/adapter/OpencodeSdkAdapter.js +622 -0
  23. package/dist/adapter/OpencodeSdkAdapter.test.d.ts +2 -0
  24. package/dist/adapter/OpencodeSdkAdapter.test.d.ts.map +1 -0
  25. package/dist/adapter/OpencodeSdkAdapter.test.js +14 -0
  26. package/dist/adapter/SdkProviderSpi.d.ts +15 -0
  27. package/dist/adapter/SdkProviderSpi.d.ts.map +1 -0
  28. package/dist/adapter/SdkProviderSpi.js +46 -0
  29. package/dist/adapter/adapter.test.d.ts +5 -0
  30. package/dist/adapter/adapter.test.d.ts.map +1 -0
  31. package/dist/adapter/adapter.test.js +180 -0
  32. package/dist/adapter/index.d.ts +11 -0
  33. package/dist/adapter/index.d.ts.map +1 -0
  34. package/dist/adapter/index.js +10 -0
  35. package/dist/adapter/types.d.ts +278 -0
  36. package/dist/adapter/types.d.ts.map +1 -0
  37. package/dist/adapter/types.js +278 -0
  38. package/dist/adapter/types.test.d.ts +2 -0
  39. package/dist/adapter/types.test.d.ts.map +1 -0
  40. package/dist/adapter/types.test.js +59 -0
  41. package/dist/adapters/cc-switch/common.d.ts +52 -0
  42. package/dist/adapters/cc-switch/common.d.ts.map +1 -0
  43. package/dist/adapters/cc-switch/common.js +61 -0
  44. package/dist/adapters/cc-switch/index.d.ts +25 -0
  45. package/dist/adapters/cc-switch/index.d.ts.map +1 -0
  46. package/dist/adapters/cc-switch/index.js +51 -0
  47. package/dist/adapters/cc-switch/mcp-claude.d.ts +15 -0
  48. package/dist/adapters/cc-switch/mcp-claude.d.ts.map +1 -0
  49. package/dist/adapters/cc-switch/mcp-claude.js +88 -0
  50. package/dist/adapters/cc-switch/mcp-claudecode.d.ts +15 -0
  51. package/dist/adapters/cc-switch/mcp-claudecode.d.ts.map +1 -0
  52. package/dist/adapters/cc-switch/mcp-claudecode.js +77 -0
  53. package/dist/adapters/cc-switch/mcp-codex.d.ts +17 -0
  54. package/dist/adapters/cc-switch/mcp-codex.d.ts.map +1 -0
  55. package/dist/adapters/cc-switch/mcp-codex.js +248 -0
  56. package/dist/adapters/cc-switch/mcp-codex.test.d.ts +2 -0
  57. package/dist/adapters/cc-switch/mcp-codex.test.d.ts.map +1 -0
  58. package/dist/adapters/cc-switch/mcp-codex.test.js +125 -0
  59. package/dist/adapters/cc-switch/mcp-opencode.d.ts +23 -0
  60. package/dist/adapters/cc-switch/mcp-opencode.d.ts.map +1 -0
  61. package/dist/adapters/cc-switch/mcp-opencode.js +100 -0
  62. package/dist/adapters/cc-switch/mcp-placeholder.d.ts +14 -0
  63. package/dist/adapters/cc-switch/mcp-placeholder.d.ts.map +1 -0
  64. package/dist/adapters/cc-switch/mcp-placeholder.js +19 -0
  65. package/dist/adapters/cc-switch/skill-claude.d.ts +15 -0
  66. package/dist/adapters/cc-switch/skill-claude.d.ts.map +1 -0
  67. package/dist/adapters/cc-switch/skill-claude.js +91 -0
  68. package/dist/adapters/cc-switch/skill-claudecode.d.ts +15 -0
  69. package/dist/adapters/cc-switch/skill-claudecode.d.ts.map +1 -0
  70. package/dist/adapters/cc-switch/skill-claudecode.js +91 -0
  71. package/dist/adapters/cc-switch/skill-opencode.d.ts +15 -0
  72. package/dist/adapters/cc-switch/skill-opencode.d.ts.map +1 -0
  73. package/dist/adapters/cc-switch/skill-opencode.js +95 -0
  74. package/dist/adapters/cc-switch/skill-placeholder.d.ts +14 -0
  75. package/dist/adapters/cc-switch/skill-placeholder.d.ts.map +1 -0
  76. package/dist/adapters/cc-switch/skill-placeholder.js +19 -0
  77. package/dist/config.d.ts +76 -0
  78. package/dist/config.d.ts.map +1 -0
  79. package/dist/config.js +109 -0
  80. package/dist/index.d.ts +8 -0
  81. package/dist/index.d.ts.map +1 -0
  82. package/dist/index.js +503 -0
  83. package/dist/middleware/auth.d.ts +12 -0
  84. package/dist/middleware/auth.d.ts.map +1 -0
  85. package/dist/middleware/auth.js +18 -0
  86. package/dist/routes/ai-sources.d.ts +2 -0
  87. package/dist/routes/ai-sources.d.ts.map +1 -0
  88. package/dist/routes/ai-sources.js +136 -0
  89. package/dist/routes/ai-sources.test.d.ts +2 -0
  90. package/dist/routes/ai-sources.test.d.ts.map +1 -0
  91. package/dist/routes/ai-sources.test.js +148 -0
  92. package/dist/routes/aws-mcp.d.ts +10 -0
  93. package/dist/routes/aws-mcp.d.ts.map +1 -0
  94. package/dist/routes/aws-mcp.js +74 -0
  95. package/dist/routes/aws-mcp.test.d.ts +2 -0
  96. package/dist/routes/aws-mcp.test.d.ts.map +1 -0
  97. package/dist/routes/aws-mcp.test.js +42 -0
  98. package/dist/routes/file-browser.d.ts +7 -0
  99. package/dist/routes/file-browser.d.ts.map +1 -0
  100. package/dist/routes/file-browser.js +227 -0
  101. package/dist/routes/file-browser.test.d.ts +5 -0
  102. package/dist/routes/file-browser.test.d.ts.map +1 -0
  103. package/dist/routes/file-browser.test.js +88 -0
  104. package/dist/routes/git.d.ts +7 -0
  105. package/dist/routes/git.d.ts.map +1 -0
  106. package/dist/routes/git.js +470 -0
  107. package/dist/routes/git.test.d.ts +5 -0
  108. package/dist/routes/git.test.d.ts.map +1 -0
  109. package/dist/routes/git.test.js +87 -0
  110. package/dist/routes/instance.d.ts +3 -0
  111. package/dist/routes/instance.d.ts.map +1 -0
  112. package/dist/routes/instance.js +170 -0
  113. package/dist/routes/instance.test.d.ts +5 -0
  114. package/dist/routes/instance.test.d.ts.map +1 -0
  115. package/dist/routes/instance.test.js +64 -0
  116. package/dist/routes/mcp.d.ts +2 -0
  117. package/dist/routes/mcp.d.ts.map +1 -0
  118. package/dist/routes/mcp.js +171 -0
  119. package/dist/routes/mcp.test.d.ts +5 -0
  120. package/dist/routes/mcp.test.d.ts.map +1 -0
  121. package/dist/routes/mcp.test.js +84 -0
  122. package/dist/routes/memory.d.ts +13 -0
  123. package/dist/routes/memory.d.ts.map +1 -0
  124. package/dist/routes/memory.js +429 -0
  125. package/dist/routes/processes.d.ts +7 -0
  126. package/dist/routes/processes.d.ts.map +1 -0
  127. package/dist/routes/processes.js +245 -0
  128. package/dist/routes/properties.d.ts +7 -0
  129. package/dist/routes/properties.d.ts.map +1 -0
  130. package/dist/routes/properties.js +72 -0
  131. package/dist/routes/properties.test.d.ts +5 -0
  132. package/dist/routes/properties.test.d.ts.map +1 -0
  133. package/dist/routes/properties.test.js +72 -0
  134. package/dist/routes/sessions.d.ts +7 -0
  135. package/dist/routes/sessions.d.ts.map +1 -0
  136. package/dist/routes/sessions.js +808 -0
  137. package/dist/routes/sessions.test.d.ts +5 -0
  138. package/dist/routes/sessions.test.d.ts.map +1 -0
  139. package/dist/routes/sessions.test.js +70 -0
  140. package/dist/routes/skills.d.ts +2 -0
  141. package/dist/routes/skills.d.ts.map +1 -0
  142. package/dist/routes/skills.js +162 -0
  143. package/dist/routes/skills.test.d.ts +5 -0
  144. package/dist/routes/skills.test.d.ts.map +1 -0
  145. package/dist/routes/skills.test.js +42 -0
  146. package/dist/routes/terminal.d.ts +18 -0
  147. package/dist/routes/terminal.d.ts.map +1 -0
  148. package/dist/routes/terminal.js +663 -0
  149. package/dist/routes/terminal.test.d.ts +2 -0
  150. package/dist/routes/terminal.test.d.ts.map +1 -0
  151. package/dist/routes/terminal.test.js +91 -0
  152. package/dist/routes/yml.d.ts +7 -0
  153. package/dist/routes/yml.d.ts.map +1 -0
  154. package/dist/routes/yml.js +223 -0
  155. package/dist/routes/yml.test.d.ts +5 -0
  156. package/dist/routes/yml.test.d.ts.map +1 -0
  157. package/dist/routes/yml.test.js +58 -0
  158. package/dist/services/agent-process-manager.d.ts +241 -0
  159. package/dist/services/agent-process-manager.d.ts.map +1 -0
  160. package/dist/services/agent-process-manager.js +762 -0
  161. package/dist/services/auto-register.d.ts +94 -0
  162. package/dist/services/auto-register.d.ts.map +1 -0
  163. package/dist/services/auto-register.js +510 -0
  164. package/dist/services/aws-client-agent-mcp.d.ts +26 -0
  165. package/dist/services/aws-client-agent-mcp.d.ts.map +1 -0
  166. package/dist/services/aws-client-agent-mcp.js +142 -0
  167. package/dist/services/aws-client-agent-mcp.test.d.ts +2 -0
  168. package/dist/services/aws-client-agent-mcp.test.d.ts.map +1 -0
  169. package/dist/services/aws-client-agent-mcp.test.js +89 -0
  170. package/dist/services/aws-mcp-http.d.ts +11 -0
  171. package/dist/services/aws-mcp-http.d.ts.map +1 -0
  172. package/dist/services/aws-mcp-http.js +225 -0
  173. package/dist/services/aws-mcp-http.test.d.ts +2 -0
  174. package/dist/services/aws-mcp-http.test.d.ts.map +1 -0
  175. package/dist/services/aws-mcp-http.test.js +27 -0
  176. package/dist/services/cc-switch-sdk.d.ts +18 -0
  177. package/dist/services/cc-switch-sdk.d.ts.map +1 -0
  178. package/dist/services/cc-switch-sdk.js +117 -0
  179. package/dist/services/easytier-manager.d.ts +106 -0
  180. package/dist/services/easytier-manager.d.ts.map +1 -0
  181. package/dist/services/easytier-manager.js +331 -0
  182. package/dist/services/easytier-manager.test.d.ts +5 -0
  183. package/dist/services/easytier-manager.test.d.ts.map +1 -0
  184. package/dist/services/easytier-manager.test.js +98 -0
  185. package/dist/services/instance-init-service.d.ts +35 -0
  186. package/dist/services/instance-init-service.d.ts.map +1 -0
  187. package/dist/services/instance-init-service.js +190 -0
  188. package/dist/services/instance-service.d.ts +88 -0
  189. package/dist/services/instance-service.d.ts.map +1 -0
  190. package/dist/services/instance-service.js +236 -0
  191. package/dist/services/instance-state.d.ts +36 -0
  192. package/dist/services/instance-state.d.ts.map +1 -0
  193. package/dist/services/instance-state.js +79 -0
  194. package/dist/services/instance-state.test.d.ts +2 -0
  195. package/dist/services/instance-state.test.d.ts.map +1 -0
  196. package/dist/services/instance-state.test.js +213 -0
  197. package/dist/services/memory-service.d.ts +195 -0
  198. package/dist/services/memory-service.d.ts.map +1 -0
  199. package/dist/services/memory-service.js +650 -0
  200. package/dist/services/orphan-monitor.d.ts +94 -0
  201. package/dist/services/orphan-monitor.d.ts.map +1 -0
  202. package/dist/services/orphan-monitor.js +321 -0
  203. package/dist/services/process-detector.d.ts +175 -0
  204. package/dist/services/process-detector.d.ts.map +1 -0
  205. package/dist/services/process-detector.js +992 -0
  206. package/dist/services/process-registry.d.ts +208 -0
  207. package/dist/services/process-registry.d.ts.map +1 -0
  208. package/dist/services/process-registry.js +354 -0
  209. package/dist/services/session-lookup.d.ts +20 -0
  210. package/dist/services/session-lookup.d.ts.map +1 -0
  211. package/dist/services/session-lookup.js +43 -0
  212. package/dist/services/session-output.d.ts +56 -0
  213. package/dist/services/session-output.d.ts.map +1 -0
  214. package/dist/services/session-output.js +122 -0
  215. package/dist/services/session-output.test.d.ts +5 -0
  216. package/dist/services/session-output.test.d.ts.map +1 -0
  217. package/dist/services/session-output.test.js +68 -0
  218. package/dist/services/terminal-persistence.d.ts +51 -0
  219. package/dist/services/terminal-persistence.d.ts.map +1 -0
  220. package/dist/services/terminal-persistence.js +125 -0
  221. package/dist/services/terminal-persistence.test.d.ts +5 -0
  222. package/dist/services/terminal-persistence.test.d.ts.map +1 -0
  223. package/dist/services/terminal-persistence.test.js +88 -0
  224. package/dist/services/tool-installer.d.ts +15 -0
  225. package/dist/services/tool-installer.d.ts.map +1 -0
  226. package/dist/services/tool-installer.js +297 -0
  227. package/dist/services/tool-installer.test.d.ts +2 -0
  228. package/dist/services/tool-installer.test.d.ts.map +1 -0
  229. package/dist/services/tool-installer.test.js +102 -0
  230. package/dist/services/user-api-key-service.d.ts +28 -0
  231. package/dist/services/user-api-key-service.d.ts.map +1 -0
  232. package/dist/services/user-api-key-service.js +75 -0
  233. package/dist/services/workspace-files.d.ts +85 -0
  234. package/dist/services/workspace-files.d.ts.map +1 -0
  235. package/dist/services/workspace-files.js +224 -0
  236. package/dist/services/workspace-files.test.d.ts +2 -0
  237. package/dist/services/workspace-files.test.d.ts.map +1 -0
  238. package/dist/services/workspace-files.test.js +117 -0
  239. package/dist/types.d.ts +233 -0
  240. package/dist/types.d.ts.map +1 -0
  241. package/dist/types.js +1 -0
  242. package/dist/utils/file-utils.d.ts +13 -0
  243. package/dist/utils/file-utils.d.ts.map +1 -0
  244. package/dist/utils/file-utils.js +140 -0
  245. package/dist/utils/file-utils.test.d.ts +2 -0
  246. package/dist/utils/file-utils.test.d.ts.map +1 -0
  247. package/dist/utils/file-utils.test.js +201 -0
  248. package/dist/utils/logger.d.ts +39 -0
  249. package/dist/utils/logger.d.ts.map +1 -0
  250. package/dist/utils/logger.js +110 -0
  251. package/dist/utils/logger.test.d.ts +2 -0
  252. package/dist/utils/logger.test.d.ts.map +1 -0
  253. package/dist/utils/logger.test.js +93 -0
  254. package/dist/utils/mcp-utils.d.ts +73 -0
  255. package/dist/utils/mcp-utils.d.ts.map +1 -0
  256. package/dist/utils/mcp-utils.js +165 -0
  257. package/dist/utils/path-utils.d.ts +24 -0
  258. package/dist/utils/path-utils.d.ts.map +1 -0
  259. package/dist/utils/path-utils.js +44 -0
  260. package/dist/utils/validation.d.ts +23 -0
  261. package/dist/utils/validation.d.ts.map +1 -0
  262. package/dist/utils/validation.js +53 -0
  263. package/dist/utils/validation.test.d.ts +2 -0
  264. package/dist/utils/validation.test.d.ts.map +1 -0
  265. package/dist/utils/validation.test.js +88 -0
  266. package/dist/utils/yaml-utils.d.ts +73 -0
  267. package/dist/utils/yaml-utils.d.ts.map +1 -0
  268. package/dist/utils/yaml-utils.js +309 -0
  269. package/dist/utils/yaml-utils.test.d.ts +2 -0
  270. package/dist/utils/yaml-utils.test.d.ts.map +1 -0
  271. package/dist/utils/yaml-utils.test.js +363 -0
  272. package/package/aws-client-agent-mcp/README.md +288 -0
  273. package/package/aws-client-agent-mcp/dist/activity-reporter.d.ts +150 -0
  274. package/package/aws-client-agent-mcp/dist/activity-reporter.d.ts.map +1 -0
  275. package/package/aws-client-agent-mcp/dist/activity-reporter.js +353 -0
  276. package/package/aws-client-agent-mcp/dist/activity-reporter.js.map +1 -0
  277. package/package/aws-client-agent-mcp/dist/activity-reporter.test.d.ts +2 -0
  278. package/package/aws-client-agent-mcp/dist/activity-reporter.test.d.ts.map +1 -0
  279. package/package/aws-client-agent-mcp/dist/activity-reporter.test.js +75 -0
  280. package/package/aws-client-agent-mcp/dist/activity-reporter.test.js.map +1 -0
  281. package/package/aws-client-agent-mcp/dist/activity-types.d.ts +96 -0
  282. package/package/aws-client-agent-mcp/dist/activity-types.d.ts.map +1 -0
  283. package/package/aws-client-agent-mcp/dist/activity-types.js +141 -0
  284. package/package/aws-client-agent-mcp/dist/activity-types.js.map +1 -0
  285. package/package/aws-client-agent-mcp/dist/agent-client.d.ts +165 -0
  286. package/package/aws-client-agent-mcp/dist/agent-client.d.ts.map +1 -0
  287. package/package/aws-client-agent-mcp/dist/agent-client.js +588 -0
  288. package/package/aws-client-agent-mcp/dist/agent-client.js.map +1 -0
  289. package/package/aws-client-agent-mcp/dist/agent-client.test.d.ts +2 -0
  290. package/package/aws-client-agent-mcp/dist/agent-client.test.d.ts.map +1 -0
  291. package/package/aws-client-agent-mcp/dist/agent-client.test.js +534 -0
  292. package/package/aws-client-agent-mcp/dist/agent-client.test.js.map +1 -0
  293. package/package/aws-client-agent-mcp/dist/config.d.ts +21 -0
  294. package/package/aws-client-agent-mcp/dist/config.d.ts.map +1 -0
  295. package/package/aws-client-agent-mcp/dist/config.js +67 -0
  296. package/package/aws-client-agent-mcp/dist/config.js.map +1 -0
  297. package/package/aws-client-agent-mcp/dist/config.test.d.ts +2 -0
  298. package/package/aws-client-agent-mcp/dist/config.test.d.ts.map +1 -0
  299. package/package/aws-client-agent-mcp/dist/config.test.js +139 -0
  300. package/package/aws-client-agent-mcp/dist/config.test.js.map +1 -0
  301. package/package/aws-client-agent-mcp/dist/constants.d.ts +15 -0
  302. package/package/aws-client-agent-mcp/dist/constants.d.ts.map +1 -0
  303. package/package/aws-client-agent-mcp/dist/constants.js +19 -0
  304. package/package/aws-client-agent-mcp/dist/constants.js.map +1 -0
  305. package/package/aws-client-agent-mcp/dist/http-client.d.ts +27 -0
  306. package/package/aws-client-agent-mcp/dist/http-client.d.ts.map +1 -0
  307. package/package/aws-client-agent-mcp/dist/http-client.js +65 -0
  308. package/package/aws-client-agent-mcp/dist/http-client.js.map +1 -0
  309. package/package/aws-client-agent-mcp/dist/http-client.test.d.ts +2 -0
  310. package/package/aws-client-agent-mcp/dist/http-client.test.d.ts.map +1 -0
  311. package/package/aws-client-agent-mcp/dist/http-client.test.js +228 -0
  312. package/package/aws-client-agent-mcp/dist/http-client.test.js.map +1 -0
  313. package/package/aws-client-agent-mcp/dist/index.d.ts +14 -0
  314. package/package/aws-client-agent-mcp/dist/index.d.ts.map +1 -0
  315. package/package/aws-client-agent-mcp/dist/index.js +30 -0
  316. package/package/aws-client-agent-mcp/dist/index.js.map +1 -0
  317. package/package/aws-client-agent-mcp/dist/logger.d.ts +7 -0
  318. package/package/aws-client-agent-mcp/dist/logger.d.ts.map +1 -0
  319. package/package/aws-client-agent-mcp/dist/logger.js +19 -0
  320. package/package/aws-client-agent-mcp/dist/logger.js.map +1 -0
  321. package/package/aws-client-agent-mcp/dist/mcp-server.d.ts +77 -0
  322. package/package/aws-client-agent-mcp/dist/mcp-server.d.ts.map +1 -0
  323. package/package/aws-client-agent-mcp/dist/mcp-server.js +427 -0
  324. package/package/aws-client-agent-mcp/dist/mcp-server.js.map +1 -0
  325. package/package/aws-client-agent-mcp/dist/mcp-server.test.d.ts +2 -0
  326. package/package/aws-client-agent-mcp/dist/mcp-server.test.d.ts.map +1 -0
  327. package/package/aws-client-agent-mcp/dist/mcp-server.test.js +624 -0
  328. package/package/aws-client-agent-mcp/dist/mcp-server.test.js.map +1 -0
  329. package/package/aws-client-agent-mcp/dist/mcp-tools.d.ts +78 -0
  330. package/package/aws-client-agent-mcp/dist/mcp-tools.d.ts.map +1 -0
  331. package/package/aws-client-agent-mcp/dist/mcp-tools.js +420 -0
  332. package/package/aws-client-agent-mcp/dist/mcp-tools.js.map +1 -0
  333. package/package/aws-client-agent-mcp/dist/memory-store.d.ts +61 -0
  334. package/package/aws-client-agent-mcp/dist/memory-store.d.ts.map +1 -0
  335. package/package/aws-client-agent-mcp/dist/memory-store.js +268 -0
  336. package/package/aws-client-agent-mcp/dist/memory-store.js.map +1 -0
  337. package/package/aws-client-agent-mcp/dist/memory-store.test.d.ts +2 -0
  338. package/package/aws-client-agent-mcp/dist/memory-store.test.d.ts.map +1 -0
  339. package/package/aws-client-agent-mcp/dist/memory-store.test.js +164 -0
  340. package/package/aws-client-agent-mcp/dist/memory-store.test.js.map +1 -0
  341. package/package/aws-client-agent-mcp/dist/message-buffer.d.ts +74 -0
  342. package/package/aws-client-agent-mcp/dist/message-buffer.d.ts.map +1 -0
  343. package/package/aws-client-agent-mcp/dist/message-buffer.js +159 -0
  344. package/package/aws-client-agent-mcp/dist/message-buffer.js.map +1 -0
  345. package/package/aws-client-agent-mcp/dist/message-buffer.test.d.ts +2 -0
  346. package/package/aws-client-agent-mcp/dist/message-buffer.test.d.ts.map +1 -0
  347. package/package/aws-client-agent-mcp/dist/message-buffer.test.js +44 -0
  348. package/package/aws-client-agent-mcp/dist/message-buffer.test.js.map +1 -0
  349. package/package/aws-client-agent-mcp/dist/messageContent.d.ts +53 -0
  350. package/package/aws-client-agent-mcp/dist/messageContent.d.ts.map +1 -0
  351. package/package/aws-client-agent-mcp/dist/messageContent.js +125 -0
  352. package/package/aws-client-agent-mcp/dist/messageContent.js.map +1 -0
  353. package/package/aws-client-agent-mcp/dist/orchestration-tools.d.ts +19 -0
  354. package/package/aws-client-agent-mcp/dist/orchestration-tools.d.ts.map +1 -0
  355. package/package/aws-client-agent-mcp/dist/orchestration-tools.js +317 -0
  356. package/package/aws-client-agent-mcp/dist/orchestration-tools.js.map +1 -0
  357. package/package/aws-client-agent-mcp/dist/status-reporter.d.ts +66 -0
  358. package/package/aws-client-agent-mcp/dist/status-reporter.d.ts.map +1 -0
  359. package/package/aws-client-agent-mcp/dist/status-reporter.js +220 -0
  360. package/package/aws-client-agent-mcp/dist/status-reporter.js.map +1 -0
  361. package/package/aws-client-agent-mcp/dist/status-reporter.test.d.ts +2 -0
  362. package/package/aws-client-agent-mcp/dist/status-reporter.test.d.ts.map +1 -0
  363. package/package/aws-client-agent-mcp/dist/status-reporter.test.js +45 -0
  364. package/package/aws-client-agent-mcp/dist/status-reporter.test.js.map +1 -0
  365. package/package/aws-client-agent-mcp/dist/types.d.ts +286 -0
  366. package/package/aws-client-agent-mcp/dist/types.d.ts.map +1 -0
  367. package/package/aws-client-agent-mcp/dist/types.js +9 -0
  368. package/package/aws-client-agent-mcp/dist/types.js.map +1 -0
  369. package/package/aws-client-agent-mcp/dist/user-config-reader.d.ts +63 -0
  370. package/package/aws-client-agent-mcp/dist/user-config-reader.d.ts.map +1 -0
  371. package/package/aws-client-agent-mcp/dist/user-config-reader.js +161 -0
  372. package/package/aws-client-agent-mcp/dist/user-config-reader.js.map +1 -0
  373. package/package/aws-client-agent-mcp/dist/websocket-client.d.ts +94 -0
  374. package/package/aws-client-agent-mcp/dist/websocket-client.d.ts.map +1 -0
  375. package/package/aws-client-agent-mcp/dist/websocket-client.js +316 -0
  376. package/package/aws-client-agent-mcp/dist/websocket-client.js.map +1 -0
  377. package/package/aws-client-agent-mcp/dist/websocket-client.test.d.ts +2 -0
  378. package/package/aws-client-agent-mcp/dist/websocket-client.test.d.ts.map +1 -0
  379. package/package/aws-client-agent-mcp/dist/websocket-client.test.js +191 -0
  380. package/package/aws-client-agent-mcp/dist/websocket-client.test.js.map +1 -0
  381. package/package/aws-client-agent-mcp/package.json +51 -0
  382. package/package/cc-switch-sdk/README.md +541 -0
  383. package/package/cc-switch-sdk/dist/adapters/common.d.ts +38 -0
  384. package/package/cc-switch-sdk/dist/adapters/common.d.ts.map +1 -0
  385. package/package/cc-switch-sdk/dist/adapters/common.js +47 -0
  386. package/package/cc-switch-sdk/dist/adapters/index.d.ts +5 -0
  387. package/package/cc-switch-sdk/dist/adapters/index.d.ts.map +1 -0
  388. package/package/cc-switch-sdk/dist/adapters/index.js +28 -0
  389. package/package/cc-switch-sdk/dist/adapters/mcp-claude.d.ts +10 -0
  390. package/package/cc-switch-sdk/dist/adapters/mcp-claude.d.ts.map +1 -0
  391. package/package/cc-switch-sdk/dist/adapters/mcp-claude.js +39 -0
  392. package/package/cc-switch-sdk/dist/adapters/mcp-claudecode.d.ts +10 -0
  393. package/package/cc-switch-sdk/dist/adapters/mcp-claudecode.d.ts.map +1 -0
  394. package/package/cc-switch-sdk/dist/adapters/mcp-claudecode.js +40 -0
  395. package/package/cc-switch-sdk/dist/adapters/mcp-opencode.d.ts +18 -0
  396. package/package/cc-switch-sdk/dist/adapters/mcp-opencode.d.ts.map +1 -0
  397. package/package/cc-switch-sdk/dist/adapters/mcp-opencode.js +63 -0
  398. package/package/cc-switch-sdk/dist/adapters/mcp-opencode.test.d.ts +2 -0
  399. package/package/cc-switch-sdk/dist/adapters/mcp-opencode.test.d.ts.map +1 -0
  400. package/package/cc-switch-sdk/dist/adapters/mcp-opencode.test.js +86 -0
  401. package/package/cc-switch-sdk/dist/adapters/mcp-placeholder.d.ts +9 -0
  402. package/package/cc-switch-sdk/dist/adapters/mcp-placeholder.d.ts.map +1 -0
  403. package/package/cc-switch-sdk/dist/adapters/mcp-placeholder.js +14 -0
  404. package/package/cc-switch-sdk/dist/adapters/skill-claude.d.ts +10 -0
  405. package/package/cc-switch-sdk/dist/adapters/skill-claude.d.ts.map +1 -0
  406. package/package/cc-switch-sdk/dist/adapters/skill-claude.js +51 -0
  407. package/package/cc-switch-sdk/dist/adapters/skill-claudecode.d.ts +10 -0
  408. package/package/cc-switch-sdk/dist/adapters/skill-claudecode.d.ts.map +1 -0
  409. package/package/cc-switch-sdk/dist/adapters/skill-claudecode.js +51 -0
  410. package/package/cc-switch-sdk/dist/adapters/skill-opencode.d.ts +10 -0
  411. package/package/cc-switch-sdk/dist/adapters/skill-opencode.d.ts.map +1 -0
  412. package/package/cc-switch-sdk/dist/adapters/skill-opencode.js +51 -0
  413. package/package/cc-switch-sdk/dist/adapters/skill-placeholder.d.ts +9 -0
  414. package/package/cc-switch-sdk/dist/adapters/skill-placeholder.d.ts.map +1 -0
  415. package/package/cc-switch-sdk/dist/adapters/skill-placeholder.js +14 -0
  416. package/package/cc-switch-sdk/dist/constants.d.ts +9 -0
  417. package/package/cc-switch-sdk/dist/constants.d.ts.map +1 -0
  418. package/package/cc-switch-sdk/dist/constants.js +54 -0
  419. package/package/cc-switch-sdk/dist/errors.d.ts +6 -0
  420. package/package/cc-switch-sdk/dist/errors.d.ts.map +1 -0
  421. package/package/cc-switch-sdk/dist/errors.js +8 -0
  422. package/package/cc-switch-sdk/dist/index.d.ts +11 -0
  423. package/package/cc-switch-sdk/dist/index.d.ts.map +1 -0
  424. package/package/cc-switch-sdk/dist/index.js +9 -0
  425. package/package/cc-switch-sdk/dist/schemas.d.ts +8 -0
  426. package/package/cc-switch-sdk/dist/schemas.d.ts.map +1 -0
  427. package/package/cc-switch-sdk/dist/schemas.js +37 -0
  428. package/package/cc-switch-sdk/dist/sdk.d.ts +91 -0
  429. package/package/cc-switch-sdk/dist/sdk.d.ts.map +1 -0
  430. package/package/cc-switch-sdk/dist/sdk.js +427 -0
  431. package/package/cc-switch-sdk/dist/services/ai-config-service.d.ts +75 -0
  432. package/package/cc-switch-sdk/dist/services/ai-config-service.d.ts.map +1 -0
  433. package/package/cc-switch-sdk/dist/services/ai-config-service.js +280 -0
  434. package/package/cc-switch-sdk/dist/services/instance-service.d.ts +78 -0
  435. package/package/cc-switch-sdk/dist/services/instance-service.d.ts.map +1 -0
  436. package/package/cc-switch-sdk/dist/services/instance-service.js +180 -0
  437. package/package/cc-switch-sdk/dist/services/mcp-model.d.ts +17 -0
  438. package/package/cc-switch-sdk/dist/services/mcp-model.d.ts.map +1 -0
  439. package/package/cc-switch-sdk/dist/services/mcp-model.js +34 -0
  440. package/package/cc-switch-sdk/dist/services/mcp-service.d.ts +18 -0
  441. package/package/cc-switch-sdk/dist/services/mcp-service.d.ts.map +1 -0
  442. package/package/cc-switch-sdk/dist/services/mcp-service.js +9 -0
  443. package/package/cc-switch-sdk/dist/services/skill-model.d.ts +17 -0
  444. package/package/cc-switch-sdk/dist/services/skill-model.d.ts.map +1 -0
  445. package/package/cc-switch-sdk/dist/services/skill-model.js +38 -0
  446. package/package/cc-switch-sdk/dist/services/skill-service.d.ts +17 -0
  447. package/package/cc-switch-sdk/dist/services/skill-service.d.ts.map +1 -0
  448. package/package/cc-switch-sdk/dist/services/skill-service.js +9 -0
  449. package/package/cc-switch-sdk/dist/state.d.ts +4 -0
  450. package/package/cc-switch-sdk/dist/state.d.ts.map +1 -0
  451. package/package/cc-switch-sdk/dist/state.js +19 -0
  452. package/package/cc-switch-sdk/dist/types.d.ts +75 -0
  453. package/package/cc-switch-sdk/dist/types.d.ts.map +1 -0
  454. package/package/cc-switch-sdk/dist/types.js +1 -0
  455. package/package/cc-switch-sdk/dist/utils/fs.d.ts +10 -0
  456. package/package/cc-switch-sdk/dist/utils/fs.d.ts.map +1 -0
  457. package/package/cc-switch-sdk/dist/utils/fs.js +91 -0
  458. package/package/cc-switch-sdk/dist/utils/id.d.ts +4 -0
  459. package/package/cc-switch-sdk/dist/utils/id.d.ts.map +1 -0
  460. package/package/cc-switch-sdk/dist/utils/id.js +12 -0
  461. package/package/cc-switch-sdk/package.json +31 -0
  462. package/package.json +73 -0
@@ -0,0 +1,992 @@
1
+ /**
2
+ * 进程检测服务
3
+ *
4
+ * 用于检测孤儿进程(当 runtime-bridge 异常关闭后仍在运行的 Agent 进程)
5
+ */
6
+ import { execSync } from 'child_process';
7
+ import os from 'os';
8
+ import { createLogger } from '../utils/logger.js';
9
+ const log = createLogger('process-detector');
10
+ /**
11
+ * 在 Windows 上执行 PowerShell 命令
12
+ *
13
+ * 使用 -EncodedCommand 传递 Base64 编码的命令,
14
+ * 彻底避免 cmd.exe 对管道符 |、引号、$ 等特殊字符的转义破坏。
15
+ *
16
+ * @param psScript PowerShell 脚本内容(UTF-16LE 编码后 Base64)
17
+ * @param timeout 超时时间(毫秒)
18
+ * @returns 命令输出
19
+ */
20
+ function execPowerShell(psScript, timeout = 15000) {
21
+ // PowerShell -EncodedCommand 需要 UTF-16LE 编码的 Base64
22
+ const buffer = Buffer.from(psScript, 'utf16le');
23
+ const encoded = buffer.toString('base64');
24
+ const output = execSync(`powershell -NoProfile -NonInteractive -EncodedCommand ${encoded}`, { encoding: 'utf8', timeout, windowsHide: true });
25
+ // ★ 过滤 PowerShell CLIXML 噪音(进度信息等 stderr 混入 stdout 的内容)
26
+ // CLIXML 格式:#< CLIXML <Objs ...>...</Objs>
27
+ return output.replace(/#\s*<\s*CLIXML[\s\S]*?(?=#<\s*CLIXML|$)/g, '').trim();
28
+ }
29
+ /**
30
+ * 检测进程是否存活
31
+ *
32
+ * @param pid 进程 ID
33
+ * @returns 是否存活
34
+ */
35
+ export function isProcessRunning(pid) {
36
+ try {
37
+ if (os.platform() === 'win32') {
38
+ // Windows: 使用 tasklist 检测,比 process.kill(pid, 0) 更可靠
39
+ // process.kill(pid, 0) 在 Windows 上对某些子进程可能权限不足
40
+ const output = execSync(`tasklist /FI "PID eq ${pid}" /NH /FO CSV`, { encoding: 'utf8', timeout: 5000, windowsHide: true });
41
+ // tasklist 返回中包含 PID 则进程存活
42
+ return output.includes(String(pid));
43
+ }
44
+ else {
45
+ // Unix: 发送信号 0 检测进程是否存活
46
+ process.kill(pid, 0);
47
+ return true;
48
+ }
49
+ }
50
+ catch {
51
+ // 进程不存在或无法访问
52
+ return false;
53
+ }
54
+ }
55
+ /**
56
+ * 查找 Agent 相关的进程(Claude Code、OpenCode 等)
57
+ *
58
+ * @returns 匹配的进程列表
59
+ */
60
+ export function findClaudeCodeProcesses() {
61
+ const platform = os.platform();
62
+ const results = [];
63
+ try {
64
+ if (platform === 'win32') {
65
+ // Windows: 优先使用 PowerShell(wmic 已弃用)
66
+ results.push(...findProcessesWindows());
67
+ }
68
+ else {
69
+ // macOS/Linux: 使用 ps
70
+ results.push(...findProcessesUnix());
71
+ }
72
+ }
73
+ catch (error) {
74
+ // 命令执行失败,可能没有匹配的进程
75
+ log.debug('Failed to list processes:', error);
76
+ }
77
+ return results;
78
+ }
79
+ /**
80
+ * Windows: 使用 PowerShell 查找 Agent 进程
81
+ * PowerShell 比 wmic 更可靠(wmic 在 Win10 21H1+ 已弃用)
82
+ */
83
+ function findProcessesWindows() {
84
+ const results = [];
85
+ try {
86
+ const psScript = `Get-CimInstance Win32_Process -Filter "Name LIKE '%node%' OR Name LIKE '%claude%' OR Name LIKE '%opencode%' OR Name LIKE '%python%'" | Select-Object ProcessId, CommandLine | ConvertTo-Json -Compress`;
87
+ const output = execPowerShell(psScript, 10000);
88
+ if (!output || !output.trim())
89
+ return results;
90
+ let processes;
91
+ try {
92
+ const parsed = JSON.parse(output);
93
+ // PowerShell 单条结果返回对象,多条返回数组
94
+ processes = Array.isArray(parsed) ? parsed : [parsed];
95
+ }
96
+ catch {
97
+ return results;
98
+ }
99
+ for (const proc of processes) {
100
+ if (!proc.ProcessId || !proc.CommandLine)
101
+ continue;
102
+ const cmd = proc.CommandLine;
103
+ if (isAgentProcess(cmd)) {
104
+ const agentId = extractAgentId(cmd);
105
+ results.push({
106
+ pid: proc.ProcessId,
107
+ command: cmd,
108
+ agentId,
109
+ });
110
+ }
111
+ }
112
+ }
113
+ catch (error) {
114
+ // PowerShell 失败,回退到 wmic
115
+ log.debug('PowerShell process query failed, trying wmic fallback:', error);
116
+ results.push(...findProcessesWindowsWmic());
117
+ }
118
+ return results;
119
+ }
120
+ /**
121
+ * Windows: wmic 回退方案
122
+ */
123
+ function findProcessesWindowsWmic() {
124
+ const results = [];
125
+ try {
126
+ const output = execSync('wmic process where "name like \'%node%\' or name like \'%claude%\' or name like \'%opencode%\'" get processid,commandline /format:list', { encoding: 'utf8', timeout: 5000, windowsHide: true });
127
+ const lines = output.split('\n');
128
+ let currentPid = null;
129
+ let currentCmd = null;
130
+ for (const line of lines) {
131
+ const trimmed = line.trim();
132
+ if (trimmed.startsWith('CommandLine=')) {
133
+ currentCmd = trimmed.substring('CommandLine='.length);
134
+ }
135
+ else if (trimmed.startsWith('ProcessId=')) {
136
+ currentPid = trimmed.substring('ProcessId='.length);
137
+ }
138
+ if (currentPid && currentCmd) {
139
+ if (isAgentProcess(currentCmd)) {
140
+ const agentId = extractAgentId(currentCmd);
141
+ results.push({
142
+ pid: parseInt(currentPid, 10),
143
+ command: currentCmd,
144
+ agentId,
145
+ });
146
+ }
147
+ currentPid = null;
148
+ currentCmd = null;
149
+ }
150
+ }
151
+ }
152
+ catch (error) {
153
+ log.debug('wmic process query failed:', error);
154
+ }
155
+ return results;
156
+ }
157
+ /**
158
+ * Unix: 使用 ps 查找 Agent 进程
159
+ */
160
+ function findProcessesUnix() {
161
+ const results = [];
162
+ try {
163
+ const output = execSync('ps aux | grep -E "claude|claude-code|opencode" | grep -v grep', { encoding: 'utf8', timeout: 5000 });
164
+ const lines = output.split('\n').filter(l => l.trim());
165
+ for (const line of lines) {
166
+ const parts = line.trim().split(/\s+/);
167
+ if (parts.length >= 2) {
168
+ const pid = parseInt(parts[1], 10);
169
+ const cmd = parts.slice(10).join(' ');
170
+ if (isAgentProcess(cmd)) {
171
+ const agentId = extractAgentId(cmd);
172
+ results.push({
173
+ pid,
174
+ command: cmd,
175
+ agentId,
176
+ });
177
+ }
178
+ }
179
+ }
180
+ }
181
+ catch (error) {
182
+ log.debug('ps process query failed:', error);
183
+ }
184
+ return results;
185
+ }
186
+ /**
187
+ * 检查命令行是否是 Agent 相关进程
188
+ * 包含 Claude Code、OpenCode 等各种 Agent 进程特征
189
+ *
190
+ * @param cmd 命令行
191
+ * @returns 是否匹配
192
+ */
193
+ function isAgentProcess(cmd) {
194
+ if (!cmd)
195
+ return false;
196
+ const lowerCmd = cmd.toLowerCase();
197
+ // Claude Code 相关特征
198
+ if (lowerCmd.includes('claude') ||
199
+ lowerCmd.includes('claude-code') ||
200
+ lowerCmd.includes('@anthropic-ai/claude-code') ||
201
+ lowerCmd.includes('cli.js')) {
202
+ return true;
203
+ }
204
+ // OpenCode 相关特征
205
+ if (lowerCmd.includes('opencode') ||
206
+ lowerCmd.includes('open-code') ||
207
+ lowerCmd.includes('opencode.exe') ||
208
+ lowerCmd.includes('opencode.cmd')) {
209
+ return true;
210
+ }
211
+ // 通用特征:包含 serve --port 模式的 node 进程(OpenCode SDK 的 opencode serve --port)
212
+ if (lowerCmd.includes('serve') && lowerCmd.includes('--port')) {
213
+ return true;
214
+ }
215
+ return false;
216
+ }
217
+ /**
218
+ * 从命令行提取 Agent ID
219
+ *
220
+ * @param cmd 命令行
221
+ * @returns Agent ID 或 undefined
222
+ */
223
+ function extractAgentId(cmd) {
224
+ if (!cmd)
225
+ return undefined;
226
+ // 尝试匹配 AWS_AGENT_ID 环境变量(某些情况下 wmic/PowerShell 会包含环境变量)
227
+ const envMatch = cmd.match(/AWS_AGENT_ID=(\S+)/);
228
+ if (envMatch) {
229
+ return envMatch[1];
230
+ }
231
+ // 尝试匹配 --agent-id 参数
232
+ const argMatch = cmd.match(/--agent-id[=\s]+(\S+)/);
233
+ if (argMatch) {
234
+ return argMatch[1];
235
+ }
236
+ return undefined;
237
+ }
238
+ /**
239
+ * 根据 agentId 查找孤儿进程
240
+ *
241
+ * 检测策略(按优先级):
242
+ * 1. 通过命令行中的 agentId 直接匹配
243
+ * 2. Windows: 通过 PowerShell 在命令行中模糊搜索 agentId
244
+ * 3. Windows: 通过进程树搜索(解决 PTY 场景下 agentId 仅存在于环境变量的问题)
245
+ * PTY 启动链: pty.spawn('powershell.exe', {env: {AWS_AGENT_ID}}) → 用户运行 'claude'
246
+ * 此时 claude 是 powershell 子进程,agentId 仅存在于父进程的环境变量中
247
+ *
248
+ * @param agentId Agent ID
249
+ * @returns 进程信息或 undefined
250
+ */
251
+ export function findOrphanProcessByAgentId(agentId) {
252
+ // 1. 先通过命令行匹配
253
+ const processes = findClaudeCodeProcesses();
254
+ const cmdMatch = processes.find(p => p.agentId === agentId);
255
+ if (cmdMatch)
256
+ return cmdMatch;
257
+ // 2. Windows 特有:在命令行中模糊搜索 agentId
258
+ if (os.platform() === 'win32') {
259
+ const envMatch = findProcessByEnvVarWindows(agentId);
260
+ if (envMatch)
261
+ return envMatch;
262
+ // ★ 3. Windows: 进程树搜索 —— 遍历所有 Agent 进程,
263
+ // 检查其祖先进程中是否有 node(runtime-bridge) → shell 的模式
264
+ const treeMatch = findOrphanByAncestorEnvSearch(agentId);
265
+ if (treeMatch)
266
+ return treeMatch;
267
+ }
268
+ return undefined;
269
+ }
270
+ /**
271
+ * Windows: 通过进程环境变量查找包含 AWS_AGENT_ID 的进程
272
+ *
273
+ * 策略:在所有 node/claude/opencode 进程的命令行中模糊搜索 agentId
274
+ */
275
+ function findProcessByEnvVarWindows(agentId) {
276
+ try {
277
+ const psScript = `$targetId = '${agentId}'; $procs = Get-CimInstance Win32_Process | Where-Object { $_.CommandLine -and ($_.Name -like '*node*' -or $_.Name -like '*claude*' -or $_.Name -like '*opencode*') }; foreach ($proc in $procs) { if ($proc.CommandLine -like "*$targetId*") { @{ProcessId=$proc.ProcessId; CommandLine=$proc.CommandLine; AgentId=$targetId} | ConvertTo-Json -Compress } }`;
278
+ const output = execPowerShell(psScript, 10000);
279
+ if (!output || !output.trim())
280
+ return undefined;
281
+ const lines = output.trim().split('\n').filter(l => l.trim());
282
+ for (const line of lines) {
283
+ try {
284
+ const parsed = JSON.parse(line.trim());
285
+ if (parsed.ProcessId) {
286
+ return {
287
+ pid: parsed.ProcessId,
288
+ command: parsed.CommandLine || '',
289
+ agentId: parsed.AgentId || agentId,
290
+ };
291
+ }
292
+ }
293
+ catch {
294
+ // 跳过无法解析的行
295
+ }
296
+ }
297
+ }
298
+ catch (error) {
299
+ log.debug('PowerShell env var query failed:', error);
300
+ }
301
+ return undefined;
302
+ }
303
+ /**
304
+ * Windows: 通过祖先环境变量搜索孤儿进程(解决 PTY 模式检测问题)
305
+ *
306
+ * 场景说明:
307
+ * PTY 模式启动 Agent 时,runtime-bridge 执行:
308
+ * pty.spawn('powershell.exe', [], { env: { AWS_AGENT_ID: 'agent-xxx' } })
309
+ * 然后用户在 shell 中执行 'claude' 命令,产生如下进程树:
310
+ * node.exe (runtime-bridge, PID=R)
311
+ * └── powershell.exe (PID=A, 有 AWS_AGENT_ID 环境变量)
312
+ * └── claude.exe (PID=B, 无 AWS_AGENT_ID, 命令行含 'claude')
313
+ *
314
+ * 此时:
315
+ * - findProcessesWindows() 能找到 claude.exe,但 extractAgentId() 提取不到 agentId
316
+ * - findProcessByEnvVarWindows() 在命令行中搜不到 agentId(环境变量不在命令行中)
317
+ *
318
+ * 策略:用极简 PowerShell 获取全量进程树数据 → 在 Node.js 层做祖先链匹配
319
+ */
320
+ function findOrphanByAncestorEnvSearch(agentId) {
321
+ try {
322
+ // ★ 极简 PowerShell —— 只做数据采集,不做任何逻辑判断
323
+ const psScript = `Get-CimInstance Win32_Process | Select-Object ProcessId, ParentProcessId, Name, CommandLine | ConvertTo-Json -Compress`;
324
+ const output = execPowerShell(psScript, 15000);
325
+ if (!output || !output.trim())
326
+ return undefined;
327
+ // ★ 所有逻辑在 Node.js 层执行
328
+ return searchOrphanInProcessTree(output.trim(), agentId);
329
+ }
330
+ catch (error) {
331
+ log.debug('[findOrphanByAncestorEnvSearch] Failed:', error);
332
+ }
333
+ return undefined;
334
+ }
335
+ /**
336
+ * 在进程树中搜索孤儿 Agent 进程(纯 Node.js 逻辑)
337
+ *
338
+ * 核心思路:
339
+ * 1. 解析全部 Windows 进程列表
340
+ * 2. 找出所有 Agent 候选进程(claude.exe / opencode.exe / 含特征的 node 进程)
341
+ * 3. 对每个候选向上遍历祖先链
342
+ * 4. 如果祖先链中出现 node(runtime-bridge) → powershell/cmd 的模式 → 判定为孤儿
343
+ */
344
+ function searchOrphanInProcessTree(rawJson, agentId) {
345
+ let allProcs;
346
+ try {
347
+ // ★ 过滤 CLIXML 噪音后再解析 JSON
348
+ const cleaned = rawJson.replace(/#\s*<\s*CLIXML[\s\S]*?(?=\{|\[|$)/g, '').trim();
349
+ const jsonStr = extractJsonFromOutput(cleaned);
350
+ const parsed = JSON.parse(jsonStr);
351
+ allProcs = Array.isArray(parsed) ? parsed : [parsed];
352
+ }
353
+ catch (e) {
354
+ log.debug(`[searchOrphanInProcessTree] JSON parse failed, raw length=${rawJson.length}`, e);
355
+ return undefined;
356
+ }
357
+ if (!allProcs.length)
358
+ return undefined;
359
+ // 构建快速查找表
360
+ const procMap = new Map();
361
+ for (const p of allProcs) {
362
+ if (p.processId) {
363
+ procMap.set(p.processId, p);
364
+ }
365
+ }
366
+ /**
367
+ * 检查进程是否是 Agent 相关进程
368
+ */
369
+ function isCandidate(p) {
370
+ const nameLower = p.name.toLowerCase();
371
+ const cmd = (p.commandLine || '').toLowerCase();
372
+ // Claude Code 进程
373
+ if (nameLower.includes('claude'))
374
+ return true;
375
+ if (cmd.includes('claude') || cmd.includes('@anthropic-ai/claude-code') || cmd.includes('cli.js'))
376
+ return true;
377
+ // OpenCode 进程
378
+ if (nameLower.includes('opencode'))
379
+ return true;
380
+ if (cmd.includes('opencode'))
381
+ return true;
382
+ // serve --port 模式
383
+ if (cmd.includes('serve') && cmd.includes('--port'))
384
+ return true;
385
+ return false;
386
+ }
387
+ /**
388
+ * 检查进程名是否为 Shell 类型
389
+ */
390
+ function isShell(name) {
391
+ const n = name.toLowerCase();
392
+ return n === 'powershell.exe' || n === 'cmd.exe' || n === 'pwsh.exe' || n === 'bash.exe';
393
+ }
394
+ /**
395
+ * 向上追踪祖先链,查找 node(bridge) → shell 的模式
396
+ * ★ 改进:返回匹配的 shell 进程 PID,用于后续 agentId 验证
397
+ */
398
+ function findAncestorShell(pid) {
399
+ let currentPid = pid;
400
+ const maxDepth = 10;
401
+ for (let depth = 0; depth < maxDepth; depth++) {
402
+ const ancestor = procMap.get(currentPid);
403
+ if (!ancestor)
404
+ break;
405
+ // 如果祖先是 shell 进程
406
+ if (isShell(ancestor.name)) {
407
+ // 检查 shell 的父进程是否是 node(runtime-bridge 是 node 进程)
408
+ const shellParent = procMap.get(ancestor.parentProcessId);
409
+ if (shellParent && shellParent.name.toLowerCase() === 'node.exe') {
410
+ const nodeCmd = (shellParent.commandLine || '').toLowerCase();
411
+ // 验证这个 node 是否是 runtime-bridge
412
+ if (nodeCmd.includes('runtime-bridge') || nodeCmd.includes('agentswork')) {
413
+ log.debug(`[searchOrphanInProcessTree] Found bridge ancestor chain: agent(${pid}) -> shell(${ancestor.processId}) -> node(${shellParent.processId})`);
414
+ return { shellPid: ancestor.processId, shellCmd: ancestor.commandLine || '' };
415
+ }
416
+ }
417
+ }
418
+ currentPid = ancestor.parentProcessId;
419
+ if (currentPid <= 0)
420
+ break;
421
+ }
422
+ return null;
423
+ }
424
+ // ★ 策略1:遍历所有进程,找 Agent 候选并检查其祖先链
425
+ // 然后通过 shell 的命令行或环境变量验证 agentId
426
+ for (const proc of allProcs) {
427
+ if (!isCandidate(proc))
428
+ continue;
429
+ const shellInfo = findAncestorShell(proc.processId);
430
+ if (shellInfo) {
431
+ // ★ 验证 agentId:检查 shell 命令行中是否包含目标 agentId
432
+ // PTY 模式下,shell 的命令行中不直接包含 agentId,但可以尝试匹配
433
+ // 如果无法验证,仍然返回(保持向后兼容)
434
+ const shellCmdLower = shellInfo.shellCmd.toLowerCase();
435
+ const cmdLineIncludesAgentId = shellCmdLower.includes(agentId.toLowerCase());
436
+ if (cmdLineIncludesAgentId) {
437
+ log.info(`[searchOrphanInProcessTree] Found orphan by tree search (agentId verified): agentId=${agentId}, pid=${proc.processId}, name=${proc.name}`);
438
+ return {
439
+ pid: proc.processId,
440
+ command: proc.commandLine || '',
441
+ agentId,
442
+ };
443
+ }
444
+ // ★ 如果只有一个候选进程匹配 runtime-bridge 祖先链,直接返回
445
+ // (没有其他 agent 竞争时无需精确验证)
446
+ const allCandidates = allProcs.filter(p => isCandidate(p) && findAncestorShell(p.processId));
447
+ if (allCandidates.length === 1) {
448
+ log.info(`[searchOrphanInProcessTree] Found orphan by tree search (single candidate): agentId=${agentId}, pid=${proc.processId}, name=${proc.name}`);
449
+ return {
450
+ pid: proc.processId,
451
+ command: proc.commandLine || '',
452
+ agentId,
453
+ };
454
+ }
455
+ // 多个候选时,尝试通过进程命令行中的工作目录匹配
456
+ log.debug(`[searchOrphanInProcessTree] Multiple candidates found (${allCandidates.length}), cannot determine which belongs to agentId=${agentId}`);
457
+ }
458
+ }
459
+ // ★ 策略2:宽松搜索 —— 查找所有不在已知会话中的 Agent 候选进程
460
+ // 当进程树断链时(shell 父进程已死,agent 被 reparent),走这个策略
461
+ // 通过直接读取进程的环境变量来验证 agentId
462
+ const candidateWithoutBridge = allProcs.filter(p => isCandidate(p) && !findAncestorShell(p.processId));
463
+ for (const proc of candidateWithoutBridge) {
464
+ // 尝试通过读取进程环境变量来验证 agentId
465
+ const verified = verifyProcessAgentId(proc.processId, agentId);
466
+ if (verified) {
467
+ log.info(`[searchOrphanInProcessTree] Found orphan by env verification: agentId=${agentId}, pid=${proc.processId}, name=${proc.name}`);
468
+ return {
469
+ pid: proc.processId,
470
+ command: proc.commandLine || '',
471
+ agentId,
472
+ };
473
+ }
474
+ }
475
+ return undefined;
476
+ }
477
+ /**
478
+ * 从混合输出中提取 JSON 字符串
479
+ * 处理 CLIXML 噪音、进度信息等 PowerShell 杂讯
480
+ */
481
+ function extractJsonFromOutput(output) {
482
+ // 找到第一个 [ 或 { 开始的位置
483
+ const arrayStart = output.indexOf('[');
484
+ const objStart = output.indexOf('{');
485
+ let start = -1;
486
+ if (arrayStart >= 0 && objStart >= 0) {
487
+ start = Math.min(arrayStart, objStart);
488
+ }
489
+ else if (arrayStart >= 0) {
490
+ start = arrayStart;
491
+ }
492
+ else if (objStart >= 0) {
493
+ start = objStart;
494
+ }
495
+ if (start < 0)
496
+ return output;
497
+ return output.substring(start);
498
+ }
499
+ /**
500
+ * 通过读取进程环境变量来验证 agentId
501
+ *
502
+ * Windows 下无法直接读取其他进程的环境变量,但可以通过以下方式间接验证:
503
+ * 1. 检查进程命令行中是否包含 agentId
504
+ * 2. 检查父进程命令行中是否包含 agentId(PTY 模式下环境变量在父进程)
505
+ * 3. 检查进程的整个祖先链中是否有匹配的 runtime-bridge 启动的 shell
506
+ *
507
+ * @param pid 进程 PID
508
+ * @param targetAgentId 目标 Agent ID
509
+ * @returns 是否匹配
510
+ */
511
+ function verifyProcessAgentId(pid, targetAgentId) {
512
+ try {
513
+ // 策略1:检查进程命令行是否包含 agentId
514
+ const psScript = `
515
+ try {
516
+ $proc = Get-CimInstance Win32_Process -Filter "ProcessId = ${pid}" -ErrorAction SilentlyContinue
517
+ if ($proc -and $proc.CommandLine -like '*${targetAgentId}*') { 'MATCH' } else { 'NOMATCH' }
518
+ } catch { 'ERROR' }
519
+ `;
520
+ const result = execPowerShell(psScript, 5000).trim();
521
+ if (result === 'MATCH')
522
+ return true;
523
+ // 策略2:检查父进程命令行是否包含 agentId(PTY 场景)
524
+ const parentPsScript = `
525
+ try {
526
+ $proc = Get-CimInstance Win32_Process -Filter "ProcessId = ${pid}" -ErrorAction SilentlyContinue
527
+ if ($proc) {
528
+ $parentPid = $proc.ParentProcessId
529
+ $parent = Get-CimInstance Win32_Process -Filter "ProcessId = $parentPid" -ErrorAction SilentlyContinue
530
+ if ($parent -and $parent.CommandLine -like '*${targetAgentId}*') { 'MATCH' } else { 'NOMATCH' }
531
+ } else { 'NOPROC' }
532
+ } catch { 'ERROR' }
533
+ `;
534
+ const parentResult = execPowerShell(parentPsScript, 5000).trim();
535
+ if (parentResult === 'MATCH')
536
+ return true;
537
+ // 策略3:检查祖父进程(node → powershell → claude 三级链中,agentId 在 shell 命令行中)
538
+ const grandParentPsScript = `
539
+ try {
540
+ $proc = Get-CimInstance Win32_Process -Filter "ProcessId = ${pid}" -ErrorAction SilentlyContinue
541
+ if ($proc) {
542
+ $parentPid = $proc.ParentProcessId
543
+ $parent = Get-CimInstance Win32_Process -Filter "ProcessId = $parentPid" -ErrorAction SilentlyContinue
544
+ if ($parent) {
545
+ $grandParentPid = $parent.ParentProcessId
546
+ $grandParent = Get-CimInstance Win32_Process -Filter "ProcessId = $grandParentPid" -ErrorAction SilentlyContinue
547
+ if ($grandParent -and $grandParent.CommandLine -like '*${targetAgentId}*') { 'MATCH' } else { 'NOMATCH' }
548
+ } else { 'NOPARENT' }
549
+ } else { 'NOPROC' }
550
+ } catch { 'ERROR' }
551
+ `;
552
+ const grandParentResult = execPowerShell(grandParentPsScript, 5000).trim();
553
+ return grandParentResult === 'MATCH';
554
+ }
555
+ catch (error) {
556
+ log.debug(`[verifyProcessAgentId] Failed for pid=${pid}, agentId=${targetAgentId}:`, error);
557
+ return false;
558
+ }
559
+ }
560
+ /**
561
+ * 通过工作目录路径查找孤儿进程
562
+ *
563
+ * 当 agentId 无法匹配到进程时,通过工作目录路径做宽泛搜索。
564
+ * 适用于以下场景:
565
+ * - runtime-bridge 重启后持久化会话丢失
566
+ * - PTY 模式下 agentId 仅在环境变量中,命令行搜索不到
567
+ * - 进程树断链,无法通过祖先链匹配
568
+ *
569
+ * @param workspacePath 工作目录路径
570
+ * @returns 匹配的进程信息或 undefined
571
+ */
572
+ export function findOrphanProcessByWorkspace(workspacePath) {
573
+ if (!workspacePath)
574
+ return undefined;
575
+ try {
576
+ const processes = findClaudeCodeProcesses();
577
+ // 在匹配的进程命令行中搜索工作目录路径
578
+ const normalizedPath = workspacePath.replace(/\\/g, '/').toLowerCase();
579
+ for (const proc of processes) {
580
+ const cmdNormalized = proc.command.replace(/\\/g, '/').toLowerCase();
581
+ if (cmdNormalized.includes(normalizedPath)) {
582
+ log.info(`[findOrphanProcessByWorkspace] Found process by workspace: pid=${proc.pid}, workspace=${workspacePath}`);
583
+ return proc;
584
+ }
585
+ }
586
+ // ★ Windows 特有:通过 PowerShell 搜索工作目录匹配的进程
587
+ if (os.platform() === 'win32') {
588
+ const escapedPath = workspacePath.replace(/'/g, "''");
589
+ const psScript = `
590
+ $targetPath = '${escapedPath}'.ToLower().Replace('\\', '/')
591
+ $procs = Get-CimInstance Win32_Process | Where-Object {
592
+ $_.CommandLine -and ($_.Name -like '*node*' -or $_.Name -like '*claude*' -or $_.Name -like '*opencode*')
593
+ }
594
+ foreach ($proc in $procs) {
595
+ $cmdPath = $proc.CommandLine.ToLower().Replace('\\', '/')
596
+ if ($cmdPath -like "*$targetPath*") {
597
+ @{ProcessId=$proc.ProcessId; CommandLine=$proc.CommandLine} | ConvertTo-Json -Compress
598
+ }
599
+ }
600
+ `;
601
+ const output = execPowerShell(psScript, 10000);
602
+ if (output && output.trim()) {
603
+ const lines = output.trim().split('\n').filter(l => l.trim());
604
+ for (const line of lines) {
605
+ try {
606
+ const parsed = JSON.parse(line.trim());
607
+ if (parsed.ProcessId) {
608
+ log.info(`[findOrphanProcessByWorkspace] Found process by PowerShell workspace search: pid=${parsed.ProcessId}`);
609
+ return {
610
+ pid: parsed.ProcessId,
611
+ command: parsed.CommandLine || '',
612
+ };
613
+ }
614
+ }
615
+ catch {
616
+ // 跳过无法解析的行
617
+ }
618
+ }
619
+ }
620
+ }
621
+ }
622
+ catch (error) {
623
+ log.debug('[findOrphanProcessByWorkspace] Failed:', error);
624
+ }
625
+ return undefined;
626
+ }
627
+ /**
628
+ * 根据 PID 终止进程
629
+ *
630
+ * @param pid 进程 ID
631
+ * @returns 是否成功
632
+ */
633
+ export function terminateProcess(pid) {
634
+ try {
635
+ process.kill(pid, 'SIGTERM');
636
+ return true;
637
+ }
638
+ catch (error) {
639
+ log.warn(`Failed to terminate process ${pid}:`, error);
640
+ return false;
641
+ }
642
+ }
643
+ /**
644
+ * 终止进程树(包括所有子进程)
645
+ *
646
+ * 跨平台实现:
647
+ * - Windows: 使用 taskkill /T 终止整个进程树
648
+ * - Unix: 递归获取所有子进程并逐个终止
649
+ *
650
+ * @param pid 进程 ID
651
+ * @returns { terminated: 成功终止的进程数,failed: 失败的进程数 }
652
+ */
653
+ export function terminateProcessTree(pid) {
654
+ const result = { terminated: 0, failed: 0 };
655
+ if (os.platform() === 'win32') {
656
+ // Windows: 使用 taskkill /T /F 终止进程树
657
+ try {
658
+ execSync(`taskkill /PID ${pid} /T /F`, { encoding: 'utf8', timeout: 5000, windowsHide: true });
659
+ result.terminated++;
660
+ log.info(`Terminated process tree for pid=${pid}`);
661
+ }
662
+ catch (error) {
663
+ const err = error;
664
+ log.warn(`Failed to terminate process tree for pid=${pid}:`, err.message);
665
+ result.failed++;
666
+ }
667
+ }
668
+ else {
669
+ // Unix: 递归获取所有子进程并终止
670
+ const childPids = getChildProcesses(pid);
671
+ log.debug(`Found ${childPids.length} child processes for pid=${pid}`);
672
+ // 先终止所有子进程
673
+ for (const childPid of childPids) {
674
+ const childResult = terminateProcessTree(childPid);
675
+ result.terminated += childResult.terminated;
676
+ result.failed += childResult.failed;
677
+ }
678
+ // 然后终止父进程
679
+ if (terminateProcess(pid)) {
680
+ result.terminated++;
681
+ }
682
+ else {
683
+ result.failed++;
684
+ }
685
+ }
686
+ return result;
687
+ }
688
+ /**
689
+ * Unix: 获取进程的所有子进程(递归)
690
+ *
691
+ * @param pid 父进程 ID
692
+ * @returns 子进程 PID 列表
693
+ */
694
+ function getChildProcesses(pid) {
695
+ try {
696
+ const output = execSync(`pgrep -P ${pid}`, { encoding: 'utf8', timeout: 3000 });
697
+ const children = output.trim().split('\n').filter(Boolean).map(Number);
698
+ // 递归获取孙进程
699
+ const allDescendants = [];
700
+ for (const childPid of children) {
701
+ allDescendants.push(childPid);
702
+ allDescendants.push(...getChildProcesses(childPid));
703
+ }
704
+ return allDescendants;
705
+ }
706
+ catch {
707
+ // pgrep 失败(无子进程或命令不存在)
708
+ return [];
709
+ }
710
+ }
711
+ /**
712
+ * 等待进程完全终止(轮询检测)
713
+ *
714
+ * @param pid 进程 ID
715
+ * @param timeoutMs 超时时间(毫秒)
716
+ * @returns 是否成功终止
717
+ */
718
+ export function waitForProcessExit(pid, timeoutMs = 5000) {
719
+ const startTime = Date.now();
720
+ while (Date.now() - startTime < timeoutMs) {
721
+ if (!isProcessRunning(pid)) {
722
+ return true;
723
+ }
724
+ // 等待 100ms 后重试
725
+ const delay = Math.min(100, timeoutMs - (Date.now() - startTime));
726
+ if (delay > 0) {
727
+ try {
728
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, delay);
729
+ }
730
+ catch {
731
+ // SharedArrayBuffer 不可用时回退到 setTimeout
732
+ const startWait = Date.now();
733
+ while (Date.now() - startWait < delay) {
734
+ // 忙等待
735
+ }
736
+ }
737
+ }
738
+ }
739
+ return false;
740
+ }
741
+ /**
742
+ * 检测并收集所有孤儿进程信息
743
+ * 用于 runtime-bridge 启动时恢复控制
744
+ *
745
+ * 改进策略:
746
+ * 1. 检查持久化会话中的 PID 是否仍在运行(使用可靠的 isProcessRunning)
747
+ * 2. PID 存活时,优先从进程列表匹配详细信息,匹配不到则用持久化信息构造
748
+ * 3. 对于没有 PID 的会话,通过 agentId 搜索进程(包括环境变量搜索)
749
+ *
750
+ * @param persistedSessions 持久化的会话列表(包含 PID 信息)
751
+ * @returns 孤儿进程列表
752
+ */
753
+ export function detectOrphanProcesses(persistedSessions) {
754
+ const orphans = [];
755
+ // 1. 首先检查持久化会话中的 PID 是否仍在运行
756
+ for (const session of persistedSessions) {
757
+ if (session.pid && isProcessRunning(session.pid)) {
758
+ // PID 存活,尝试获取详细进程信息
759
+ const processes = findClaudeCodeProcesses();
760
+ const matched = processes.find(p => p.pid === session.pid);
761
+ if (matched) {
762
+ orphans.push({
763
+ agentId: session.agentId,
764
+ process: matched,
765
+ sessionInfo: {
766
+ workspacePath: session.workspacePath,
767
+ command: session.command,
768
+ },
769
+ });
770
+ log.info(`Found orphan process by PID: agentId=${session.agentId}, pid=${session.pid}`);
771
+ }
772
+ else {
773
+ // ★ PID 存活但进程列表匹配不到(可能是命令行特征未被识别)
774
+ // 仍然报告为孤儿进程,用持久化信息构造 ProcessInfo
775
+ orphans.push({
776
+ agentId: session.agentId,
777
+ process: {
778
+ pid: session.pid,
779
+ command: session.command || '(unknown - persisted session)',
780
+ agentId: session.agentId,
781
+ },
782
+ sessionInfo: {
783
+ workspacePath: session.workspacePath,
784
+ command: session.command,
785
+ },
786
+ });
787
+ log.info(`Found orphan process by PID (no cmd match): agentId=${session.agentId}, pid=${session.pid}`);
788
+ }
789
+ }
790
+ }
791
+ // 2. 对于没有 PID 但有 agentId 的会话,尝试通过 agentId 搜索进程
792
+ for (const session of persistedSessions) {
793
+ if (!session.pid && session.agentId) {
794
+ const process = findOrphanProcessByAgentId(session.agentId);
795
+ if (process && !orphans.some(o => o.agentId === session.agentId)) {
796
+ orphans.push({
797
+ agentId: session.agentId,
798
+ process,
799
+ sessionInfo: {
800
+ workspacePath: session.workspacePath,
801
+ command: session.command,
802
+ },
803
+ });
804
+ log.info(`Found orphan process by agentId: agentId=${session.agentId}, pid=${process.pid}`);
805
+ }
806
+ }
807
+ }
808
+ return orphans;
809
+ }
810
+ /**
811
+ * 检测进程健康状态
812
+ *
813
+ * @param pid 进程 ID
814
+ * @param agentId Agent ID
815
+ * @returns 健康状态
816
+ */
817
+ export async function checkProcessHealth(pid, agentId) {
818
+ const status = {
819
+ pid,
820
+ agentId,
821
+ alive: false,
822
+ cpu: 0,
823
+ memoryMB: 0,
824
+ status: 'dead',
825
+ lastUpdate: new Date(),
826
+ };
827
+ try {
828
+ // 检查进程是否存在
829
+ if (!isProcessRunning(pid)) {
830
+ status.status = 'dead';
831
+ log.debug(`Process ${pid} is not running`);
832
+ return status;
833
+ }
834
+ status.alive = true;
835
+ // 获取进程资源使用情况
836
+ const { cpu, memoryMB } = await getProcessResources(pid);
837
+ status.cpu = cpu;
838
+ status.memoryMB = memoryMB;
839
+ // 判断状态
840
+ if (memoryMB > 2048) {
841
+ status.status = 'high_memory';
842
+ }
843
+ else if (cpu > 100) {
844
+ status.status = 'high_cpu';
845
+ }
846
+ else {
847
+ status.status = 'healthy';
848
+ }
849
+ log.debug(`Process ${pid} health: CPU=${cpu}%, Memory=${memoryMB}MB, Status=${status.status}`);
850
+ return status;
851
+ }
852
+ catch (error) {
853
+ log.warn(`Failed to check health for process ${pid}:`, error);
854
+ status.status = 'dead';
855
+ return status;
856
+ }
857
+ }
858
+ /**
859
+ * 获取进程资源使用情况
860
+ *
861
+ * @param pid 进程 ID
862
+ * @returns { cpu: CPU使用率, memoryMB: 内存使用(MB) }
863
+ */
864
+ async function getProcessResources(pid) {
865
+ const platform = os.platform();
866
+ if (platform === 'win32') {
867
+ // Windows: 使用 PowerShell 获取进程资源
868
+ const psScript = `Get-CimInstance Win32_Process -Filter "ProcessId=${pid}" | Select-Object @{Name='CPU';Expression={$_.WorkingSetSize/1MB}}, @{Name='Mem';Expression={$_.WorkingSetSize/1MB}} | ConvertTo-Json -Compress`;
869
+ try {
870
+ const output = execPowerShell(psScript, 5000);
871
+ if (!output || !output.trim()) {
872
+ return { cpu: 0, memoryMB: 0 };
873
+ }
874
+ const parsed = JSON.parse(output);
875
+ // WorkingSetSize 是内存使用
876
+ return {
877
+ cpu: 0, // Windows 难以准确获取 CPU 使用率
878
+ memoryMB: Math.round((parsed.WorkingSetSize || 0) / 1024 / 1024),
879
+ };
880
+ }
881
+ catch {
882
+ return { cpu: 0, memoryMB: 0 };
883
+ }
884
+ }
885
+ else {
886
+ // Unix: 使用 ps 获取资源
887
+ try {
888
+ const output = execSync(`ps -p ${pid} -o %cpu=,rss=`, { encoding: 'utf8', timeout: 5000 });
889
+ const parts = output.trim().split(/\s+/);
890
+ if (parts.length >= 2) {
891
+ return {
892
+ cpu: parseFloat(parts[0]) || 0,
893
+ memoryMB: Math.round(parseInt(parts[1], 10) / 1024), // RSS is KB
894
+ };
895
+ }
896
+ }
897
+ catch {
898
+ return { cpu: 0, memoryMB: 0 };
899
+ }
900
+ }
901
+ return { cpu: 0, memoryMB: 0 };
902
+ }
903
+ /**
904
+ * 批量检测会话健康状态
905
+ *
906
+ * @param sessions 持久化会话列表
907
+ * @returns 健康状态列表
908
+ */
909
+ export async function checkAllSessionsHealth(sessions) {
910
+ const results = new Map();
911
+ const promises = sessions
912
+ .filter(s => s.pid)
913
+ .map(async (session) => {
914
+ // s.pid is guaranteed to exist after filter
915
+ const health = await checkProcessHealth(session.pid, session.agentId);
916
+ results.set(session.agentId, health);
917
+ });
918
+ await Promise.all(promises);
919
+ return results;
920
+ }
921
+ /**
922
+ * 全局发现:扫描机器上所有 Agent 进程,并标注管理状态
923
+ *
924
+ * 返回三类进程:
925
+ * - managed: 在注册表中且进程存活
926
+ * - orphan: 进程存在但不在注册表中(脱离控制)
927
+ * - unknown: 在注册表中但进程已死亡
928
+ *
929
+ * @param managedPids 已知被管理的 PID 集合(来自 ProcessRegistry)
930
+ * @returns 发现的进程列表
931
+ */
932
+ export function discoverAllProcesses(managedPids = new Set(), managedAgentIds = new Set()) {
933
+ const results = [];
934
+ // 1. 扫描机器上所有 Agent 进程
935
+ const allAgentProcesses = findClaudeCodeProcesses();
936
+ for (const proc of allAgentProcesses) {
937
+ const isManaged = managedPids.has(proc.pid);
938
+ const isAgentManaged = proc.agentId ? managedAgentIds.has(proc.agentId) : false;
939
+ results.push({
940
+ ...proc,
941
+ isRunning: true,
942
+ managementStatus: isManaged || isAgentManaged ? 'managed' : 'orphan',
943
+ sessionId: undefined,
944
+ lastSeen: new Date().toISOString(),
945
+ });
946
+ }
947
+ // 2. 找出在注册表中但未被扫描到的进程(可能已死亡)
948
+ // 这部分由调用方(AgentProcessManager)补充
949
+ return results;
950
+ }
951
+ /**
952
+ * 批量发现:扫描所有进程并补充注册表中缺失的进程状态
953
+ *
954
+ * @param registryExport 注册表导出的进程记录(含 agentId, pid)
955
+ * @returns 完整的发现结果
956
+ */
957
+ export function discoverAllProcessesFull(registryExport) {
958
+ const managedPids = new Set(registryExport.map(r => r.pid));
959
+ const managedAgentIds = new Set(registryExport.map(r => r.agentId));
960
+ const agentIdToRecord = new Map(registryExport.map(r => [r.agentId, r]));
961
+ const results = [];
962
+ const seenPids = new Set();
963
+ // 1. 扫描实际运行的进程
964
+ const runningProcesses = findClaudeCodeProcesses();
965
+ for (const proc of runningProcesses) {
966
+ seenPids.add(proc.pid);
967
+ const isManaged = managedPids.has(proc.pid);
968
+ const isAgentManaged = proc.agentId ? managedAgentIds.has(proc.agentId) : false;
969
+ const record = proc.agentId ? agentIdToRecord.get(proc.agentId) : undefined;
970
+ results.push({
971
+ ...proc,
972
+ isRunning: true,
973
+ managementStatus: isManaged || isAgentManaged ? 'managed' : 'orphan',
974
+ sessionId: record ? undefined : undefined,
975
+ lastSeen: new Date().toISOString(),
976
+ });
977
+ }
978
+ // 2. 注册表中存在但进程已死亡的记录
979
+ for (const record of registryExport) {
980
+ if (!seenPids.has(record.pid) && !isProcessRunning(record.pid)) {
981
+ results.push({
982
+ pid: record.pid,
983
+ command: '(process exited)',
984
+ agentId: record.agentId,
985
+ isRunning: false,
986
+ managementStatus: 'unknown',
987
+ lastSeen: undefined,
988
+ });
989
+ }
990
+ }
991
+ return results;
992
+ }