synapse-mcp 1.0.0 → 1.0.2

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 (413) hide show
  1. package/README.md +1820 -147
  2. package/dist/constants.d.ts +10 -4
  3. package/dist/constants.d.ts.map +1 -1
  4. package/dist/constants.js +18 -8
  5. package/dist/constants.js.map +1 -1
  6. package/dist/events/emitter.d.ts +63 -0
  7. package/dist/events/emitter.d.ts.map +1 -0
  8. package/dist/events/emitter.js +112 -0
  9. package/dist/events/emitter.js.map +1 -0
  10. package/dist/events/index.d.ts +3 -0
  11. package/dist/events/index.d.ts.map +1 -0
  12. package/dist/events/index.js +3 -0
  13. package/dist/events/index.js.map +1 -0
  14. package/dist/events/types.d.ts +51 -0
  15. package/dist/events/types.d.ts.map +1 -0
  16. package/dist/events/types.js +3 -0
  17. package/dist/events/types.js.map +1 -0
  18. package/dist/formatters/compose.d.ts +185 -0
  19. package/dist/formatters/compose.d.ts.map +1 -0
  20. package/dist/formatters/compose.js +397 -0
  21. package/dist/formatters/compose.js.map +1 -0
  22. package/dist/formatters/container.d.ts +84 -0
  23. package/dist/formatters/container.d.ts.map +1 -0
  24. package/dist/formatters/container.js +323 -0
  25. package/dist/formatters/container.js.map +1 -0
  26. package/dist/formatters/diagnostics.d.ts +20 -0
  27. package/dist/formatters/diagnostics.d.ts.map +1 -0
  28. package/dist/formatters/diagnostics.js +73 -0
  29. package/dist/formatters/diagnostics.js.map +1 -0
  30. package/dist/formatters/docker.d.ts +139 -0
  31. package/dist/formatters/docker.d.ts.map +1 -0
  32. package/dist/formatters/docker.js +216 -0
  33. package/dist/formatters/docker.js.map +1 -0
  34. package/dist/formatters/host.d.ts +137 -0
  35. package/dist/formatters/host.d.ts.map +1 -0
  36. package/dist/formatters/host.js +198 -0
  37. package/dist/formatters/host.js.map +1 -0
  38. package/dist/formatters/index.d.ts +17 -270
  39. package/dist/formatters/index.d.ts.map +1 -1
  40. package/dist/formatters/index.js +21 -456
  41. package/dist/formatters/index.js.map +1 -1
  42. package/dist/formatters/scout.d.ts +424 -0
  43. package/dist/formatters/scout.d.ts.map +1 -0
  44. package/dist/formatters/scout.js +687 -0
  45. package/dist/formatters/scout.js.map +1 -0
  46. package/dist/formatters/strategy.d.ts +105 -0
  47. package/dist/formatters/strategy.d.ts.map +1 -0
  48. package/dist/formatters/strategy.js +120 -0
  49. package/dist/formatters/strategy.js.map +1 -0
  50. package/dist/formatters/utils.d.ts +84 -0
  51. package/dist/formatters/utils.d.ts.map +1 -0
  52. package/dist/formatters/utils.js +129 -0
  53. package/dist/formatters/utils.js.map +1 -0
  54. package/dist/health-rate-limiter.d.ts +59 -0
  55. package/dist/health-rate-limiter.d.ts.map +1 -0
  56. package/dist/health-rate-limiter.js +159 -0
  57. package/dist/health-rate-limiter.js.map +1 -0
  58. package/dist/index.js +61 -100
  59. package/dist/index.js.map +1 -1
  60. package/dist/middleware/async-handler.d.ts +62 -0
  61. package/dist/middleware/async-handler.d.ts.map +1 -0
  62. package/dist/middleware/async-handler.js +58 -0
  63. package/dist/middleware/async-handler.js.map +1 -0
  64. package/dist/middleware/auth.d.ts +32 -0
  65. package/dist/middleware/auth.d.ts.map +1 -0
  66. package/dist/middleware/auth.js +63 -0
  67. package/dist/middleware/auth.js.map +1 -0
  68. package/dist/middleware/csrf-protection.d.ts +58 -0
  69. package/dist/middleware/csrf-protection.d.ts.map +1 -0
  70. package/dist/middleware/csrf-protection.js +123 -0
  71. package/dist/middleware/csrf-protection.js.map +1 -0
  72. package/dist/middleware/error-handler.d.ts +49 -0
  73. package/dist/middleware/error-handler.d.ts.map +1 -0
  74. package/dist/middleware/error-handler.js +90 -0
  75. package/dist/middleware/error-handler.js.map +1 -0
  76. package/dist/middleware/error-mapper.d.ts +44 -0
  77. package/dist/middleware/error-mapper.d.ts.map +1 -0
  78. package/dist/middleware/error-mapper.js +127 -0
  79. package/dist/middleware/error-mapper.js.map +1 -0
  80. package/dist/middleware/index.d.ts +13 -0
  81. package/dist/middleware/index.d.ts.map +1 -0
  82. package/dist/middleware/index.js +13 -0
  83. package/dist/middleware/index.js.map +1 -0
  84. package/dist/middleware/request-id.d.ts +22 -0
  85. package/dist/middleware/request-id.d.ts.map +1 -0
  86. package/dist/middleware/request-id.js +31 -0
  87. package/dist/middleware/request-id.js.map +1 -0
  88. package/dist/middleware/types.d.ts +33 -0
  89. package/dist/middleware/types.d.ts.map +1 -0
  90. package/dist/middleware/types.js +2 -0
  91. package/dist/middleware/types.js.map +1 -0
  92. package/dist/schemas/common.d.ts +205 -8
  93. package/dist/schemas/common.d.ts.map +1 -1
  94. package/dist/schemas/common.js +290 -17
  95. package/dist/schemas/common.js.map +1 -1
  96. package/dist/schemas/flux/compose.d.ts +307 -44
  97. package/dist/schemas/flux/compose.d.ts.map +1 -1
  98. package/dist/schemas/flux/compose.js +74 -48
  99. package/dist/schemas/flux/compose.js.map +1 -1
  100. package/dist/schemas/flux/container.d.ts +423 -56
  101. package/dist/schemas/flux/container.d.ts.map +1 -1
  102. package/dist/schemas/flux/container.js +83 -61
  103. package/dist/schemas/flux/container.js.map +1 -1
  104. package/dist/schemas/flux/docker.d.ts +254 -37
  105. package/dist/schemas/flux/docker.d.ts.map +1 -1
  106. package/dist/schemas/flux/docker.js +69 -39
  107. package/dist/schemas/flux/docker.js.map +1 -1
  108. package/dist/schemas/flux/host.d.ts +312 -29
  109. package/dist/schemas/flux/host.d.ts.map +1 -1
  110. package/dist/schemas/flux/host.js +74 -31
  111. package/dist/schemas/flux/host.js.map +1 -1
  112. package/dist/schemas/flux/index.d.ts +503 -11
  113. package/dist/schemas/flux/index.d.ts.map +1 -1
  114. package/dist/schemas/flux/index.js +34 -70
  115. package/dist/schemas/flux/index.js.map +1 -1
  116. package/dist/schemas/host-config.d.ts +76 -0
  117. package/dist/schemas/host-config.d.ts.map +1 -0
  118. package/dist/schemas/host-config.js +105 -0
  119. package/dist/schemas/host-config.js.map +1 -0
  120. package/dist/schemas/scout/index.d.ts +80 -23
  121. package/dist/schemas/scout/index.d.ts.map +1 -1
  122. package/dist/schemas/scout/index.js +26 -11
  123. package/dist/schemas/scout/index.js.map +1 -1
  124. package/dist/schemas/scout/logs.d.ts +17 -5
  125. package/dist/schemas/scout/logs.d.ts.map +1 -1
  126. package/dist/schemas/scout/logs.js +41 -31
  127. package/dist/schemas/scout/logs.js.map +1 -1
  128. package/dist/schemas/scout/simple.d.ts +126 -11
  129. package/dist/schemas/scout/simple.d.ts.map +1 -1
  130. package/dist/schemas/scout/simple.js +112 -57
  131. package/dist/schemas/scout/simple.js.map +1 -1
  132. package/dist/schemas/scout/zfs.d.ts +17 -5
  133. package/dist/schemas/scout/zfs.d.ts.map +1 -1
  134. package/dist/schemas/scout/zfs.js +34 -25
  135. package/dist/schemas/scout/zfs.js.map +1 -1
  136. package/dist/services/cache-layer.d.ts +160 -0
  137. package/dist/services/cache-layer.d.ts.map +1 -0
  138. package/dist/services/cache-layer.js +138 -0
  139. package/dist/services/cache-layer.js.map +1 -0
  140. package/dist/services/compose-cache.d.ts +75 -0
  141. package/dist/services/compose-cache.d.ts.map +1 -0
  142. package/dist/services/compose-cache.js +178 -0
  143. package/dist/services/compose-cache.js.map +1 -0
  144. package/dist/services/compose-discovery.d.ts +46 -0
  145. package/dist/services/compose-discovery.d.ts.map +1 -0
  146. package/dist/services/compose-discovery.js +219 -0
  147. package/dist/services/compose-discovery.js.map +1 -0
  148. package/dist/services/compose-project-lister.d.ts +27 -0
  149. package/dist/services/compose-project-lister.d.ts.map +1 -0
  150. package/dist/services/compose-project-lister.js +71 -0
  151. package/dist/services/compose-project-lister.js.map +1 -0
  152. package/dist/services/compose-scanner.d.ts +63 -0
  153. package/dist/services/compose-scanner.d.ts.map +1 -0
  154. package/dist/services/compose-scanner.js +253 -0
  155. package/dist/services/compose-scanner.js.map +1 -0
  156. package/dist/services/compose.d.ts +64 -28
  157. package/dist/services/compose.d.ts.map +1 -1
  158. package/dist/services/compose.js +220 -98
  159. package/dist/services/compose.js.map +1 -1
  160. package/dist/services/config-loader.d.ts +23 -0
  161. package/dist/services/config-loader.d.ts.map +1 -0
  162. package/dist/services/config-loader.js +124 -0
  163. package/dist/services/config-loader.js.map +1 -0
  164. package/dist/services/config-service.d.ts +38 -0
  165. package/dist/services/config-service.d.ts.map +1 -0
  166. package/dist/services/config-service.js +225 -0
  167. package/dist/services/config-service.js.map +1 -0
  168. package/dist/services/container-host-map-cache.d.ts +121 -0
  169. package/dist/services/container-host-map-cache.d.ts.map +1 -0
  170. package/dist/services/container-host-map-cache.js +188 -0
  171. package/dist/services/container-host-map-cache.js.map +1 -0
  172. package/dist/services/container.d.ts +194 -6
  173. package/dist/services/container.d.ts.map +1 -1
  174. package/dist/services/container.js +386 -11
  175. package/dist/services/container.js.map +1 -1
  176. package/dist/services/diagnostics.d.ts +57 -0
  177. package/dist/services/diagnostics.d.ts.map +1 -0
  178. package/dist/services/diagnostics.js +271 -0
  179. package/dist/services/diagnostics.js.map +1 -0
  180. package/dist/services/docker/container-service.d.ts +123 -0
  181. package/dist/services/docker/container-service.d.ts.map +1 -0
  182. package/dist/services/docker/container-service.js +347 -0
  183. package/dist/services/docker/container-service.js.map +1 -0
  184. package/dist/services/docker/image-service.d.ts +82 -0
  185. package/dist/services/docker/image-service.d.ts.map +1 -0
  186. package/dist/services/docker/image-service.js +193 -0
  187. package/dist/services/docker/image-service.js.map +1 -0
  188. package/dist/services/docker/index.d.ts +80 -0
  189. package/dist/services/docker/index.d.ts.map +1 -0
  190. package/dist/services/docker/index.js +103 -0
  191. package/dist/services/docker/index.js.map +1 -0
  192. package/dist/services/docker/network-service.d.ts +22 -0
  193. package/dist/services/docker/network-service.d.ts.map +1 -0
  194. package/dist/services/docker/network-service.js +43 -0
  195. package/dist/services/docker/network-service.js.map +1 -0
  196. package/dist/services/docker/system-service.d.ts +49 -0
  197. package/dist/services/docker/system-service.d.ts.map +1 -0
  198. package/dist/services/docker/system-service.js +215 -0
  199. package/dist/services/docker/system-service.js.map +1 -0
  200. package/dist/services/docker/utils/client-factory.d.ts +56 -0
  201. package/dist/services/docker/utils/client-factory.d.ts.map +1 -0
  202. package/dist/services/docker/utils/client-factory.js +139 -0
  203. package/dist/services/docker/utils/client-factory.js.map +1 -0
  204. package/dist/services/docker/utils/client-manager.d.ts +88 -0
  205. package/dist/services/docker/utils/client-manager.d.ts.map +1 -0
  206. package/dist/services/docker/utils/client-manager.js +124 -0
  207. package/dist/services/docker/utils/client-manager.js.map +1 -0
  208. package/dist/services/docker/utils/exec-handler.d.ts +94 -0
  209. package/dist/services/docker/utils/exec-handler.d.ts.map +1 -0
  210. package/dist/services/docker/utils/exec-handler.js +197 -0
  211. package/dist/services/docker/utils/exec-handler.js.map +1 -0
  212. package/dist/services/docker/utils/formatters.d.ts +13 -0
  213. package/dist/services/docker/utils/formatters.d.ts.map +1 -0
  214. package/dist/services/docker/utils/formatters.js +33 -0
  215. package/dist/services/docker/utils/formatters.js.map +1 -0
  216. package/dist/services/docker/utils/log-parser.d.ts +10 -0
  217. package/dist/services/docker/utils/log-parser.d.ts.map +1 -0
  218. package/dist/services/docker/utils/log-parser.js +48 -0
  219. package/dist/services/docker/utils/log-parser.js.map +1 -0
  220. package/dist/services/docker/utils/stats-calculator.d.ts +68 -0
  221. package/dist/services/docker/utils/stats-calculator.d.ts.map +1 -0
  222. package/dist/services/docker/utils/stats-calculator.js +61 -0
  223. package/dist/services/docker/utils/stats-calculator.js.map +1 -0
  224. package/dist/services/docker/volume-service.d.ts +22 -0
  225. package/dist/services/docker/volume-service.d.ts.map +1 -0
  226. package/dist/services/docker/volume-service.js +48 -0
  227. package/dist/services/docker/volume-service.js.map +1 -0
  228. package/dist/services/docker-interfaces.d.ts +283 -0
  229. package/dist/services/docker-interfaces.d.ts.map +1 -0
  230. package/dist/services/docker-interfaces.js +13 -0
  231. package/dist/services/docker-interfaces.js.map +1 -0
  232. package/dist/services/docker.d.ts +42 -5
  233. package/dist/services/docker.d.ts.map +1 -1
  234. package/dist/services/docker.js +335 -127
  235. package/dist/services/docker.js.map +1 -1
  236. package/dist/services/file-service.d.ts +6 -2
  237. package/dist/services/file-service.d.ts.map +1 -1
  238. package/dist/services/file-service.js +156 -52
  239. package/dist/services/file-service.js.map +1 -1
  240. package/dist/services/host-config-repository.d.ts +133 -0
  241. package/dist/services/host-config-repository.d.ts.map +1 -0
  242. package/dist/services/host-config-repository.js +323 -0
  243. package/dist/services/host-config-repository.js.map +1 -0
  244. package/dist/services/host-resolver.d.ts +49 -0
  245. package/dist/services/host-resolver.d.ts.map +1 -0
  246. package/dist/services/host-resolver.js +176 -0
  247. package/dist/services/host-resolver.js.map +1 -0
  248. package/dist/services/interfaces.d.ts +61 -194
  249. package/dist/services/interfaces.d.ts.map +1 -1
  250. package/dist/services/local-executor.d.ts +31 -0
  251. package/dist/services/local-executor.d.ts.map +1 -0
  252. package/dist/services/local-executor.js +71 -0
  253. package/dist/services/local-executor.js.map +1 -0
  254. package/dist/services/ssh-config-loader.d.ts +35 -0
  255. package/dist/services/ssh-config-loader.d.ts.map +1 -0
  256. package/dist/services/ssh-config-loader.js +218 -0
  257. package/dist/services/ssh-config-loader.js.map +1 -0
  258. package/dist/services/ssh-pool.d.ts +26 -1
  259. package/dist/services/ssh-pool.d.ts.map +1 -1
  260. package/dist/services/ssh-pool.js +166 -25
  261. package/dist/services/ssh-pool.js.map +1 -1
  262. package/dist/services/ssh-service.d.ts +3 -0
  263. package/dist/services/ssh-service.d.ts.map +1 -1
  264. package/dist/services/ssh-service.js +53 -31
  265. package/dist/services/ssh-service.js.map +1 -1
  266. package/dist/services/ssh.d.ts +2 -6
  267. package/dist/services/ssh.d.ts.map +1 -1
  268. package/dist/services/ssh.js +9 -40
  269. package/dist/services/ssh.js.map +1 -1
  270. package/dist/tools/definitions/flux.d.ts +13 -0
  271. package/dist/tools/definitions/flux.d.ts.map +1 -0
  272. package/dist/tools/definitions/flux.js +101 -0
  273. package/dist/tools/definitions/flux.js.map +1 -0
  274. package/dist/tools/definitions/index.d.ts +8 -0
  275. package/dist/tools/definitions/index.d.ts.map +1 -0
  276. package/dist/tools/definitions/index.js +8 -0
  277. package/dist/tools/definitions/index.js.map +1 -0
  278. package/dist/tools/definitions/scout.d.ts +13 -0
  279. package/dist/tools/definitions/scout.d.ts.map +1 -0
  280. package/dist/tools/definitions/scout.js +78 -0
  281. package/dist/tools/definitions/scout.js.map +1 -0
  282. package/dist/tools/flux.d.ts +16 -8
  283. package/dist/tools/flux.d.ts.map +1 -1
  284. package/dist/tools/flux.js +27 -66
  285. package/dist/tools/flux.js.map +1 -1
  286. package/dist/tools/handlers/base-handler.d.ts +172 -0
  287. package/dist/tools/handlers/base-handler.d.ts.map +1 -0
  288. package/dist/tools/handlers/base-handler.js +234 -0
  289. package/dist/tools/handlers/base-handler.js.map +1 -0
  290. package/dist/tools/handlers/compose-handlers.d.ts +108 -0
  291. package/dist/tools/handlers/compose-handlers.d.ts.map +1 -0
  292. package/dist/tools/handlers/compose-handlers.js +293 -0
  293. package/dist/tools/handlers/compose-handlers.js.map +1 -0
  294. package/dist/tools/handlers/compose-utils.d.ts +35 -0
  295. package/dist/tools/handlers/compose-utils.d.ts.map +1 -0
  296. package/dist/tools/handlers/compose-utils.js +76 -0
  297. package/dist/tools/handlers/compose-utils.js.map +1 -0
  298. package/dist/tools/handlers/compose.d.ts +23 -0
  299. package/dist/tools/handlers/compose.d.ts.map +1 -0
  300. package/dist/tools/handlers/compose.js +125 -0
  301. package/dist/tools/handlers/compose.js.map +1 -0
  302. package/dist/tools/handlers/container.d.ts +23 -0
  303. package/dist/tools/handlers/container.d.ts.map +1 -0
  304. package/dist/tools/handlers/container.js +333 -0
  305. package/dist/tools/handlers/container.js.map +1 -0
  306. package/dist/tools/handlers/docker.d.ts +24 -0
  307. package/dist/tools/handlers/docker.d.ts.map +1 -0
  308. package/dist/tools/handlers/docker.js +155 -0
  309. package/dist/tools/handlers/docker.js.map +1 -0
  310. package/dist/tools/handlers/host.d.ts +23 -0
  311. package/dist/tools/handlers/host.d.ts.map +1 -0
  312. package/dist/tools/handlers/host.js +196 -0
  313. package/dist/tools/handlers/host.js.map +1 -0
  314. package/dist/tools/handlers/scout-logs.d.ts +24 -0
  315. package/dist/tools/handlers/scout-logs.d.ts.map +1 -0
  316. package/dist/tools/handlers/scout-logs.js +119 -0
  317. package/dist/tools/handlers/scout-logs.js.map +1 -0
  318. package/dist/tools/handlers/scout-simple.d.ts +23 -0
  319. package/dist/tools/handlers/scout-simple.d.ts.map +1 -0
  320. package/dist/tools/handlers/scout-simple.js +286 -0
  321. package/dist/tools/handlers/scout-simple.js.map +1 -0
  322. package/dist/tools/handlers/scout-zfs.d.ts +23 -0
  323. package/dist/tools/handlers/scout-zfs.d.ts.map +1 -0
  324. package/dist/tools/handlers/scout-zfs.js +82 -0
  325. package/dist/tools/handlers/scout-zfs.js.map +1 -0
  326. package/dist/tools/index.d.ts +32 -2
  327. package/dist/tools/index.d.ts.map +1 -1
  328. package/dist/tools/index.js +41 -35
  329. package/dist/tools/index.js.map +1 -1
  330. package/dist/tools/registry.d.ts +135 -0
  331. package/dist/tools/registry.d.ts.map +1 -0
  332. package/dist/tools/registry.js +151 -0
  333. package/dist/tools/registry.js.map +1 -0
  334. package/dist/tools/scout.d.ts +16 -8
  335. package/dist/tools/scout.d.ts.map +1 -1
  336. package/dist/tools/scout.js +36 -78
  337. package/dist/tools/scout.js.map +1 -1
  338. package/dist/types.d.ts +629 -1
  339. package/dist/types.d.ts.map +1 -1
  340. package/dist/types.js.map +1 -1
  341. package/dist/utils/command-security.d.ts +82 -0
  342. package/dist/utils/command-security.d.ts.map +1 -0
  343. package/dist/utils/command-security.js +122 -0
  344. package/dist/utils/command-security.js.map +1 -0
  345. package/dist/utils/error-sanitization.d.ts +77 -0
  346. package/dist/utils/error-sanitization.d.ts.map +1 -0
  347. package/dist/utils/error-sanitization.js +107 -0
  348. package/dist/utils/error-sanitization.js.map +1 -0
  349. package/dist/utils/errors.d.ts +30 -6
  350. package/dist/utils/errors.d.ts.map +1 -1
  351. package/dist/utils/errors.js +91 -12
  352. package/dist/utils/errors.js.map +1 -1
  353. package/dist/utils/help-handler.d.ts +23 -0
  354. package/dist/utils/help-handler.d.ts.map +1 -0
  355. package/dist/utils/help-handler.js +21 -0
  356. package/dist/utils/help-handler.js.map +1 -0
  357. package/dist/utils/help.d.ts +1 -1
  358. package/dist/utils/help.d.ts.map +1 -1
  359. package/dist/utils/help.js +57 -16
  360. package/dist/utils/help.js.map +1 -1
  361. package/dist/utils/host-utils.d.ts +31 -0
  362. package/dist/utils/host-utils.d.ts.map +1 -0
  363. package/dist/utils/host-utils.js +80 -0
  364. package/dist/utils/host-utils.js.map +1 -0
  365. package/dist/utils/index.d.ts +8 -2
  366. package/dist/utils/index.d.ts.map +1 -1
  367. package/dist/utils/index.js +8 -2
  368. package/dist/utils/index.js.map +1 -1
  369. package/dist/utils/init-detection.d.ts +36 -0
  370. package/dist/utils/init-detection.d.ts.map +1 -0
  371. package/dist/utils/init-detection.js +79 -0
  372. package/dist/utils/init-detection.js.map +1 -0
  373. package/dist/utils/logger.d.ts +11 -0
  374. package/dist/utils/logger.d.ts.map +1 -0
  375. package/dist/utils/logger.js +32 -0
  376. package/dist/utils/logger.js.map +1 -0
  377. package/dist/utils/pagination.d.ts +20 -0
  378. package/dist/utils/pagination.d.ts.map +1 -0
  379. package/dist/utils/pagination.js +29 -0
  380. package/dist/utils/pagination.js.map +1 -0
  381. package/dist/utils/path-security.d.ts +132 -18
  382. package/dist/utils/path-security.d.ts.map +1 -1
  383. package/dist/utils/path-security.js +164 -35
  384. package/dist/utils/path-security.js.map +1 -1
  385. package/dist/utils/sorting.d.ts +33 -0
  386. package/dist/utils/sorting.d.ts.map +1 -0
  387. package/dist/utils/sorting.js +57 -0
  388. package/dist/utils/sorting.js.map +1 -0
  389. package/dist/utils/text-filters.d.ts +13 -0
  390. package/dist/utils/text-filters.d.ts.map +1 -0
  391. package/dist/utils/text-filters.js +18 -0
  392. package/dist/utils/text-filters.js.map +1 -0
  393. package/dist/utils/time.d.ts +11 -0
  394. package/dist/utils/time.d.ts.map +1 -0
  395. package/dist/utils/time.js +13 -0
  396. package/dist/utils/time.js.map +1 -0
  397. package/dist/utils/validation.d.ts +25 -0
  398. package/dist/utils/validation.d.ts.map +1 -0
  399. package/dist/utils/validation.js +56 -0
  400. package/dist/utils/validation.js.map +1 -0
  401. package/package.json +45 -19
  402. package/dist/schemas/discriminator.d.ts +0 -20
  403. package/dist/schemas/discriminator.d.ts.map +0 -1
  404. package/dist/schemas/discriminator.js +0 -25
  405. package/dist/schemas/discriminator.js.map +0 -1
  406. package/dist/schemas/unified.d.ts +0 -674
  407. package/dist/schemas/unified.d.ts.map +0 -1
  408. package/dist/schemas/unified.js +0 -453
  409. package/dist/schemas/unified.js.map +0 -1
  410. package/dist/tools/unified.d.ts +0 -7
  411. package/dist/tools/unified.d.ts.map +0 -1
  412. package/dist/tools/unified.js +0 -827
  413. package/dist/tools/unified.js.map +0 -1
@@ -0,0 +1,219 @@
1
+ import { DEFAULT_COMPOSE_SCAN_CONCURRENCY } from "../constants.js";
2
+ import { logError } from "../utils/errors.js";
3
+ import { getCurrentTimestamp } from "../utils/time.js";
4
+ const DEFAULT_SEARCH_PATHS = ["/compose", "/mnt/cache/compose", "/mnt/cache/code"];
5
+ export class ComposeDiscovery {
6
+ projectLister;
7
+ cache;
8
+ scanner;
9
+ /**
10
+ * In-flight filesystem scan promises keyed by host name.
11
+ * Coalesces concurrent scan requests for the same host into a single scan,
12
+ * preventing redundant filesystem operations (200-1000ms each).
13
+ */
14
+ inflightScans = new Map();
15
+ constructor(projectLister, cache, // Public for cache invalidation in handlers
16
+ scanner) {
17
+ this.projectLister = projectLister;
18
+ this.cache = cache;
19
+ this.scanner = scanner;
20
+ }
21
+ getSearchPaths(host, cachedPaths) {
22
+ const paths = new Set();
23
+ // Add default paths
24
+ for (const p of DEFAULT_SEARCH_PATHS) {
25
+ paths.add(p);
26
+ }
27
+ // Add cached paths
28
+ for (const p of cachedPaths) {
29
+ paths.add(p);
30
+ }
31
+ // Add user-configured paths
32
+ if (host.composeSearchPaths) {
33
+ for (const p of host.composeSearchPaths) {
34
+ paths.add(p);
35
+ }
36
+ }
37
+ return Array.from(paths);
38
+ }
39
+ async discoverFromDockerLs(host, projectName) {
40
+ try {
41
+ const projects = await this.projectLister.listComposeProjects(host);
42
+ const found = projects.find((p) => p.name === projectName);
43
+ if (found && found.configFiles.length > 0) {
44
+ return {
45
+ path: found.configFiles[0],
46
+ name: projectName,
47
+ discoveredFrom: "docker-ls",
48
+ lastSeen: getCurrentTimestamp(),
49
+ };
50
+ }
51
+ }
52
+ catch (error) {
53
+ logError(error, {
54
+ operation: "discoverFromDockerLs",
55
+ metadata: { host: host.name, project: projectName },
56
+ });
57
+ }
58
+ return null;
59
+ }
60
+ /**
61
+ * Scan a host's filesystem for compose projects, coalescing concurrent requests.
62
+ * If a scan is already in flight for this host, returns the existing promise.
63
+ *
64
+ * @param host - Host to scan
65
+ * @returns Array of discovered projects with name and path
66
+ */
67
+ async scanHostFilesystem(host) {
68
+ const existing = this.inflightScans.get(host.name);
69
+ if (existing) {
70
+ return existing;
71
+ }
72
+ const scanPromise = (async () => {
73
+ try {
74
+ const cacheData = await this.cache.load(host.name);
75
+ const searchPaths = this.getSearchPaths(host, cacheData.searchPaths);
76
+ const hostWithSearchPaths = {
77
+ ...host,
78
+ composeSearchPaths: searchPaths,
79
+ };
80
+ const files = await this.scanner.findComposeFiles(hostWithSearchPaths);
81
+ const nameMap = await this.scanner.batchParseComposeNames(host, files, DEFAULT_COMPOSE_SCAN_CONCURRENCY);
82
+ return files.map((file) => {
83
+ const dirName = this.scanner.extractProjectName(file);
84
+ const explicitName = nameMap.get(file);
85
+ const name = explicitName ?? dirName;
86
+ return { name, path: file };
87
+ });
88
+ }
89
+ finally {
90
+ this.inflightScans.delete(host.name);
91
+ }
92
+ })();
93
+ this.inflightScans.set(host.name, scanPromise);
94
+ return scanPromise;
95
+ }
96
+ async discoverFromFilesystem(host, projectName) {
97
+ try {
98
+ const projects = await this.scanHostFilesystem(host);
99
+ // Cache all discovered projects to avoid future scans
100
+ for (const project of projects) {
101
+ await this.cache.updateProject(host.name, project.name, {
102
+ path: project.path,
103
+ name: project.name,
104
+ discoveredFrom: "scan",
105
+ lastSeen: getCurrentTimestamp(),
106
+ });
107
+ }
108
+ const found = projects.find((p) => p.name === projectName);
109
+ if (found) {
110
+ return {
111
+ path: found.path,
112
+ name: found.name,
113
+ discoveredFrom: "scan",
114
+ lastSeen: getCurrentTimestamp(),
115
+ };
116
+ }
117
+ }
118
+ catch (error) {
119
+ logError(error, {
120
+ operation: "discoverFromFilesystem",
121
+ metadata: { host: host.name, project: projectName },
122
+ });
123
+ }
124
+ return null;
125
+ }
126
+ /**
127
+ * Resolve compose file path for a project
128
+ * Strategy:
129
+ * 1. Check cache (trust it - lazy invalidation at handler level)
130
+ * 2. Check docker compose ls (running projects) - FAST
131
+ * 3. Scan filesystem if not found - SLOWER
132
+ * 4. Error if not found
133
+ */
134
+ async resolveProjectPath(host, projectName) {
135
+ // Step 1: Check cache (no validation - lazy invalidation)
136
+ const cached = await this.cache.getProject(host.name, projectName);
137
+ if (cached) {
138
+ return cached.path;
139
+ }
140
+ // Step 2: Try docker ls first (fast, authoritative for running projects)
141
+ const dockerLsResult = await this.discoverFromDockerLs(host, projectName);
142
+ if (dockerLsResult) {
143
+ await this.cache.updateProject(host.name, projectName, dockerLsResult);
144
+ return dockerLsResult.path;
145
+ }
146
+ // Step 3: Fallback to filesystem scan (slower, but finds stopped projects)
147
+ const scanResult = await this.discoverFromFilesystem(host, projectName);
148
+ if (scanResult) {
149
+ await this.cache.updateProject(host.name, projectName, scanResult);
150
+ return scanResult.path;
151
+ }
152
+ // Step 4: Not found
153
+ const cacheData = await this.cache.load(host.name);
154
+ const searchPaths = cacheData.searchPaths.length > 0 ? cacheData.searchPaths : DEFAULT_SEARCH_PATHS;
155
+ throw new Error(`Project '${projectName}' not found on host '${host.name}'\nSearched locations: ${searchPaths.join(", ")}\nTip: Provide compose_file parameter if project is in a different location`);
156
+ }
157
+ /**
158
+ * Warm cache by discovering all projects on a host in the background.
159
+ * This mitigates cold-start penalty (200-1000ms) on first compose operation.
160
+ * Call this on server startup or after cache invalidation.
161
+ *
162
+ * @param host - Host to warm cache for
163
+ */
164
+ async warmCache(host) {
165
+ // Phase 1: Discover from docker ls (fast, finds running projects)
166
+ try {
167
+ const runningProjects = await this.projectLister.listComposeProjects(host);
168
+ // Cache all running projects
169
+ for (const project of runningProjects) {
170
+ if (project.configFiles.length > 0) {
171
+ await this.cache.updateProject(host.name, project.name, {
172
+ path: project.configFiles[0],
173
+ name: project.name,
174
+ discoveredFrom: "docker-ls",
175
+ lastSeen: getCurrentTimestamp(),
176
+ });
177
+ }
178
+ }
179
+ }
180
+ catch (error) {
181
+ // Non-fatal: docker-ls failure should not prevent filesystem scan
182
+ logError(error, {
183
+ operation: "warmCache:docker-ls",
184
+ metadata: { host: host.name },
185
+ });
186
+ }
187
+ // Phase 2: Discover from filesystem (slower, finds stopped projects)
188
+ try {
189
+ const cacheData = await this.cache.load(host.name);
190
+ const searchPaths = this.getSearchPaths(host, cacheData.searchPaths);
191
+ const hostWithSearchPaths = { ...host, composeSearchPaths: searchPaths };
192
+ const files = await this.scanner.findComposeFiles(hostWithSearchPaths);
193
+ const nameMap = await this.scanner.batchParseComposeNames(host, files, DEFAULT_COMPOSE_SCAN_CONCURRENCY);
194
+ const projects = files.map((file) => {
195
+ const dirName = this.scanner.extractProjectName(file);
196
+ const explicitName = nameMap.get(file);
197
+ const name = explicitName ?? dirName;
198
+ return { name, path: file };
199
+ });
200
+ // Cache all discovered projects
201
+ for (const project of projects) {
202
+ await this.cache.updateProject(host.name, project.name, {
203
+ path: project.path,
204
+ name: project.name,
205
+ discoveredFrom: "scan",
206
+ lastSeen: getCurrentTimestamp(),
207
+ });
208
+ }
209
+ }
210
+ catch (error) {
211
+ // Non-fatal: filesystem scan failure is best-effort
212
+ logError(error, {
213
+ operation: "warmCache:filesystem-scan",
214
+ metadata: { host: host.name },
215
+ });
216
+ }
217
+ }
218
+ }
219
+ //# sourceMappingURL=compose-discovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compose-discovery.js","sourceRoot":"","sources":["../../src/services/compose-discovery.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import type { ComposeProject, HostConfig } from "../types.js";
2
+ import type { IComposeProjectLister, ILocalExecutorService, ISSHService } from "./interfaces.js";
3
+ /**
4
+ * Standalone service for listing Docker Compose projects on hosts.
5
+ *
6
+ * Extracted from ComposeService to break the circular dependency:
7
+ * ComposeService <-> ComposeDiscovery
8
+ *
9
+ * Before: ComposeService implemented both IComposeService and IComposeProjectLister,
10
+ * requiring setter injection to wire ComposeDiscovery as its path resolver.
11
+ *
12
+ * After: ComposeProjectLister implements IComposeProjectLister independently,
13
+ * allowing a clean dependency chain:
14
+ * ComposeProjectLister -> ComposeDiscovery -> ComposeService
15
+ * (no cycle, no setter injection)
16
+ */
17
+ export declare class ComposeProjectLister implements IComposeProjectLister {
18
+ private sshService;
19
+ private localExecutor;
20
+ constructor(sshService: ISSHService, localExecutor: ILocalExecutorService);
21
+ /**
22
+ * List all compose projects on a host (local or remote)
23
+ * via `docker compose ls --format json`.
24
+ */
25
+ listComposeProjects(host: HostConfig): Promise<ComposeProject[]>;
26
+ }
27
+ //# sourceMappingURL=compose-project-lister.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compose-project-lister.d.ts","sourceRoot":"","sources":["../../src/services/compose-project-lister.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAI9D,OAAO,KAAK,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAGjG;;;;;;;;;;;;;GAaG;AACH,qBAAa,oBAAqB,YAAW,qBAAqB;IAE9D,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,aAAa;gBADb,UAAU,EAAE,WAAW,EACvB,aAAa,EAAE,qBAAqB;IAG9C;;;OAGG;IACG,mBAAmB,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;CA0DvE"}
@@ -0,0 +1,71 @@
1
+ import { ComposeOperationError } from "../utils/errors.js";
2
+ import { isLocalHost } from "../utils/host-utils.js";
3
+ import { parseComposeStatus } from "./compose.js";
4
+ import { validateHostForSsh } from "./ssh.js";
5
+ /**
6
+ * Standalone service for listing Docker Compose projects on hosts.
7
+ *
8
+ * Extracted from ComposeService to break the circular dependency:
9
+ * ComposeService <-> ComposeDiscovery
10
+ *
11
+ * Before: ComposeService implemented both IComposeService and IComposeProjectLister,
12
+ * requiring setter injection to wire ComposeDiscovery as its path resolver.
13
+ *
14
+ * After: ComposeProjectLister implements IComposeProjectLister independently,
15
+ * allowing a clean dependency chain:
16
+ * ComposeProjectLister -> ComposeDiscovery -> ComposeService
17
+ * (no cycle, no setter injection)
18
+ */
19
+ export class ComposeProjectLister {
20
+ sshService;
21
+ localExecutor;
22
+ constructor(sshService, localExecutor) {
23
+ this.sshService = sshService;
24
+ this.localExecutor = localExecutor;
25
+ }
26
+ /**
27
+ * List all compose projects on a host (local or remote)
28
+ * via `docker compose ls --format json`.
29
+ */
30
+ async listComposeProjects(host) {
31
+ const args = ["--format", "json"];
32
+ try {
33
+ let stdout;
34
+ if (isLocalHost(host)) {
35
+ stdout = await this.localExecutor.executeLocalCommand("docker", ["compose", "ls", ...args], { timeoutMs: 15000 });
36
+ }
37
+ else {
38
+ validateHostForSsh(host);
39
+ const command = `docker compose ls ${args.join(" ")}`;
40
+ stdout = await this.sshService.executeSSHCommand(host, command, [], {
41
+ timeoutMs: 15000,
42
+ });
43
+ }
44
+ if (!stdout.trim()) {
45
+ return [];
46
+ }
47
+ const projects = JSON.parse(stdout);
48
+ return projects.map((p) => {
49
+ if (!p.ConfigFiles) {
50
+ return {
51
+ name: p.Name,
52
+ status: parseComposeStatus(p.Status),
53
+ configFiles: [],
54
+ services: [],
55
+ };
56
+ }
57
+ return {
58
+ name: p.Name,
59
+ status: parseComposeStatus(p.Status),
60
+ configFiles: p.ConfigFiles.split(",").map((f) => f.trim()),
61
+ services: [],
62
+ };
63
+ });
64
+ }
65
+ catch (error) {
66
+ const detail = error instanceof Error ? error.message : "Unknown error";
67
+ throw new ComposeOperationError(`Failed to list compose projects: ${detail}`, host.name, "*", "ls", error);
68
+ }
69
+ }
70
+ }
71
+ //# sourceMappingURL=compose-project-lister.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compose-project-lister.js","sourceRoot":"","sources":["../../src/services/compose-project-lister.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAElD,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAE9C;;;;;;;;;;;;;GAaG;AACH,MAAM,OAAO,oBAAoB;IAErB;IACA;IAFV,YACU,UAAuB,EACvB,aAAoC;QADpC,eAAU,GAAV,UAAU,CAAa;QACvB,kBAAa,GAAb,aAAa,CAAuB;IAC3C,CAAC;IAEJ;;;OAGG;IACH,KAAK,CAAC,mBAAmB,CAAC,IAAgB;QACxC,MAAM,IAAI,GAAG,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;QAElC,IAAI,CAAC;YACH,IAAI,MAAc,CAAC;YAEnB,IAAI,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;gBACtB,MAAM,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,mBAAmB,CACnD,QAAQ,EACR,CAAC,SAAS,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC,EAC1B,EAAE,SAAS,EAAE,KAAK,EAAE,CACrB,CAAC;YACJ,CAAC;iBAAM,CAAC;gBACN,kBAAkB,CAAC,IAAI,CAAC,CAAC;gBACzB,MAAM,OAAO,GAAG,qBAAqB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;gBACtD,MAAM,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,iBAAiB,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE;oBAClE,SAAS,EAAE,KAAK;iBACjB,CAAC,CAAC;YACL,CAAC;YAED,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;gBACnB,OAAO,EAAE,CAAC;YACZ,CAAC;YAED,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAIhC,CAAC;YAEH,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;gBACxB,IAAI,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;oBACnB,OAAO;wBACL,IAAI,EAAE,CAAC,CAAC,IAAI;wBACZ,MAAM,EAAE,kBAAkB,CAAC,CAAC,CAAC,MAAM,CAAC;wBACpC,WAAW,EAAE,EAAE;wBACf,QAAQ,EAAE,EAAE;qBACb,CAAC;gBACJ,CAAC;gBAED,OAAO;oBACL,IAAI,EAAE,CAAC,CAAC,IAAI;oBACZ,MAAM,EAAE,kBAAkB,CAAC,CAAC,CAAC,MAAM,CAAC;oBACpC,WAAW,EAAE,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;oBAC1D,QAAQ,EAAE,EAAE;iBACb,CAAC;YACJ,CAAC,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,MAAM,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;YACxE,MAAM,IAAI,qBAAqB,CAC7B,oCAAoC,MAAM,EAAE,EAC5C,IAAI,CAAC,IAAI,EACT,GAAG,EACH,IAAI,EACJ,KAAK,CACN,CAAC;QACJ,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,63 @@
1
+ import type { HostConfig } from "../types.js";
2
+ import type { ILocalExecutorService, ISSHService } from "./interfaces.js";
3
+ /**
4
+ * Service for scanning filesystems to find Docker Compose files.
5
+ * Supports both remote (SSH) and local execution.
6
+ */
7
+ export declare class ComposeScanner {
8
+ private readonly sshService;
9
+ private readonly localExecutor;
10
+ constructor(sshService: ISSHService, localExecutor: ILocalExecutorService);
11
+ /**
12
+ * Find all compose files in configured search paths.
13
+ * Uses SSH for remote hosts, local execution for localhost.
14
+ *
15
+ * @param host - Host configuration with optional composeSearchPaths
16
+ * @returns Array of absolute paths to compose files
17
+ */
18
+ findComposeFiles(host: HostConfig): Promise<string[]>;
19
+ /**
20
+ * Extract project name from compose file path (parent directory name).
21
+ *
22
+ * @param filePath - Absolute path to compose file
23
+ * @returns Parent directory name, or empty string if at root
24
+ */
25
+ extractProjectName(filePath: string): string;
26
+ /**
27
+ * Parse compose file to extract explicit 'name:' field.
28
+ * Returns null if parsing fails or no name field exists.
29
+ *
30
+ * SECURITY: Uses args array to prevent shell injection when reading files.
31
+ *
32
+ * @param host - Host configuration
33
+ * @param filePath - Absolute path to compose file
34
+ * @returns Explicit project name from 'name:' field, or null
35
+ */
36
+ parseComposeName(host: HostConfig, filePath: string): Promise<string | null>;
37
+ /**
38
+ * Parse multiple compose files in chunks and read each chunk in parallel.
39
+ * Avoids shell string concatenation by issuing one cat command per file.
40
+ *
41
+ * @param host - Host configuration where files are located
42
+ * @param filePaths - Array of absolute paths to compose files
43
+ * @param concurrency - Maximum concurrent SSH connections (default from constants)
44
+ * @returns Map of file path to project name (null if parse failed)
45
+ */
46
+ batchParseComposeNames(host: HostConfig, filePaths: string[], concurrency?: number): Promise<Map<string, string | null>>;
47
+ /**
48
+ * Read and parse a batch of compose files using parallel cat commands.
49
+ *
50
+ * @param host - Host configuration
51
+ * @param filePaths - Batch of file paths to read
52
+ * @returns Map of file path to parsed project name (null if parse failed)
53
+ */
54
+ private batchReadAndParse;
55
+ /**
56
+ * Check if host is localhost (avoids SSH overhead for local operations).
57
+ *
58
+ * @param host - Host configuration
59
+ * @returns true if host is localhost/127.0.0.1
60
+ */
61
+ private isLocalHost;
62
+ }
63
+ //# sourceMappingURL=compose-scanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compose-scanner.d.ts","sourceRoot":"","sources":["../../src/services/compose-scanner.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAAE,qBAAqB,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAsC1E;;;GAGG;AACH,qBAAa,cAAc;IAEvB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,aAAa;gBADb,UAAU,EAAE,WAAW,EACvB,aAAa,EAAE,qBAAqB;IAGvD;;;;;;OAMG;IACG,gBAAgB,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAwC3D;;;;;OAKG;IACH,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAS5C;;;;;;;;;OASG;IACG,gBAAgB,CAAC,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IA8BlF;;;;;;;;OAQG;IACG,sBAAsB,CAC1B,IAAI,EAAE,UAAU,EAChB,SAAS,EAAE,MAAM,EAAE,EACnB,WAAW,GAAE,MAAyC,GACrD,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;IAyCtC;;;;;;OAMG;YACW,iBAAiB;IAwE/B;;;;;OAKG;IACH,OAAO,CAAC,WAAW;CAIpB"}
@@ -0,0 +1,253 @@
1
+ import pLimit from "p-limit";
2
+ import YAML from "yaml";
3
+ import { DEFAULT_COMPOSE_SCAN_CONCURRENCY } from "../constants.js";
4
+ /**
5
+ * Default search paths for compose files if not specified in host config
6
+ */
7
+ const DEFAULT_SEARCH_PATHS = ["/compose", "/mnt/cache/compose", "/mnt/cache/code"];
8
+ /**
9
+ * Maximum depth to search for compose files
10
+ */
11
+ const MAX_SCAN_DEPTH = 3;
12
+ /**
13
+ * Timeout for remote find operations (ms)
14
+ */
15
+ const FIND_TIMEOUT_MS = 60_000;
16
+ /**
17
+ * Timeout for reading individual compose files (ms)
18
+ */
19
+ const CAT_TIMEOUT_MS = 10_000;
20
+ /**
21
+ * Maximum number of files to read in a single batched cat command.
22
+ * Keeps argument lists and output size manageable.
23
+ */
24
+ const BATCH_CAT_CHUNK_SIZE = 20;
25
+ /**
26
+ * Compose file patterns to search for
27
+ */
28
+ const COMPOSE_FILE_PATTERNS = [
29
+ "docker-compose.yml",
30
+ "docker-compose.yaml",
31
+ "compose.yml",
32
+ "compose.yaml",
33
+ ];
34
+ /**
35
+ * Service for scanning filesystems to find Docker Compose files.
36
+ * Supports both remote (SSH) and local execution.
37
+ */
38
+ export class ComposeScanner {
39
+ sshService;
40
+ localExecutor;
41
+ constructor(sshService, localExecutor) {
42
+ this.sshService = sshService;
43
+ this.localExecutor = localExecutor;
44
+ }
45
+ /**
46
+ * Find all compose files in configured search paths.
47
+ * Uses SSH for remote hosts, local execution for localhost.
48
+ *
49
+ * @param host - Host configuration with optional composeSearchPaths
50
+ * @returns Array of absolute paths to compose files
51
+ */
52
+ async findComposeFiles(host) {
53
+ const searchPaths = host.composeSearchPaths ?? DEFAULT_SEARCH_PATHS;
54
+ const isLocal = this.isLocalHost(host);
55
+ // Build find command args to avoid shell injection
56
+ // find /path1 /path2 -maxdepth 3 -type f \( -name "docker-compose.yml" -o -name "compose.yaml" ... \) -print
57
+ const args = [...searchPaths, "-maxdepth", MAX_SCAN_DEPTH.toString(), "-type", "f", "("];
58
+ // Add each pattern with -o (OR) between them
59
+ for (let i = 0; i < COMPOSE_FILE_PATTERNS.length; i++) {
60
+ if (i > 0) {
61
+ args.push("-o");
62
+ }
63
+ const pattern = COMPOSE_FILE_PATTERNS[i];
64
+ if (pattern) {
65
+ args.push("-name", pattern);
66
+ }
67
+ }
68
+ args.push(")", "-print");
69
+ try {
70
+ const output = isLocal
71
+ ? await this.localExecutor.executeLocalCommand("find", args, { timeoutMs: FIND_TIMEOUT_MS })
72
+ : await this.sshService.executeSSHCommand(host, "find", args, {
73
+ timeoutMs: FIND_TIMEOUT_MS,
74
+ });
75
+ // Split output by newlines, filter empty lines, and deduplicate
76
+ const allFiles = output
77
+ .split("\n")
78
+ .map((line) => line.trim())
79
+ .filter((line) => line.length > 0);
80
+ return Array.from(new Set(allFiles));
81
+ }
82
+ catch (_error) {
83
+ return [];
84
+ }
85
+ }
86
+ /**
87
+ * Extract project name from compose file path (parent directory name).
88
+ *
89
+ * @param filePath - Absolute path to compose file
90
+ * @returns Parent directory name, or empty string if at root
91
+ */
92
+ extractProjectName(filePath) {
93
+ const parts = filePath.split("/").filter((p) => p.length > 0);
94
+ // Return parent directory name (last directory before filename)
95
+ if (parts.length < 2) {
96
+ return "";
97
+ }
98
+ return parts[parts.length - 2] ?? "";
99
+ }
100
+ /**
101
+ * Parse compose file to extract explicit 'name:' field.
102
+ * Returns null if parsing fails or no name field exists.
103
+ *
104
+ * SECURITY: Uses args array to prevent shell injection when reading files.
105
+ *
106
+ * @param host - Host configuration
107
+ * @param filePath - Absolute path to compose file
108
+ * @returns Explicit project name from 'name:' field, or null
109
+ */
110
+ async parseComposeName(host, filePath) {
111
+ const isLocal = this.isLocalHost(host);
112
+ try {
113
+ // Read file contents using cat command with args array
114
+ const content = isLocal
115
+ ? await this.localExecutor.executeLocalCommand("cat", [filePath], {
116
+ timeoutMs: CAT_TIMEOUT_MS,
117
+ })
118
+ : await this.sshService.executeSSHCommand(host, "cat", [filePath], {
119
+ timeoutMs: CAT_TIMEOUT_MS,
120
+ });
121
+ // Parse YAML and extract name field
122
+ const parsed = YAML.parse(content);
123
+ if (parsed && typeof parsed === "object" && "name" in parsed) {
124
+ const name = parsed.name;
125
+ if (typeof name === "string" && name.length > 0) {
126
+ return name;
127
+ }
128
+ }
129
+ return null;
130
+ }
131
+ catch (_error) {
132
+ // Alternative: Log errors for debugging while still returning null.
133
+ return null;
134
+ }
135
+ }
136
+ /**
137
+ * Parse multiple compose files in chunks and read each chunk in parallel.
138
+ * Avoids shell string concatenation by issuing one cat command per file.
139
+ *
140
+ * @param host - Host configuration where files are located
141
+ * @param filePaths - Array of absolute paths to compose files
142
+ * @param concurrency - Maximum concurrent SSH connections (default from constants)
143
+ * @returns Map of file path to project name (null if parse failed)
144
+ */
145
+ async batchParseComposeNames(host, filePaths, concurrency = DEFAULT_COMPOSE_SCAN_CONCURRENCY) {
146
+ const results = new Map();
147
+ if (filePaths.length === 0) {
148
+ return results;
149
+ }
150
+ // Split file paths into chunks for batched reading
151
+ const chunks = [];
152
+ for (let i = 0; i < filePaths.length; i += BATCH_CAT_CHUNK_SIZE) {
153
+ chunks.push(filePaths.slice(i, i + BATCH_CAT_CHUNK_SIZE));
154
+ }
155
+ // Process chunks in parallel with concurrency control
156
+ const limit = pLimit(concurrency);
157
+ const chunkPromises = chunks.map((chunk) => limit(async () => this.batchReadAndParse(host, chunk)));
158
+ const chunkResults = await Promise.allSettled(chunkPromises);
159
+ // Merge results from all chunks
160
+ for (const settled of chunkResults) {
161
+ if (settled.status === "fulfilled") {
162
+ for (const [path, name] of settled.value) {
163
+ results.set(path, name);
164
+ }
165
+ }
166
+ }
167
+ // Ensure every requested path has an entry
168
+ for (const filePath of filePaths) {
169
+ if (!results.has(filePath)) {
170
+ results.set(filePath, null);
171
+ }
172
+ }
173
+ return results;
174
+ }
175
+ /**
176
+ * Read and parse a batch of compose files using parallel cat commands.
177
+ *
178
+ * @param host - Host configuration
179
+ * @param filePaths - Batch of file paths to read
180
+ * @returns Map of file path to parsed project name (null if parse failed)
181
+ */
182
+ async batchReadAndParse(host, filePaths) {
183
+ const results = new Map();
184
+ const isLocal = this.isLocalHost(host);
185
+ if (filePaths.length === 1) {
186
+ // Single file — use simple cat (no delimiter overhead)
187
+ const name = await this.parseComposeName(host, filePaths[0]);
188
+ results.set(filePaths[0], name);
189
+ return results;
190
+ }
191
+ try {
192
+ const contents = await Promise.all(filePaths.map((filePath) => isLocal
193
+ ? this.localExecutor.executeLocalCommand("cat", [filePath], {
194
+ timeoutMs: CAT_TIMEOUT_MS,
195
+ })
196
+ : this.sshService.executeSSHCommand(host, "cat", [filePath], {
197
+ timeoutMs: CAT_TIMEOUT_MS,
198
+ })));
199
+ for (let i = 0; i < filePaths.length; i++) {
200
+ const content = contents[i]?.trim();
201
+ const filePath = filePaths[i];
202
+ if (!content) {
203
+ results.set(filePath, null);
204
+ continue;
205
+ }
206
+ try {
207
+ const parsed = YAML.parse(content);
208
+ if (parsed && typeof parsed === "object" && "name" in parsed) {
209
+ const name = parsed.name;
210
+ if (typeof name === "string" && name.length > 0) {
211
+ results.set(filePath, name);
212
+ continue;
213
+ }
214
+ }
215
+ results.set(filePath, null);
216
+ }
217
+ catch {
218
+ results.set(filePath, null);
219
+ }
220
+ }
221
+ }
222
+ catch {
223
+ // Batch read failed — fall back to individual reads
224
+ const individualPromises = filePaths.map(async (filePath) => {
225
+ try {
226
+ const name = await this.parseComposeName(host, filePath);
227
+ return { path: filePath, name };
228
+ }
229
+ catch {
230
+ return { path: filePath, name: null };
231
+ }
232
+ });
233
+ const settled = await Promise.allSettled(individualPromises);
234
+ for (const result of settled) {
235
+ if (result.status === "fulfilled") {
236
+ results.set(result.value.path, result.value.name);
237
+ }
238
+ }
239
+ }
240
+ return results;
241
+ }
242
+ /**
243
+ * Check if host is localhost (avoids SSH overhead for local operations).
244
+ *
245
+ * @param host - Host configuration
246
+ * @returns true if host is localhost/127.0.0.1
247
+ */
248
+ isLocalHost(host) {
249
+ const hostname = host.host.toLowerCase();
250
+ return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1";
251
+ }
252
+ }
253
+ //# sourceMappingURL=compose-scanner.js.map