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,1140 @@
1
+ /**
2
+ * Claude Code Agent SDK Adapter
3
+ *
4
+ * 通过 @anthropic-ai/claude-agent-sdk 的 query() API
5
+ * 实现与 Claude Code 的结构化交互。
6
+ *
7
+ * 核心特性:
8
+ * - 支持 autoAccept 模式自动确认所有权限
9
+ * - 支持 AskUserQuestion 拦截并转发到聊天面板
10
+ * - 支持 turn_complete 事件精确判断 AI 就绪状态
11
+ */
12
+ import { EventEmitter } from 'events';
13
+ import { v4 as uuidv4 } from 'uuid';
14
+ import * as fs from 'fs';
15
+ import * as path from 'path';
16
+ import { execSync } from 'child_process';
17
+ import { getToolActionInfo } from './types.js';
18
+ // ============ AsyncIterableQueue ============
19
+ /**
20
+ * 可排队的 AsyncIterable,用于向 SDK query() 输入流推送用户消息
21
+ */
22
+ class AsyncIterableQueue {
23
+ constructor() {
24
+ this.queue = [];
25
+ this.resolve = null;
26
+ this.done = false;
27
+ }
28
+ enqueue(item) {
29
+ if (this.done)
30
+ return;
31
+ if (this.resolve) {
32
+ const r = this.resolve;
33
+ this.resolve = null;
34
+ r({ value: item, done: false });
35
+ }
36
+ else {
37
+ this.queue.push(item);
38
+ }
39
+ }
40
+ close() {
41
+ this.done = true;
42
+ if (this.resolve) {
43
+ const r = this.resolve;
44
+ this.resolve = null;
45
+ r({ value: undefined, done: true });
46
+ }
47
+ }
48
+ [Symbol.asyncIterator]() {
49
+ return {
50
+ next: () => {
51
+ if (this.queue.length > 0) {
52
+ return Promise.resolve({ value: this.queue.shift(), done: false });
53
+ }
54
+ if (this.done) {
55
+ return Promise.resolve({ value: undefined, done: true });
56
+ }
57
+ return new Promise((resolve) => {
58
+ this.resolve = resolve;
59
+ });
60
+ },
61
+ };
62
+ }
63
+ }
64
+ // ============ ClaudeSdkAdapter ============
65
+ /**
66
+ * Claude Code Agent SDK Adapter
67
+ */
68
+ export class ClaudeSdkAdapter extends EventEmitter {
69
+ constructor() {
70
+ super(...arguments);
71
+ this.providerId = 'claude-code';
72
+ this.displayName = 'Claude Code';
73
+ this.sessions = new Map();
74
+ this.sdkQueries = new Map();
75
+ this.inputStreams = new Map();
76
+ this.abortControllers = new Map();
77
+ this.sdkModule = null;
78
+ // 挂起的权限请求
79
+ this.pendingPermissions = new Map();
80
+ // 挂起的 AskUserQuestion
81
+ this.pendingQuestions = new Map();
82
+ // 正在处理的工具调用 ID(用于去重)
83
+ this.activeToolUseIds = new Map(); // sessionId -> toolUseId
84
+ // 最近处理的工具名(用于 stream_event 和 tool_use 的去重)
85
+ this.recentToolNames = new Map(); // sessionId -> { name, time }
86
+ // 收集工具参数的缓冲区(用于 stream_event 模式)
87
+ this.toolInputBuffers = new Map(); // "${sessionId}:${toolUseId}" -> JSON string
88
+ // ============ 空闲命令管理 ============
89
+ this.idleCommands = new Map();
90
+ this.idleTimers = new Map();
91
+ this.lastActivityAt = new Map();
92
+ }
93
+ // ============ 生命周期方法 ============
94
+ async startSession(sessionId, config) {
95
+ // ★ 特征日志:确认使用的是 Claude Code Adapter
96
+ console.log(`[ClaudeSdkAdapter] ★★★ 启动 Claude Code SDK 会话 ★★★ sessionId="${sessionId}", command="${config.command}", workingDirectory="${config.workingDirectory}"`);
97
+ const session = {
98
+ sessionId,
99
+ status: 'starting',
100
+ messages: [],
101
+ createdAt: new Date().toISOString(),
102
+ totalUsage: { inputTokens: 0, outputTokens: 0 },
103
+ };
104
+ this.sessions.set(sessionId, session);
105
+ try {
106
+ const sdk = await this.loadSdk();
107
+ const abortController = new AbortController();
108
+ this.abortControllers.set(sessionId, abortController);
109
+ // 创建输入流
110
+ const inputStream = new AsyncIterableQueue();
111
+ this.inputStreams.set(sessionId, inputStream);
112
+ // 构建选项
113
+ const options = this.buildQueryOptions(sessionId, config, abortController);
114
+ // 启动 SDK query
115
+ const sdkQuery = sdk.query({
116
+ prompt: inputStream,
117
+ options,
118
+ });
119
+ this.sdkQueries.set(sessionId, sdkQuery);
120
+ // 启动流消费(异步,不阻塞)
121
+ this.consumeStream(sessionId, sdkQuery).catch(err => {
122
+ console.error(`[ClaudeSdkAdapter] Stream error for ${sessionId}:`, err);
123
+ });
124
+ // ★ 等待一小段时间让 SDK 进程启动
125
+ await new Promise(resolve => setTimeout(resolve, 100));
126
+ // 发送初始 prompt
127
+ if (config.initialPrompt) {
128
+ // 有初始 prompt,启动后会进入思考状态
129
+ session.status = 'starting';
130
+ this.emit('status-change', sessionId, 'starting');
131
+ const userMsg = {
132
+ id: uuidv4(),
133
+ sessionId,
134
+ role: 'user',
135
+ content: config.initialPrompt,
136
+ timestamp: new Date().toISOString(),
137
+ };
138
+ session.messages.push(userMsg);
139
+ this.emit('conversation-message', sessionId, userMsg);
140
+ // ★ 解析初始 prompt 中的图片标记
141
+ const initialContent = this.parseMessageContent(config.initialPrompt);
142
+ inputStream.enqueue({
143
+ type: 'user',
144
+ message: {
145
+ role: 'user',
146
+ content: initialContent,
147
+ },
148
+ });
149
+ }
150
+ else {
151
+ // 没有初始 prompt,等待用户输入
152
+ session.status = 'waiting_input';
153
+ this.emit('status-change', sessionId, 'waiting_input');
154
+ // 如果有空闲命令配置,立即启动空闲检测
155
+ if (this.idleCommands.has(sessionId)) {
156
+ this.startIdleDetection(sessionId);
157
+ }
158
+ }
159
+ }
160
+ catch (error) {
161
+ const errorMessage = error instanceof Error ? error.message : String(error);
162
+ session.status = 'error';
163
+ this.emit('status-change', sessionId, 'error');
164
+ this.emitEvent(sessionId, {
165
+ type: 'error',
166
+ sessionId,
167
+ timestamp: new Date().toISOString(),
168
+ data: { text: `Failed to start session: ${errorMessage}` },
169
+ });
170
+ throw error;
171
+ }
172
+ }
173
+ async sendMessage(sessionId, message) {
174
+ const session = this.sessions.get(sessionId);
175
+ const inputStream = this.inputStreams.get(sessionId);
176
+ if (!session || !inputStream) {
177
+ throw new Error(`Session ${sessionId} not found`);
178
+ }
179
+ if (session.status === 'error') {
180
+ throw new Error(`Session ${sessionId} is in error state`);
181
+ }
182
+ // 记录用户消息
183
+ const userMsg = {
184
+ id: uuidv4(),
185
+ sessionId,
186
+ role: 'user',
187
+ content: message,
188
+ timestamp: new Date().toISOString(),
189
+ };
190
+ session.messages.push(userMsg);
191
+ this.emit('conversation-message', sessionId, userMsg);
192
+ // 更新状态 - 用户发送消息后,AI 将开始处理
193
+ session.status = 'thinking';
194
+ this.emit('status-change', sessionId, 'thinking');
195
+ // ★ 解析消息中的图片标记,构造多模态内容
196
+ const content = this.parseMessageContent(message);
197
+ // 推送到输入流
198
+ inputStream.enqueue({
199
+ type: 'user',
200
+ message: {
201
+ role: 'user',
202
+ content,
203
+ },
204
+ });
205
+ }
206
+ /**
207
+ * 解析消息内容,提取图片和文本
208
+ * 支持 [图片: url] 标记格式
209
+ */
210
+ parseMessageContent(message) {
211
+ const content = [];
212
+ // 匹配 [图片: url] 格式
213
+ const imageTagRegex = /\[图片\s*:\s*([^\]\n]+?)\s*\]/gi;
214
+ let lastIndex = 0;
215
+ let match = imageTagRegex.exec(message);
216
+ while (match !== null) {
217
+ // 添加图片之前的文本
218
+ if (match.index > lastIndex) {
219
+ const text = message.slice(lastIndex, match.index).trim();
220
+ if (text) {
221
+ content.push({ type: 'text', text });
222
+ }
223
+ }
224
+ // 添加图片
225
+ const imageUrl = match[1].trim();
226
+ if (imageUrl) {
227
+ console.log(`[ClaudeSdkAdapter] 添加图片 URL: ${imageUrl}`);
228
+ content.push({
229
+ type: 'image',
230
+ source: {
231
+ type: 'url',
232
+ url: imageUrl,
233
+ },
234
+ });
235
+ }
236
+ lastIndex = match.index + match[0].length;
237
+ match = imageTagRegex.exec(message);
238
+ }
239
+ // 添加最后的文本
240
+ if (lastIndex < message.length) {
241
+ const text = message.slice(lastIndex).trim();
242
+ if (text) {
243
+ content.push({ type: 'text', text });
244
+ }
245
+ }
246
+ // 如果没有找到任何内容,返回原始消息作为文本
247
+ if (content.length === 0) {
248
+ content.push({ type: 'text', text: message });
249
+ }
250
+ return content;
251
+ }
252
+ async sendConfirmation(sessionId, accept) {
253
+ const pending = this.pendingPermissions.get(sessionId);
254
+ if (pending) {
255
+ if (accept) {
256
+ pending.resolve({ behavior: 'allow', updatedInput: pending.toolInput });
257
+ }
258
+ else {
259
+ pending.resolve({ behavior: 'deny', message: 'User denied' });
260
+ }
261
+ this.pendingPermissions.delete(sessionId);
262
+ }
263
+ }
264
+ async sendQuestionAnswer(sessionId, answers) {
265
+ const pending = this.pendingQuestions.get(sessionId);
266
+ if (!pending)
267
+ return;
268
+ const questions = pending.toolInput.questions;
269
+ let answersText = '用户已回答了您的问题:\n';
270
+ if (Array.isArray(questions)) {
271
+ questions.forEach((q, i) => {
272
+ const key = String(i);
273
+ const answer = answers[key] || answers[q.header || ''] || answers[q.question] || '(未填写)';
274
+ answersText += `• ${q.header || q.question}:${answer}\n`;
275
+ });
276
+ }
277
+ else {
278
+ answersText += JSON.stringify(answers);
279
+ }
280
+ pending.resolve({ behavior: 'deny', message: answersText });
281
+ this.pendingQuestions.delete(sessionId);
282
+ }
283
+ async abortCurrentTurn(sessionId) {
284
+ const abortController = this.abortControllers.get(sessionId);
285
+ if (abortController) {
286
+ abortController.abort();
287
+ }
288
+ }
289
+ async terminateSession(sessionId) {
290
+ const session = this.sessions.get(sessionId);
291
+ const sdkQuery = this.sdkQueries.get(sessionId);
292
+ const inputStream = this.inputStreams.get(sessionId);
293
+ if (inputStream) {
294
+ inputStream.close();
295
+ }
296
+ if (sdkQuery) {
297
+ try {
298
+ sdkQuery.close();
299
+ }
300
+ catch {
301
+ // ignore
302
+ }
303
+ }
304
+ if (session) {
305
+ session.status = 'terminated';
306
+ this.emit('status-change', sessionId, 'terminated');
307
+ this.emitEvent(sessionId, {
308
+ type: 'session_complete',
309
+ sessionId,
310
+ timestamp: new Date().toISOString(),
311
+ data: { exitCode: 0 },
312
+ });
313
+ }
314
+ this.cleanupSession(sessionId);
315
+ }
316
+ getConversation(sessionId) {
317
+ return this.sessions.get(sessionId)?.messages ?? [];
318
+ }
319
+ hasSession(sessionId) {
320
+ return this.sessions.has(sessionId);
321
+ }
322
+ getProviderSessionId(sessionId) {
323
+ return this.sessions.get(sessionId)?.providerSessionId;
324
+ }
325
+ getSessionStatus(sessionId) {
326
+ return this.sessions.get(sessionId)?.status;
327
+ }
328
+ getSessionPid(sessionId) {
329
+ return this.sessions.get(sessionId)?.pid;
330
+ }
331
+ cleanup() {
332
+ for (const sessionId of this.sessions.keys()) {
333
+ try {
334
+ this.terminateSession(sessionId);
335
+ }
336
+ catch {
337
+ // ignore
338
+ }
339
+ }
340
+ this.sessions.clear();
341
+ this.sdkQueries.clear();
342
+ this.inputStreams.clear();
343
+ this.abortControllers.clear();
344
+ this.pendingPermissions.clear();
345
+ this.pendingQuestions.clear();
346
+ this.idleCommands.clear();
347
+ this.idleTimers.clear();
348
+ }
349
+ /**
350
+ * 设置空闲命令配置
351
+ */
352
+ setIdleCommands(sessionId, commands) {
353
+ this.idleCommands.set(sessionId, commands);
354
+ // 如果当前状态是 waiting_input,立即启动空闲检测
355
+ const session = this.sessions.get(sessionId);
356
+ if (session && session.status === 'waiting_input' && (commands.idleInputCommand || commands.nonInputCommand)) {
357
+ this.startIdleDetection(sessionId);
358
+ }
359
+ }
360
+ /**
361
+ * 启动空闲检测定时器
362
+ */
363
+ startIdleDetection(sessionId) {
364
+ // 清除现有定时器
365
+ this.stopIdleDetection(sessionId);
366
+ const commands = this.idleCommands.get(sessionId);
367
+ if (!commands?.idleInputCommand) {
368
+ return;
369
+ }
370
+ if (this.isTaskPollingIdleCommand(commands.idleInputCommand)) {
371
+ return;
372
+ }
373
+ this.lastActivityAt.set(sessionId, Date.now());
374
+ // 每500ms检测一次空闲状态
375
+ const timer = setInterval(() => {
376
+ this.checkIdleState(sessionId);
377
+ }, 500);
378
+ this.idleTimers.set(sessionId, timer);
379
+ }
380
+ /**
381
+ * 停止空闲检测定时器
382
+ */
383
+ stopIdleDetection(sessionId) {
384
+ const timer = this.idleTimers.get(sessionId);
385
+ if (timer) {
386
+ clearInterval(timer);
387
+ this.idleTimers.delete(sessionId);
388
+ }
389
+ }
390
+ /**
391
+ * 检测空闲状态并执行命令
392
+ */
393
+ checkIdleState(sessionId) {
394
+ const session = this.sessions.get(sessionId);
395
+ if (!session || session.status !== 'waiting_input') {
396
+ return;
397
+ }
398
+ const commands = this.idleCommands.get(sessionId);
399
+ if (!commands || (!commands.idleInputCommand && !commands.nonInputCommand)) {
400
+ return;
401
+ }
402
+ const lastActivity = this.lastActivityAt.get(sessionId) || 0;
403
+ const idleTime = Date.now() - lastActivity;
404
+ // 空闲1.5秒后执行空闲命令
405
+ const IDLE_THRESHOLD = 1500;
406
+ if (idleTime < IDLE_THRESHOLD) {
407
+ return;
408
+ }
409
+ // 标记活动时间,避免重复执行
410
+ this.lastActivityAt.set(sessionId, Date.now());
411
+ // SDK 模式:空闲时发送一个简单的提示消息让 AI 调用 poll_message
412
+ // 实际的消息获取由 AI 通过 MCP 工具 poll_message 完成
413
+ if (commands.idleInputCommand) {
414
+ // 解析空闲命令,提取实际要执行的指令
415
+ const command = commands.idleInputCommand;
416
+ // 如果空闲命令包含 poll_message,发送一个提示让 AI 执行
417
+ if (this.isMessagePollingIdleCommand(command)) {
418
+ this.sendIdlePrompt(sessionId, '请使用 poll_message 工具检查是否有新消息,如果有的话处理它们。');
419
+ }
420
+ else {
421
+ // 其他命令,直接作为消息发送给 AI
422
+ this.sendIdlePrompt(sessionId, command);
423
+ }
424
+ }
425
+ }
426
+ /**
427
+ * 发送空闲提示到 SDK
428
+ */
429
+ sendIdlePrompt(sessionId, prompt) {
430
+ const inputStream = this.inputStreams.get(sessionId);
431
+ if (!inputStream)
432
+ return;
433
+ // 更新状态为思考中
434
+ const session = this.sessions.get(sessionId);
435
+ if (session) {
436
+ session.status = 'thinking';
437
+ this.emit('status-change', sessionId, 'thinking');
438
+ }
439
+ // 发送空闲提示
440
+ inputStream.enqueue({
441
+ type: 'user',
442
+ message: {
443
+ role: 'user',
444
+ content: [{ type: 'text', text: prompt }],
445
+ },
446
+ });
447
+ }
448
+ isTaskPollingIdleCommand(command) {
449
+ const normalized = command.trim();
450
+ if (!normalized) {
451
+ return false;
452
+ }
453
+ return normalized.toLowerCase().includes('my_task') || normalized.includes('流程任务');
454
+ }
455
+ isMessagePollingIdleCommand(command) {
456
+ const normalized = command.trim();
457
+ if (!normalized) {
458
+ return false;
459
+ }
460
+ return normalized.toLowerCase().includes('poll_message') || normalized.includes('取消息');
461
+ }
462
+ /**
463
+ * 执行空闲命令(支持 [enter], [wait:n] 等 token)
464
+ */
465
+ async executeIdleCommand(sessionId, command) {
466
+ const inputStream = this.inputStreams.get(sessionId);
467
+ if (!inputStream)
468
+ return;
469
+ // 解析命令 token
470
+ const tokenPattern = /\[(.+?)\]/g;
471
+ let cursor = 0;
472
+ const tokens = [];
473
+ let match = tokenPattern.exec(command);
474
+ while (match !== null) {
475
+ if (match.index > cursor) {
476
+ tokens.push({ type: 'text', value: command.slice(cursor, match.index) });
477
+ }
478
+ const token = match[1];
479
+ if (token.startsWith('wait:')) {
480
+ const seconds = parseFloat(token.slice(5));
481
+ if (!isNaN(seconds)) {
482
+ tokens.push({ type: 'wait', value: seconds * 1000 });
483
+ }
484
+ }
485
+ else {
486
+ // 映射按键 token
487
+ const keyMap = {
488
+ 'enter': '\r',
489
+ 'up': '\x1b[A',
490
+ 'down': '\x1b[B',
491
+ 'left': '\x1b[D',
492
+ 'right': '\x1b[C',
493
+ 'tab': '\t',
494
+ 'esc': '\x1b',
495
+ 'escape': '\x1b',
496
+ 'space': ' ',
497
+ 'ctrl+c': '\x03',
498
+ };
499
+ tokens.push({ type: 'key', value: keyMap[token.toLowerCase()] || token });
500
+ }
501
+ cursor = match.index + match[0].length;
502
+ match = tokenPattern.exec(command);
503
+ }
504
+ if (cursor < command.length) {
505
+ tokens.push({ type: 'text', value: command.slice(cursor) });
506
+ }
507
+ // 执行 tokens
508
+ for (const token of tokens) {
509
+ if (token.type === 'wait') {
510
+ await new Promise(resolve => setTimeout(resolve, token.value));
511
+ }
512
+ else {
513
+ const text = String(token.value);
514
+ inputStream.enqueue({
515
+ type: 'user',
516
+ message: {
517
+ role: 'user',
518
+ content: [{ type: 'text', text }],
519
+ },
520
+ });
521
+ }
522
+ }
523
+ }
524
+ /**
525
+ * 更新活动时间(在收到输出或状态变化时调用)
526
+ */
527
+ updateActivity(sessionId) {
528
+ this.lastActivityAt.set(sessionId, Date.now());
529
+ }
530
+ /**
531
+ * 恢复之前的会话
532
+ * 注意:SDK 的 resume 功能需要 providerSessionId
533
+ */
534
+ async resumeSession(sessionId, providerSessionId, config) {
535
+ // 目前简化实现:重新启动一个新会话
536
+ // TODO: 使用 SDK 的 resume API 恢复会话上下文
537
+ const session = {
538
+ sessionId,
539
+ providerSessionId,
540
+ status: 'starting',
541
+ messages: [],
542
+ createdAt: new Date().toISOString(),
543
+ totalUsage: { inputTokens: 0, outputTokens: 0 },
544
+ };
545
+ this.sessions.set(sessionId, session);
546
+ try {
547
+ await this.startSession(sessionId, config);
548
+ session.providerSessionId = providerSessionId;
549
+ }
550
+ catch (error) {
551
+ session.status = 'error';
552
+ this.emit('status-change', sessionId, 'error');
553
+ throw error;
554
+ }
555
+ }
556
+ // ============ 私有方法 ============
557
+ async loadSdk() {
558
+ if (!this.sdkModule) {
559
+ try {
560
+ this.sdkModule = await import('@anthropic-ai/claude-agent-sdk');
561
+ }
562
+ catch (err) {
563
+ throw new Error(`Failed to load @anthropic-ai/claude-agent-sdk. Please install: npm install @anthropic-ai/claude-agent-sdk. Original error: ${err}`);
564
+ }
565
+ }
566
+ return this.sdkModule;
567
+ }
568
+ /**
569
+ * 查找 Claude Code 可执行文件路径
570
+ * 支持 Windows / macOS / Linux
571
+ */
572
+ findClaudeExecutable(command) {
573
+ const normalizedCommand = (command || 'claude').trim() || 'claude';
574
+ // 1. 如果是绝对路径,直接返回
575
+ if (path.isAbsolute(normalizedCommand) && fs.existsSync(normalizedCommand)) {
576
+ return normalizedCommand;
577
+ }
578
+ // 2. Windows 特定路径(优先级高)
579
+ if (process.platform === 'win32') {
580
+ const userProfile = process.env.USERPROFILE || '';
581
+ const localAppData = process.env.LOCALAPPDATA || '';
582
+ const appData = process.env.APPDATA || '';
583
+ // Volta 安装路径(优先检查)
584
+ const voltaCandidates = [
585
+ path.join(localAppData, 'Volta', 'tools', 'shared', '@anthropic-ai', 'claude-code', 'cli.js'),
586
+ path.join(localAppData, 'Volta', 'tools', 'image', 'packages', '@anthropic-ai', 'claude-code', 'cli.js'),
587
+ ];
588
+ for (const p of voltaCandidates) {
589
+ if (fs.existsSync(p)) {
590
+ console.log(`[ClaudeSdkAdapter] Found Claude Code CLI via Volta: ${p}`);
591
+ return p;
592
+ }
593
+ }
594
+ const candidates = [
595
+ path.join(appData, 'npm', 'node_modules', '@anthropic-ai', 'claude-code', 'cli.js'),
596
+ path.join(localAppData, 'Programs', 'claude-code', 'claude.exe'),
597
+ path.join(userProfile, '.local', 'bin', 'claude.exe'),
598
+ ];
599
+ for (const p of candidates) {
600
+ if (p && fs.existsSync(p)) {
601
+ console.log(`[ClaudeSdkAdapter] Found Claude Code CLI: ${p}`);
602
+ return p;
603
+ }
604
+ }
605
+ }
606
+ // 3. 使用 which/where 查找
607
+ try {
608
+ const findCmd = process.platform === 'win32' ? `where ${normalizedCommand}` : `which ${normalizedCommand}`;
609
+ const result = execSync(findCmd, { encoding: 'utf8', timeout: 5000 }).trim();
610
+ if (result) {
611
+ const foundPath = result.split(/\r?\n/)[0].trim();
612
+ if (fs.existsSync(foundPath)) {
613
+ // 如果是 wrapper 脚本,尝试找到实际的 cli.js
614
+ if (foundPath.endsWith('.cmd') || foundPath.endsWith('.ps1')) {
615
+ const cliJs = this.resolveCliJsFromWrapper(foundPath);
616
+ if (cliJs)
617
+ return cliJs;
618
+ }
619
+ return foundPath;
620
+ }
621
+ }
622
+ }
623
+ catch {
624
+ // 忽略查找失败
625
+ }
626
+ // 4. macOS/Linux 特定路径
627
+ const home = process.env.HOME || '';
628
+ const candidates = [
629
+ `/usr/local/lib/node_modules/@anthropic-ai/claude-code/cli.js`,
630
+ `/usr/lib/node_modules/@anthropic-ai/claude-code/cli.js`,
631
+ path.join(home, '.local', 'share', 'volta', 'tools', 'shared', '@anthropic-ai', 'claude-code', 'cli.js'),
632
+ path.join(home, '.volta', 'tools', 'shared', '@anthropic-ai', 'claude-code', 'cli.js'),
633
+ ];
634
+ for (const p of candidates) {
635
+ if (p && fs.existsSync(p)) {
636
+ console.log(`[ClaudeSdkAdapter] Found Claude Code CLI: ${p}`);
637
+ return p;
638
+ }
639
+ }
640
+ // 5. 尝试 npm root -g
641
+ try {
642
+ const npmRoot = execSync('npm root -g', { encoding: 'utf8', timeout: 5000 }).trim();
643
+ const cliJs = path.join(npmRoot, '@anthropic-ai', 'claude-code', 'cli.js');
644
+ if (fs.existsSync(cliJs)) {
645
+ console.log(`[ClaudeSdkAdapter] Found Claude Code CLI via npm root: ${cliJs}`);
646
+ return cliJs;
647
+ }
648
+ }
649
+ catch {
650
+ // 忽略
651
+ }
652
+ console.warn(`[ClaudeSdkAdapter] Claude Code executable not found for command: ${normalizedCommand}`);
653
+ return undefined;
654
+ }
655
+ /**
656
+ * 从 wrapper 脚本解析 cli.js 路径
657
+ */
658
+ resolveCliJsFromWrapper(wrapperPath) {
659
+ try {
660
+ const content = fs.readFileSync(wrapperPath, 'utf8');
661
+ // Volta wrapper: volta run %~n0 %*
662
+ if (content.includes('volta run')) {
663
+ const voltaShared = path.join(process.env.LOCALAPPDATA || '', 'Volta', 'tools', 'shared', '@anthropic-ai', 'claude-code', 'cli.js');
664
+ if (fs.existsSync(voltaShared)) {
665
+ return voltaShared;
666
+ }
667
+ }
668
+ }
669
+ catch {
670
+ // 忽略
671
+ }
672
+ return undefined;
673
+ }
674
+ buildQueryOptions(sessionId, config, abortController) {
675
+ const options = {
676
+ cwd: config.workingDirectory,
677
+ abortController,
678
+ settingSources: ['user', 'project', 'local'],
679
+ // 启用部分消息以获取增量输出
680
+ includePartialMessages: true,
681
+ };
682
+ // ★ 关键:指定 Claude Code 可执行文件路径
683
+ // SDK 需要这个来启动 Claude Code CLI
684
+ const execPath = this.findClaudeExecutable(config.command);
685
+ if (execPath) {
686
+ options.pathToClaudeCodeExecutable = execPath;
687
+ // ★ 特征日志:明确显示使用的是 Claude Code 可执行文件
688
+ console.log(`[ClaudeSdkAdapter] ★★★ 使用 Claude Code 可执行文件 ★★★ path="${execPath}"`);
689
+ }
690
+ else {
691
+ console.warn(`[ClaudeSdkAdapter] ★★★ 警告:未找到 Claude Code 可执行文件 ★★★ command="${config.command}"`);
692
+ }
693
+ // 模型配置
694
+ if (config.model) {
695
+ options.model = config.model;
696
+ }
697
+ // 最大轮次
698
+ if (config.maxTurns && config.maxTurns > 0) {
699
+ options.maxTurns = config.maxTurns;
700
+ }
701
+ // MCP 服务器
702
+ if (config.mcpConfigPath) {
703
+ try {
704
+ const raw = fs.readFileSync(config.mcpConfigPath, 'utf-8');
705
+ const parsed = JSON.parse(raw);
706
+ options.mcpServers = { ...config.extraMcpServers, ...parsed.mcpServers };
707
+ }
708
+ catch {
709
+ options.mcpServers = config.extraMcpServers || {};
710
+ }
711
+ }
712
+ else {
713
+ options.mcpServers = config.extraMcpServers || {};
714
+ }
715
+ // 允许的工具
716
+ if (config.allowedTools && config.allowedTools.length > 0) {
717
+ options.allowedTools = config.allowedTools;
718
+ }
719
+ else {
720
+ options.allowedTools = [
721
+ 'Read',
722
+ 'Write',
723
+ 'Edit',
724
+ 'Bash',
725
+ 'Glob',
726
+ 'Grep',
727
+ 'WebSearch',
728
+ 'WebFetch',
729
+ 'Task',
730
+ 'NotebookEdit',
731
+ 'LSP',
732
+ 'Skill',
733
+ 'mcp__*',
734
+ ];
735
+ }
736
+ // 环境变量
737
+ options.env = { ...process.env, ...config.envOverrides };
738
+ // 权限模式 - 使用 canUseTool 回调统一处理权限,不使用 bypassPermissions
739
+ // 原因:bypassPermissions 模式下 SDK 可能跳过 canUseTool 回调,
740
+ // 导致 AskUserQuestion 等需要用户交互的工具无法被拦截,前端收不到提问事件。
741
+ // 改为通过 canUseTool 回调实现 autoAccept 逻辑:
742
+ // - AskUserQuestion → 始终拦截,转发到前端等待用户回答
743
+ // - autoAccept 普通工具 → 直接允许
744
+ // - 非 autoAccept 普通工具 → 询问用户
745
+ options.canUseTool = this.createPermissionHandler(sessionId, config.autoAccept);
746
+ return options;
747
+ }
748
+ createPermissionHandler(sessionId, autoAccept) {
749
+ return async (toolName, toolInput, _options) => {
750
+ // AskUserQuestion 特殊处理:始终拦截,转发到前端等待用户回答
751
+ if (toolName === 'AskUserQuestion' || toolName === 'ask_user_question') {
752
+ return new Promise((resolve) => {
753
+ this.pendingQuestions.set(sessionId, { resolve, toolInput });
754
+ this.emit('ask-user-question', {
755
+ sessionId,
756
+ questions: toolInput.questions,
757
+ });
758
+ });
759
+ }
760
+ // autoAccept 模式直接允许普通工具
761
+ // 返回 { behavior: 'allow', updatedInput } 格式
762
+ if (autoAccept) {
763
+ return { behavior: 'allow', updatedInput: toolInput };
764
+ }
765
+ // 非 autoAccept 模式,询问用户
766
+ return new Promise((resolve) => {
767
+ this.pendingPermissions.set(sessionId, { resolve, toolInput });
768
+ this.emit('permission-request', {
769
+ sessionId,
770
+ toolName,
771
+ toolInput,
772
+ permissionPrompt: `Allow ${toolName}?`,
773
+ });
774
+ });
775
+ };
776
+ }
777
+ async consumeStream(sessionId, sdkQuery) {
778
+ const session = this.sessions.get(sessionId);
779
+ if (!session)
780
+ return;
781
+ try {
782
+ for await (const msg of sdkQuery) {
783
+ const sdkMsg = msg;
784
+ this.handleSdkMessage(sessionId, session, sdkMsg);
785
+ }
786
+ }
787
+ catch (error) {
788
+ if (this.abortControllers.get(sessionId)?.signal.aborted) {
789
+ // 主动中止,正常结束
790
+ return;
791
+ }
792
+ const errorMessage = error instanceof Error ? error.message : String(error);
793
+ this.emitEvent(sessionId, {
794
+ type: 'error',
795
+ sessionId,
796
+ timestamp: new Date().toISOString(),
797
+ data: { text: `Stream error: ${errorMessage}` },
798
+ });
799
+ }
800
+ }
801
+ handleSdkMessage(sessionId, session, msg) {
802
+ const timestamp = new Date().toISOString();
803
+ // ★ 调试日志:记录所有收到的消息类型
804
+ console.log(`[ClaudeSdkAdapter] Received message type: "${msg.type}", subtype: "${msg.subtype || ''}"`);
805
+ // ★ 如果有工具名,也记录下来
806
+ if (msg.tool_name) {
807
+ console.log(`[ClaudeSdkAdapter] Tool name: "${msg.tool_name}"`);
808
+ }
809
+ switch (msg.type) {
810
+ case 'text':
811
+ // AI 正在输出文本
812
+ if (msg.delta) {
813
+ // 更新状态为思考中(如果有文本输出)
814
+ if (session.status !== 'thinking') {
815
+ session.status = 'thinking';
816
+ this.emit('status-change', sessionId, 'thinking');
817
+ this.stopIdleDetection(sessionId);
818
+ }
819
+ this.emitEvent(sessionId, {
820
+ type: 'text_delta',
821
+ sessionId,
822
+ timestamp,
823
+ data: { text: msg.delta },
824
+ });
825
+ }
826
+ break;
827
+ case 'thinking':
828
+ // AI 正在思考/推理
829
+ if (session.status !== 'thinking') {
830
+ session.status = 'thinking';
831
+ this.emit('status-change', sessionId, 'thinking');
832
+ this.stopIdleDetection(sessionId);
833
+ }
834
+ if (msg.content || msg.delta) {
835
+ this.emitEvent(sessionId, {
836
+ type: 'thinking',
837
+ sessionId,
838
+ timestamp,
839
+ data: { text: msg.delta || msg.content },
840
+ });
841
+ }
842
+ break;
843
+ case 'tool_use':
844
+ case 'tool_use_start':
845
+ // AI 正在调用工具
846
+ {
847
+ const actionInfo = getToolActionInfo(msg.tool_name, msg.tool_input);
848
+ session.status = 'tool_using';
849
+ this.emit('status-change', sessionId, 'tool_using', {
850
+ actionType: actionInfo.actionType,
851
+ actionLabel: actionInfo.actionLabel,
852
+ actionDetail: actionInfo.actionDetail,
853
+ });
854
+ this.stopIdleDetection(sessionId);
855
+ this.handleToolUse(sessionId, session, msg, timestamp);
856
+ }
857
+ break;
858
+ case 'tool_result':
859
+ case 'tool_use_end':
860
+ this.emitEvent(sessionId, {
861
+ type: 'tool_use_end',
862
+ sessionId,
863
+ timestamp,
864
+ data: {
865
+ toolName: msg.tool_name,
866
+ toolResult: msg.tool_result,
867
+ isError: msg.is_error,
868
+ toolUseId: msg.tool_use_id,
869
+ },
870
+ });
871
+ break;
872
+ case 'result':
873
+ // ★ SDK 的 turn_complete 事件是 'result' 类型
874
+ {
875
+ const isSuccess = msg.subtype === 'success';
876
+ if (msg.usage) {
877
+ session.totalUsage.inputTokens = msg.usage.input_tokens || session.totalUsage.inputTokens;
878
+ session.totalUsage.outputTokens = msg.usage.output_tokens || session.totalUsage.outputTokens;
879
+ }
880
+ // 发送 turn_complete 事件
881
+ this.emitEvent(sessionId, {
882
+ type: 'turn_complete',
883
+ sessionId,
884
+ timestamp,
885
+ data: {
886
+ usage: session.totalUsage,
887
+ text: isSuccess ? msg.result : undefined,
888
+ },
889
+ });
890
+ // ★ 更新状态为等待输入
891
+ session.status = 'waiting_input';
892
+ this.emit('status-change', sessionId, 'waiting_input');
893
+ // 如果有空闲命令配置,启动空闲检测
894
+ if (this.idleCommands.has(sessionId)) {
895
+ this.startIdleDetection(sessionId);
896
+ }
897
+ }
898
+ break;
899
+ case 'system':
900
+ // 系统消息,可能包含初始化数据
901
+ if (msg.subtype === 'init') {
902
+ console.log(`[ClaudeSdkAdapter] Session ${sessionId} initialized: model=${msg.model}, tools=${msg.tools?.length || 0}`);
903
+ }
904
+ break;
905
+ case 'assistant':
906
+ // AI 响应完成,可能包含完整消息
907
+ if (msg.message?.content) {
908
+ const textContent = msg.message.content
909
+ .filter((c) => c.type === 'text' && c.text)
910
+ .map((c) => c.text || '')
911
+ .join('');
912
+ if (textContent) {
913
+ session.messages.push({
914
+ id: uuidv4(),
915
+ sessionId,
916
+ role: 'assistant',
917
+ content: textContent,
918
+ timestamp,
919
+ });
920
+ }
921
+ }
922
+ break;
923
+ case 'user':
924
+ // 用户消息(工具结果)
925
+ if (msg.tool_use_result !== undefined) {
926
+ // 工具执行结果
927
+ }
928
+ break;
929
+ case 'error':
930
+ session.status = 'error';
931
+ this.emit('status-change', sessionId, 'error');
932
+ this.emitEvent(sessionId, {
933
+ type: 'error',
934
+ sessionId,
935
+ timestamp,
936
+ data: { text: msg.content || 'Unknown error' },
937
+ });
938
+ break;
939
+ case 'stream_event':
940
+ // SDK 流式事件 - 处理工具调用的增量更新
941
+ this.handleStreamEvent(sessionId, session, msg, timestamp);
942
+ break;
943
+ default:
944
+ // 未知消息类型,记录日志
945
+ console.log(`[ClaudeSdkAdapter] Unknown message type: ${msg.type}`, msg);
946
+ }
947
+ }
948
+ handleToolUse(sessionId, session, msg, timestamp) {
949
+ // 检查是否与 stream_event 处理的工具调用匹配(去重)
950
+ const recentInfo = this.recentToolNames.get(sessionId);
951
+ const toolNameSuffix = this.extractToolNameSuffix(msg.tool_name || '');
952
+ if (recentInfo) {
953
+ const timeDiff = Date.now() - recentInfo.time;
954
+ // 如果在 30s 内,且工具名后缀相同,认为是同一个调用(content_block_stop 已发出事件)
955
+ if (timeDiff < 30000 && recentInfo.name === toolNameSuffix) {
956
+ console.log(`[ClaudeSdkAdapter] Tool use ${msg.tool_name} matches recent stream_event (${recentInfo.name}), skipping duplicate event`);
957
+ // 清理记录
958
+ this.recentToolNames.delete(sessionId);
959
+ this.activeToolUseIds.delete(sessionId);
960
+ // 只记录到消息历史,不重复发送事件(content_block_stop 已经发过)
961
+ session.messages.push({
962
+ id: uuidv4(),
963
+ sessionId,
964
+ role: 'tool_use',
965
+ content: `${msg.tool_name}: ${JSON.stringify(msg.tool_input).slice(0, 100)}`,
966
+ timestamp,
967
+ toolName: msg.tool_name,
968
+ toolInput: msg.tool_input,
969
+ toolUseId: msg.tool_use_id,
970
+ });
971
+ return;
972
+ }
973
+ }
974
+ // 清理过期记录
975
+ this.recentToolNames.delete(sessionId);
976
+ this.activeToolUseIds.delete(sessionId);
977
+ // 获取工具动作分类信息
978
+ const actionInfo = getToolActionInfo(msg.tool_name, msg.tool_input);
979
+ console.log(`[ClaudeSdkAdapter] Tool use: ${msg.tool_name}, actionType: ${actionInfo.actionType}, actionDetail: ${actionInfo.actionDetail}`);
980
+ this.emitEvent(sessionId, {
981
+ type: 'tool_use_start',
982
+ sessionId,
983
+ timestamp,
984
+ data: {
985
+ toolName: msg.tool_name,
986
+ toolInput: msg.tool_input,
987
+ toolUseId: msg.tool_use_id,
988
+ actionType: actionInfo.actionType,
989
+ actionLabel: actionInfo.actionLabel,
990
+ actionDetail: actionInfo.actionDetail,
991
+ },
992
+ });
993
+ // 记录到消息历史
994
+ session.messages.push({
995
+ id: uuidv4(),
996
+ sessionId,
997
+ role: 'tool_use',
998
+ content: `${msg.tool_name}: ${JSON.stringify(msg.tool_input).slice(0, 100)}`,
999
+ timestamp,
1000
+ toolName: msg.tool_name,
1001
+ toolInput: msg.tool_input,
1002
+ toolUseId: msg.tool_use_id,
1003
+ });
1004
+ }
1005
+ /**
1006
+ * 处理 SDK 流式事件
1007
+ * 用于检测工具调用开始、增量更新和结束
1008
+ *
1009
+ * 注意:此方法只更新状态,不发送时间线事件
1010
+ * 时间线事件由 handleToolUse 发送,这样能获取完整的工具参数
1011
+ */
1012
+ handleStreamEvent(sessionId, session, msg, timestamp) {
1013
+ const event = msg.event;
1014
+ if (!event)
1015
+ return;
1016
+ // 处理 content_block_start 事件 - 工具调用开始
1017
+ if (event.type === 'content_block_start') {
1018
+ const contentBlock = event.content_block;
1019
+ if (contentBlock?.type === 'tool_use' && contentBlock.name) {
1020
+ const toolName = contentBlock.name;
1021
+ const toolId = contentBlock.id || `stream_${Date.now()}`;
1022
+ console.log(`[ClaudeSdkAdapter] Tool use started via stream_event: ${toolName} (id: ${toolId})`);
1023
+ // 记录当前活跃的工具调用 ID(用于去重)
1024
+ this.activeToolUseIds.set(sessionId, toolId);
1025
+ // 记录工具名(用于与后续 tool_use 消息匹配去重)
1026
+ // 提取工具名后缀:aws-mcp__get_profile -> get_profile
1027
+ const toolNameSuffix = this.extractToolNameSuffix(toolName);
1028
+ this.recentToolNames.set(sessionId, { name: toolNameSuffix, time: Date.now() });
1029
+ // 初始化参数缓冲区
1030
+ const bufferKey = `${sessionId}:${toolId}`;
1031
+ this.toolInputBuffers.set(bufferKey, '');
1032
+ // 先不更新状态,等待收集参数后更新
1033
+ }
1034
+ }
1035
+ // 处理 content_block_delta 事件 - 收集工具参数增量
1036
+ if (event.type === 'content_block_delta') {
1037
+ if (event.delta?.type === 'input_json_delta' && event.delta.partial_json) {
1038
+ const toolId = this.activeToolUseIds.get(sessionId);
1039
+ if (toolId) {
1040
+ const bufferKey = `${sessionId}:${toolId}`;
1041
+ const currentBuffer = this.toolInputBuffers.get(bufferKey) || '';
1042
+ this.toolInputBuffers.set(bufferKey, currentBuffer + event.delta.partial_json);
1043
+ console.log(`[ClaudeSdkAdapter] Tool input delta at index ${event.index}, buffer length: ${currentBuffer.length + event.delta.partial_json.length}`);
1044
+ }
1045
+ }
1046
+ }
1047
+ // 处理 content_block_stop 事件 - 工具调用参数收集完成
1048
+ if (event.type === 'content_block_stop') {
1049
+ const toolId = this.activeToolUseIds.get(sessionId);
1050
+ const recentInfo = this.recentToolNames.get(sessionId);
1051
+ if (toolId && recentInfo) {
1052
+ const bufferKey = `${sessionId}:${toolId}`;
1053
+ const jsonStr = this.toolInputBuffers.get(bufferKey) || '';
1054
+ console.log(`[ClaudeSdkAdapter] Content block stopped at index ${event.index}, collected JSON length: ${jsonStr.length}`);
1055
+ // 尝试解析完整的工具参数
1056
+ let toolInput;
1057
+ if (jsonStr) {
1058
+ try {
1059
+ toolInput = JSON.parse(jsonStr);
1060
+ console.log(`[ClaudeSdkAdapter] Parsed tool input:`, JSON.stringify(toolInput).slice(0, 200));
1061
+ }
1062
+ catch (e) {
1063
+ console.warn(`[ClaudeSdkAdapter] Failed to parse tool input JSON:`, jsonStr.slice(0, 100));
1064
+ }
1065
+ }
1066
+ // 获取工具动作分类信息(使用完整参数)
1067
+ const actionInfo = getToolActionInfo(recentInfo.name, toolInput);
1068
+ // 更新状态
1069
+ session.status = 'tool_using';
1070
+ this.emit('status-change', sessionId, 'tool_using', {
1071
+ actionType: actionInfo.actionType,
1072
+ actionLabel: actionInfo.actionLabel,
1073
+ actionDetail: actionInfo.actionDetail,
1074
+ });
1075
+ this.stopIdleDetection(sessionId);
1076
+ // 发送工具调用开始事件(此时有完整参数)
1077
+ this.emitEvent(sessionId, {
1078
+ type: 'tool_use_start',
1079
+ sessionId,
1080
+ timestamp,
1081
+ data: {
1082
+ toolName: recentInfo.name,
1083
+ toolInput,
1084
+ toolUseId: toolId,
1085
+ actionType: actionInfo.actionType,
1086
+ actionLabel: actionInfo.actionLabel,
1087
+ actionDetail: actionInfo.actionDetail,
1088
+ },
1089
+ });
1090
+ // 记录到消息历史
1091
+ session.messages.push({
1092
+ id: uuidv4(),
1093
+ sessionId,
1094
+ role: 'tool_use',
1095
+ content: `${recentInfo.name}: ${jsonStr.slice(0, 100)}`,
1096
+ timestamp,
1097
+ toolName: recentInfo.name,
1098
+ toolInput,
1099
+ toolUseId: toolId,
1100
+ });
1101
+ // 清理缓冲区(保留 recentToolNames 用于后续 tool_use 消息去重)
1102
+ this.toolInputBuffers.delete(bufferKey);
1103
+ this.activeToolUseIds.delete(sessionId);
1104
+ // 注意:不在此处删除 recentToolNames,让后续 tool_use 消息能匹配去重
1105
+ // recentToolNames 会在 handleToolUse 中匹配成功后删除,或过期后自动清理
1106
+ }
1107
+ }
1108
+ }
1109
+ /**
1110
+ * 提取工具名后缀
1111
+ * 用于匹配不同格式的工具名
1112
+ * 例如:aws-mcp__get_profile -> get_profile
1113
+ */
1114
+ extractToolNameSuffix(toolName) {
1115
+ // 如果包含 __,取最后一部分
1116
+ if (toolName.includes('__')) {
1117
+ return toolName.split('__').pop() || toolName;
1118
+ }
1119
+ // 如果包含 -mcp__,取后面的部分
1120
+ if (toolName.includes('-mcp__')) {
1121
+ const idx = toolName.indexOf('-mcp__');
1122
+ return toolName.substring(idx + 6);
1123
+ }
1124
+ return toolName;
1125
+ }
1126
+ emitEvent(sessionId, event) {
1127
+ this.emit('event', event);
1128
+ }
1129
+ cleanupSession(sessionId) {
1130
+ this.stopIdleDetection(sessionId);
1131
+ this.sessions.delete(sessionId);
1132
+ this.sdkQueries.delete(sessionId);
1133
+ this.inputStreams.delete(sessionId);
1134
+ this.abortControllers.delete(sessionId);
1135
+ this.pendingPermissions.delete(sessionId);
1136
+ this.pendingQuestions.delete(sessionId);
1137
+ this.idleCommands.delete(sessionId);
1138
+ this.lastActivityAt.delete(sessionId);
1139
+ }
1140
+ }