agentrix 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (402) hide show
  1. package/README.md +235 -0
  2. package/bin/agentrix.js +5 -0
  3. package/dist/api/auth.d.ts +10 -0
  4. package/dist/api/auth.d.ts.map +1 -0
  5. package/dist/api/auth.js +30 -0
  6. package/dist/api/auth.js.map +1 -0
  7. package/dist/api/automation.d.ts +52 -0
  8. package/dist/api/automation.d.ts.map +1 -0
  9. package/dist/api/automation.js +181 -0
  10. package/dist/api/automation.js.map +1 -0
  11. package/dist/api/base-handler.d.ts +62 -0
  12. package/dist/api/base-handler.d.ts.map +1 -0
  13. package/dist/api/base-handler.js +55 -0
  14. package/dist/api/base-handler.js.map +1 -0
  15. package/dist/api/config.d.ts +5 -0
  16. package/dist/api/config.d.ts.map +1 -0
  17. package/dist/api/config.js +14 -0
  18. package/dist/api/config.js.map +1 -0
  19. package/dist/api/create-plan.d.ts +8 -0
  20. package/dist/api/create-plan.d.ts.map +1 -0
  21. package/dist/api/create-plan.js +77 -0
  22. package/dist/api/create-plan.js.map +1 -0
  23. package/dist/api/git-status.d.ts +6 -0
  24. package/dist/api/git-status.d.ts.map +1 -0
  25. package/dist/api/git-status.js +57 -0
  26. package/dist/api/git-status.js.map +1 -0
  27. package/dist/api/plans.d.ts +6 -0
  28. package/dist/api/plans.d.ts.map +1 -0
  29. package/dist/api/plans.js +75 -0
  30. package/dist/api/plans.js.map +1 -0
  31. package/dist/api/repo-dashboard.d.ts +13 -0
  32. package/dist/api/repo-dashboard.d.ts.map +1 -0
  33. package/dist/api/repo-dashboard.js +47 -0
  34. package/dist/api/repo-dashboard.js.map +1 -0
  35. package/dist/api/repo-issue.d.ts +12 -0
  36. package/dist/api/repo-issue.d.ts.map +1 -0
  37. package/dist/api/repo-issue.js +47 -0
  38. package/dist/api/repo-issue.js.map +1 -0
  39. package/dist/api/repos.d.ts +9 -0
  40. package/dist/api/repos.d.ts.map +1 -0
  41. package/dist/api/repos.js +46 -0
  42. package/dist/api/repos.js.map +1 -0
  43. package/dist/api/sessions.d.ts +5 -0
  44. package/dist/api/sessions.d.ts.map +1 -0
  45. package/dist/api/sessions.js +19 -0
  46. package/dist/api/sessions.js.map +1 -0
  47. package/dist/api/tasks.d.ts +6 -0
  48. package/dist/api/tasks.d.ts.map +1 -0
  49. package/dist/api/tasks.js +22 -0
  50. package/dist/api/tasks.js.map +1 -0
  51. package/dist/api/terminal.d.ts +7 -0
  52. package/dist/api/terminal.d.ts.map +1 -0
  53. package/dist/api/terminal.js +16 -0
  54. package/dist/api/terminal.js.map +1 -0
  55. package/dist/api/worktrees.d.ts +7 -0
  56. package/dist/api/worktrees.d.ts.map +1 -0
  57. package/dist/api/worktrees.js +26 -0
  58. package/dist/api/worktrees.js.map +1 -0
  59. package/dist/cli/arg-parser.d.ts +3 -0
  60. package/dist/cli/arg-parser.d.ts.map +1 -0
  61. package/dist/cli/arg-parser.js +243 -0
  62. package/dist/cli/arg-parser.js.map +1 -0
  63. package/dist/cli/config-resolver.d.ts +29 -0
  64. package/dist/cli/config-resolver.d.ts.map +1 -0
  65. package/dist/cli/config-resolver.js +139 -0
  66. package/dist/cli/config-resolver.js.map +1 -0
  67. package/dist/cli/config.d.ts +5 -0
  68. package/dist/cli/config.d.ts.map +1 -0
  69. package/dist/cli/config.js +224 -0
  70. package/dist/cli/config.js.map +1 -0
  71. package/dist/cli/constants.d.ts +7 -0
  72. package/dist/cli/constants.d.ts.map +1 -0
  73. package/dist/cli/constants.js +15 -0
  74. package/dist/cli/constants.js.map +1 -0
  75. package/dist/cli/help.d.ts +3 -0
  76. package/dist/cli/help.d.ts.map +1 -0
  77. package/dist/cli/help.js +35 -0
  78. package/dist/cli/help.js.map +1 -0
  79. package/dist/cli/index.d.ts +23 -0
  80. package/dist/cli/index.d.ts.map +1 -0
  81. package/dist/cli/index.js +23 -0
  82. package/dist/cli/index.js.map +1 -0
  83. package/dist/cli/plans-command.d.ts +3 -0
  84. package/dist/cli/plans-command.d.ts.map +1 -0
  85. package/dist/cli/plans-command.js +151 -0
  86. package/dist/cli/plans-command.js.map +1 -0
  87. package/dist/cli/server-starter.d.ts +26 -0
  88. package/dist/cli/server-starter.d.ts.map +1 -0
  89. package/dist/cli/server-starter.js +72 -0
  90. package/dist/cli/server-starter.js.map +1 -0
  91. package/dist/cli/types.d.ts +46 -0
  92. package/dist/cli/types.d.ts.map +1 -0
  93. package/dist/cli/types.js +2 -0
  94. package/dist/cli/types.js.map +1 -0
  95. package/dist/cli/validation.d.ts +14 -0
  96. package/dist/cli/validation.d.ts.map +1 -0
  97. package/dist/cli/validation.js +99 -0
  98. package/dist/cli/validation.js.map +1 -0
  99. package/dist/cli.d.ts +5 -0
  100. package/dist/cli.d.ts.map +1 -0
  101. package/dist/cli.js +73 -0
  102. package/dist/cli.js.map +1 -0
  103. package/dist/config/agent-commands.d.ts +27 -0
  104. package/dist/config/agent-commands.d.ts.map +1 -0
  105. package/dist/config/agent-commands.js +56 -0
  106. package/dist/config/agent-commands.js.map +1 -0
  107. package/dist/config/constants.d.ts +35 -0
  108. package/dist/config/constants.d.ts.map +1 -0
  109. package/dist/config/constants.js +35 -0
  110. package/dist/config/constants.js.map +1 -0
  111. package/dist/config/developer-messages.d.ts +2 -0
  112. package/dist/config/developer-messages.d.ts.map +1 -0
  113. package/dist/config/developer-messages.js +43 -0
  114. package/dist/config/developer-messages.js.map +1 -0
  115. package/dist/core/agents.d.ts +23 -0
  116. package/dist/core/agents.d.ts.map +1 -0
  117. package/dist/core/agents.js +91 -0
  118. package/dist/core/agents.js.map +1 -0
  119. package/dist/core/auth.d.ts +3 -0
  120. package/dist/core/auth.d.ts.map +1 -0
  121. package/dist/core/auth.js +69 -0
  122. package/dist/core/auth.js.map +1 -0
  123. package/dist/core/automation/branch.d.ts +18 -0
  124. package/dist/core/automation/branch.d.ts.map +1 -0
  125. package/dist/core/automation/branch.js +29 -0
  126. package/dist/core/automation/branch.js.map +1 -0
  127. package/dist/core/automation/git-orchestration.d.ts +51 -0
  128. package/dist/core/automation/git-orchestration.d.ts.map +1 -0
  129. package/dist/core/automation/git-orchestration.js +25 -0
  130. package/dist/core/automation/git-orchestration.js.map +1 -0
  131. package/dist/core/automation/plan.d.ts +15 -0
  132. package/dist/core/automation/plan.d.ts.map +1 -0
  133. package/dist/core/automation/plan.js +25 -0
  134. package/dist/core/automation/plan.js.map +1 -0
  135. package/dist/core/automation/request-validation.d.ts +45 -0
  136. package/dist/core/automation/request-validation.d.ts.map +1 -0
  137. package/dist/core/automation/request-validation.js +144 -0
  138. package/dist/core/automation/request-validation.js.map +1 -0
  139. package/dist/core/automation/task-runner.d.ts +42 -0
  140. package/dist/core/automation/task-runner.d.ts.map +1 -0
  141. package/dist/core/automation/task-runner.js +215 -0
  142. package/dist/core/automation/task-runner.js.map +1 -0
  143. package/dist/core/branch-name.d.ts +13 -0
  144. package/dist/core/branch-name.d.ts.map +1 -0
  145. package/dist/core/branch-name.js +429 -0
  146. package/dist/core/branch-name.js.map +1 -0
  147. package/dist/core/default-branch.d.ts +12 -0
  148. package/dist/core/default-branch.d.ts.map +1 -0
  149. package/dist/core/default-branch.js +78 -0
  150. package/dist/core/default-branch.js.map +1 -0
  151. package/dist/core/event-bus.d.ts +73 -0
  152. package/dist/core/event-bus.d.ts.map +1 -0
  153. package/dist/core/event-bus.js +127 -0
  154. package/dist/core/event-bus.js.map +1 -0
  155. package/dist/core/git.d.ts +13 -0
  156. package/dist/core/git.d.ts.map +1 -0
  157. package/dist/core/git.js +15 -0
  158. package/dist/core/git.js.map +1 -0
  159. package/dist/core/github.d.ts +10 -0
  160. package/dist/core/github.d.ts.map +1 -0
  161. package/dist/core/github.js +245 -0
  162. package/dist/core/github.js.map +1 -0
  163. package/dist/core/plan-storage.d.ts +46 -0
  164. package/dist/core/plan-storage.d.ts.map +1 -0
  165. package/dist/core/plan-storage.js +237 -0
  166. package/dist/core/plan-storage.js.map +1 -0
  167. package/dist/core/plan.d.ts +23 -0
  168. package/dist/core/plan.d.ts.map +1 -0
  169. package/dist/core/plan.js +445 -0
  170. package/dist/core/plan.js.map +1 -0
  171. package/dist/core/repositories.d.ts +2 -0
  172. package/dist/core/repositories.d.ts.map +1 -0
  173. package/dist/core/repositories.js +58 -0
  174. package/dist/core/repositories.js.map +1 -0
  175. package/dist/core/repository-config.d.ts +9 -0
  176. package/dist/core/repository-config.d.ts.map +1 -0
  177. package/dist/core/repository-config.js +65 -0
  178. package/dist/core/repository-config.js.map +1 -0
  179. package/dist/core/task-store.d.ts +14 -0
  180. package/dist/core/task-store.d.ts.map +1 -0
  181. package/dist/core/task-store.js +105 -0
  182. package/dist/core/task-store.js.map +1 -0
  183. package/dist/core/tasks.d.ts +62 -0
  184. package/dist/core/tasks.d.ts.map +1 -0
  185. package/dist/core/tasks.js +582 -0
  186. package/dist/core/tasks.js.map +1 -0
  187. package/dist/core/terminal-sessions.d.ts +18 -0
  188. package/dist/core/terminal-sessions.d.ts.map +1 -0
  189. package/dist/core/terminal-sessions.js +539 -0
  190. package/dist/core/terminal-sessions.js.map +1 -0
  191. package/dist/core/tmux.d.ts +29 -0
  192. package/dist/core/tmux.d.ts.map +1 -0
  193. package/dist/core/tmux.js +151 -0
  194. package/dist/core/tmux.js.map +1 -0
  195. package/dist/core/workdir.d.ts +8 -0
  196. package/dist/core/workdir.d.ts.map +1 -0
  197. package/dist/core/workdir.js +26 -0
  198. package/dist/core/workdir.js.map +1 -0
  199. package/dist/domain/branch-validator.d.ts +51 -0
  200. package/dist/domain/branch-validator.d.ts.map +1 -0
  201. package/dist/domain/branch-validator.js +88 -0
  202. package/dist/domain/branch-validator.js.map +1 -0
  203. package/dist/domain/git-url-parser.d.ts +27 -0
  204. package/dist/domain/git-url-parser.d.ts.map +1 -0
  205. package/dist/domain/git-url-parser.js +84 -0
  206. package/dist/domain/git-url-parser.js.map +1 -0
  207. package/dist/domain/index.d.ts +8 -0
  208. package/dist/domain/index.d.ts.map +1 -0
  209. package/dist/domain/index.js +5 -0
  210. package/dist/domain/index.js.map +1 -0
  211. package/dist/domain/repository.d.ts +55 -0
  212. package/dist/domain/repository.d.ts.map +1 -0
  213. package/dist/domain/repository.js +73 -0
  214. package/dist/domain/repository.js.map +1 -0
  215. package/dist/domain/worktree.d.ts +43 -0
  216. package/dist/domain/worktree.d.ts.map +1 -0
  217. package/dist/domain/worktree.js +57 -0
  218. package/dist/domain/worktree.js.map +1 -0
  219. package/dist/infrastructure/cookies/cookie-manager.d.ts +18 -0
  220. package/dist/infrastructure/cookies/cookie-manager.d.ts.map +1 -0
  221. package/dist/infrastructure/cookies/cookie-manager.js +20 -0
  222. package/dist/infrastructure/cookies/cookie-manager.js.map +1 -0
  223. package/dist/infrastructure/cookies/cookie-parser.d.ts +43 -0
  224. package/dist/infrastructure/cookies/cookie-parser.d.ts.map +1 -0
  225. package/dist/infrastructure/cookies/cookie-parser.js +88 -0
  226. package/dist/infrastructure/cookies/cookie-parser.js.map +1 -0
  227. package/dist/infrastructure/cookies/cookie-security.d.ts +15 -0
  228. package/dist/infrastructure/cookies/cookie-security.d.ts.map +1 -0
  229. package/dist/infrastructure/cookies/cookie-security.js +35 -0
  230. package/dist/infrastructure/cookies/cookie-security.js.map +1 -0
  231. package/dist/infrastructure/cookies/index.d.ts +7 -0
  232. package/dist/infrastructure/cookies/index.d.ts.map +1 -0
  233. package/dist/infrastructure/cookies/index.js +4 -0
  234. package/dist/infrastructure/cookies/index.js.map +1 -0
  235. package/dist/infrastructure/errors/error-handler.d.ts +22 -0
  236. package/dist/infrastructure/errors/error-handler.d.ts.map +1 -0
  237. package/dist/infrastructure/errors/error-handler.js +89 -0
  238. package/dist/infrastructure/errors/error-handler.js.map +1 -0
  239. package/dist/infrastructure/errors/http-error.d.ts +30 -0
  240. package/dist/infrastructure/errors/http-error.d.ts.map +1 -0
  241. package/dist/infrastructure/errors/http-error.js +46 -0
  242. package/dist/infrastructure/errors/http-error.js.map +1 -0
  243. package/dist/infrastructure/errors/index.d.ts +5 -0
  244. package/dist/infrastructure/errors/index.d.ts.map +1 -0
  245. package/dist/infrastructure/errors/index.js +5 -0
  246. package/dist/infrastructure/errors/index.js.map +1 -0
  247. package/dist/infrastructure/errors/not-found-error.d.ts +8 -0
  248. package/dist/infrastructure/errors/not-found-error.d.ts.map +1 -0
  249. package/dist/infrastructure/errors/not-found-error.js +13 -0
  250. package/dist/infrastructure/errors/not-found-error.js.map +1 -0
  251. package/dist/infrastructure/errors/validation-error.d.ts +21 -0
  252. package/dist/infrastructure/errors/validation-error.d.ts.map +1 -0
  253. package/dist/infrastructure/errors/validation-error.js +31 -0
  254. package/dist/infrastructure/errors/validation-error.js.map +1 -0
  255. package/dist/infrastructure/logging/index.d.ts +3 -0
  256. package/dist/infrastructure/logging/index.d.ts.map +1 -0
  257. package/dist/infrastructure/logging/index.js +2 -0
  258. package/dist/infrastructure/logging/index.js.map +1 -0
  259. package/dist/infrastructure/logging/logger.d.ts +21 -0
  260. package/dist/infrastructure/logging/logger.d.ts.map +1 -0
  261. package/dist/infrastructure/logging/logger.js +49 -0
  262. package/dist/infrastructure/logging/logger.js.map +1 -0
  263. package/dist/repositories/git-repository.d.ts +67 -0
  264. package/dist/repositories/git-repository.d.ts.map +1 -0
  265. package/dist/repositories/git-repository.js +111 -0
  266. package/dist/repositories/git-repository.js.map +1 -0
  267. package/dist/repositories/git-status-repository.d.ts +22 -0
  268. package/dist/repositories/git-status-repository.d.ts.map +1 -0
  269. package/dist/repositories/git-status-repository.js +620 -0
  270. package/dist/repositories/git-status-repository.js.map +1 -0
  271. package/dist/repositories/repository-repository.d.ts +44 -0
  272. package/dist/repositories/repository-repository.d.ts.map +1 -0
  273. package/dist/repositories/repository-repository.js +155 -0
  274. package/dist/repositories/repository-repository.js.map +1 -0
  275. package/dist/repositories/worktree-repository.d.ts +66 -0
  276. package/dist/repositories/worktree-repository.d.ts.map +1 -0
  277. package/dist/repositories/worktree-repository.js +330 -0
  278. package/dist/repositories/worktree-repository.js.map +1 -0
  279. package/dist/server/cookies.d.ts +6 -0
  280. package/dist/server/cookies.d.ts.map +1 -0
  281. package/dist/server/cookies.js +6 -0
  282. package/dist/server/cookies.js.map +1 -0
  283. package/dist/server/events.d.ts +8 -0
  284. package/dist/server/events.d.ts.map +1 -0
  285. package/dist/server/events.js +128 -0
  286. package/dist/server/events.js.map +1 -0
  287. package/dist/server/index.d.ts +18 -0
  288. package/dist/server/index.d.ts.map +1 -0
  289. package/dist/server/index.js +173 -0
  290. package/dist/server/index.js.map +1 -0
  291. package/dist/server/router.d.ts +16 -0
  292. package/dist/server/router.d.ts.map +1 -0
  293. package/dist/server/router.js +256 -0
  294. package/dist/server/router.js.map +1 -0
  295. package/dist/server/ui.d.ts +8 -0
  296. package/dist/server/ui.d.ts.map +1 -0
  297. package/dist/server/ui.js +211 -0
  298. package/dist/server/ui.js.map +1 -0
  299. package/dist/server/websocket.d.ts +9 -0
  300. package/dist/server/websocket.d.ts.map +1 -0
  301. package/dist/server/websocket.js +116 -0
  302. package/dist/server/websocket.js.map +1 -0
  303. package/dist/services/auth-service.d.ts +49 -0
  304. package/dist/services/auth-service.d.ts.map +1 -0
  305. package/dist/services/auth-service.js +53 -0
  306. package/dist/services/auth-service.js.map +1 -0
  307. package/dist/services/index.d.ts +11 -0
  308. package/dist/services/index.d.ts.map +1 -0
  309. package/dist/services/index.js +6 -0
  310. package/dist/services/index.js.map +1 -0
  311. package/dist/services/repository-service.d.ts +57 -0
  312. package/dist/services/repository-service.d.ts.map +1 -0
  313. package/dist/services/repository-service.js +62 -0
  314. package/dist/services/repository-service.js.map +1 -0
  315. package/dist/services/session-service.d.ts +31 -0
  316. package/dist/services/session-service.d.ts.map +1 -0
  317. package/dist/services/session-service.js +134 -0
  318. package/dist/services/session-service.js.map +1 -0
  319. package/dist/services/terminal-service.d.ts +43 -0
  320. package/dist/services/terminal-service.d.ts.map +1 -0
  321. package/dist/services/terminal-service.js +85 -0
  322. package/dist/services/terminal-service.js.map +1 -0
  323. package/dist/services/worktree-service.d.ts +39 -0
  324. package/dist/services/worktree-service.d.ts.map +1 -0
  325. package/dist/services/worktree-service.js +208 -0
  326. package/dist/services/worktree-service.js.map +1 -0
  327. package/dist/types/auth.d.ts +35 -0
  328. package/dist/types/auth.d.ts.map +1 -0
  329. package/dist/types/auth.js +2 -0
  330. package/dist/types/auth.js.map +1 -0
  331. package/dist/types/config.d.ts +46 -0
  332. package/dist/types/config.d.ts.map +1 -0
  333. package/dist/types/config.js +5 -0
  334. package/dist/types/config.js.map +1 -0
  335. package/dist/types/git.d.ts +190 -0
  336. package/dist/types/git.d.ts.map +1 -0
  337. package/dist/types/git.js +5 -0
  338. package/dist/types/git.js.map +1 -0
  339. package/dist/types/http.d.ts +46 -0
  340. package/dist/types/http.d.ts.map +1 -0
  341. package/dist/types/http.js +2 -0
  342. package/dist/types/http.js.map +1 -0
  343. package/dist/types/index.d.ts +8 -0
  344. package/dist/types/index.d.ts.map +1 -0
  345. package/dist/types/index.js +2 -0
  346. package/dist/types/index.js.map +1 -0
  347. package/dist/types/plan.d.ts +31 -0
  348. package/dist/types/plan.d.ts.map +1 -0
  349. package/dist/types/plan.js +5 -0
  350. package/dist/types/plan.js.map +1 -0
  351. package/dist/types/services.d.ts +99 -0
  352. package/dist/types/services.d.ts.map +1 -0
  353. package/dist/types/services.js +2 -0
  354. package/dist/types/services.js.map +1 -0
  355. package/dist/types/tasks.d.ts +68 -0
  356. package/dist/types/tasks.d.ts.map +1 -0
  357. package/dist/types/tasks.js +5 -0
  358. package/dist/types/tasks.js.map +1 -0
  359. package/dist/types/terminal.d.ts +60 -0
  360. package/dist/types/terminal.d.ts.map +1 -0
  361. package/dist/types/terminal.js +2 -0
  362. package/dist/types/terminal.js.map +1 -0
  363. package/dist/utils/cookies.d.ts +7 -0
  364. package/dist/utils/cookies.d.ts.map +1 -0
  365. package/dist/utils/cookies.js +6 -0
  366. package/dist/utils/cookies.js.map +1 -0
  367. package/dist/utils/http.d.ts +23 -0
  368. package/dist/utils/http.d.ts.map +1 -0
  369. package/dist/utils/http.js +58 -0
  370. package/dist/utils/http.js.map +1 -0
  371. package/dist/utils/random.d.ts +12 -0
  372. package/dist/utils/random.d.ts.map +1 -0
  373. package/dist/utils/random.js +25 -0
  374. package/dist/utils/random.js.map +1 -0
  375. package/dist/utils/repository-cache.d.ts +8 -0
  376. package/dist/utils/repository-cache.d.ts.map +1 -0
  377. package/dist/utils/repository-cache.js +13 -0
  378. package/dist/utils/repository-cache.js.map +1 -0
  379. package/dist/validation/index.d.ts +9 -0
  380. package/dist/validation/index.d.ts.map +1 -0
  381. package/dist/validation/index.js +6 -0
  382. package/dist/validation/index.js.map +1 -0
  383. package/dist/validation/request-validator.d.ts +99 -0
  384. package/dist/validation/request-validator.d.ts.map +1 -0
  385. package/dist/validation/request-validator.js +189 -0
  386. package/dist/validation/request-validator.js.map +1 -0
  387. package/dist/validation/schemas/repository-schema.d.ts +26 -0
  388. package/dist/validation/schemas/repository-schema.d.ts.map +1 -0
  389. package/dist/validation/schemas/repository-schema.js +31 -0
  390. package/dist/validation/schemas/repository-schema.js.map +1 -0
  391. package/dist/validation/schemas/terminal-schema.d.ts +21 -0
  392. package/dist/validation/schemas/terminal-schema.d.ts.map +1 -0
  393. package/dist/validation/schemas/terminal-schema.js +38 -0
  394. package/dist/validation/schemas/terminal-schema.js.map +1 -0
  395. package/dist/validation/schemas/worktree-schema.d.ts +21 -0
  396. package/dist/validation/schemas/worktree-schema.d.ts.map +1 -0
  397. package/dist/validation/schemas/worktree-schema.js +29 -0
  398. package/dist/validation/schemas/worktree-schema.js.map +1 -0
  399. package/package.json +79 -0
  400. package/ui/dist/assets/index-BDDrbP3l.js +354 -0
  401. package/ui/dist/assets/index-CwB7gOl4.css +41 -0
  402. package/ui/dist/index.html +13 -0
package/README.md ADDED
@@ -0,0 +1,235 @@
1
+ # agentrix
2
+
3
+ `agentrix` is a password-protected CLI that serves a browser-based interface for managing
4
+ Git repositories, worktrees, and persistent shell sessions. The backend is an ES module Node.js
5
+ service that exposes REST + WebSocket APIs, while the frontend is a Vite-powered React application
6
+ that lives in `ui/`.
7
+
8
+ ## Prerequisites
9
+
10
+ - Node.js 18 or newer
11
+ - Git (for cloning repositories and creating worktrees)
12
+
13
+ ## Install Dependencies
14
+
15
+ From the repository root:
16
+
17
+ ```bash
18
+ npm install
19
+ ```
20
+
21
+ Install frontend dependencies separately:
22
+
23
+ ```bash
24
+ cd ui
25
+ npm install
26
+ ```
27
+
28
+ ## Build the Frontend
29
+
30
+ The backend serves pre-built assets from `ui/dist`. Build them once (or whenever the UI changes):
31
+
32
+ ```bash
33
+ npm run build # Invokes `vite build` in ui/
34
+ ```
35
+
36
+ The build artefacts land in `ui/dist/` and are picked up automatically by the CLI defaults.
37
+
38
+ ## Running the CLI
39
+
40
+ After building the UI:
41
+
42
+ ```bash
43
+ npm start
44
+ ```
45
+
46
+ or directly:
47
+
48
+ ```bash
49
+ node bin/agentrix.js
50
+ ```
51
+
52
+ By default the server binds to `0.0.0.0:3414`, serves assets from `ui/dist`, and scans the current
53
+ working directory for repositories. Customise behaviour with flags:
54
+
55
+ ```bash
56
+ node bin/agentrix.js \
57
+ --port 4000 \
58
+ --host 127.0.0.1 \
59
+ --ui ./ui/dist \
60
+ --workdir /path/to/workdir \
61
+ --password secret
62
+ ```
63
+
64
+ ### CLI Options
65
+
66
+ - `-p, --port <number>` – HTTP port (default: `3414`)
67
+ - `-H, --host <host>` – Bind address (default: `0.0.0.0`)
68
+ - `-u, --ui <path>` – Directory or entry file for the built UI (default: `ui/dist`)
69
+ - `-w, --workdir <path>` – Root directory that holds `org/repo` folders (default: process CWD)
70
+ - `-P, --password <string>` – UI password (default: secure random string generated at startup)
71
+ - `--default-branch <name>` – Override the sync branch when repositories use a non-`main` default
72
+ - `--terminal-session-mode <auto|tmux|pty>` – Select the terminal backend (`auto` tries tmux, falls back to PTY)
73
+ - `--force-tmux` – Shortcut for `--terminal-session-mode tmux`; errors if tmux is unavailable
74
+ - `--no-tmux` – Shortcut for `--terminal-session-mode pty`; disables tmux usage entirely
75
+ - `--show-password` – Print the resolved password even if it was set via config or flag
76
+ - `--ngrok-api-key <token>` – Authtoken used to establish a public ngrok tunnel
77
+ - `--ngrok-domain <domain>` – Reserved ngrok domain exposed when tunnelling (requires `--ngrok-api-key`)
78
+ - `--save` – Persist the effective configuration to `~/.agentrix/config.json` and exit
79
+ - `-h, --help` – Print usage
80
+ - `-v, --version` – Show package version
81
+
82
+ When both ngrok flags are supplied the CLI will establish a tunnel after the HTTP server boots and
83
+ print the public URL. If either flag is omitted the service remains reachable only via the bound host
84
+ and port.
85
+
86
+ ### Configuration File
87
+
88
+ At startup the CLI also reads `~/.agentrix/config.json` if it exists. Any values in that file
89
+ fill in defaults for matching CLI options, while explicit command-line arguments always win. A simple
90
+ configuration might look like:
91
+
92
+ ```json
93
+ {
94
+ "port": 4001,
95
+ "host": "127.0.0.1",
96
+ "ui": "./ui/dist",
97
+ "workdir": "/srv/worktrees",
98
+ "password": "s3cr3t",
99
+ "defaultBranch": "develop",
100
+ "defaultBranches": {
101
+ "acme/web": "master"
102
+ },
103
+ "cookies": {
104
+ "secure": "auto"
105
+ },
106
+ "commands": {
107
+ "codex": "codex",
108
+ "cursor": "cursor-agent",
109
+ "vscode": "code ."
110
+ },
111
+ "ngrok": {
112
+ "apiKey": "NGROK_AUTHTOKEN",
113
+ "domain": "example.ngrok.app"
114
+ },
115
+ "automation": {
116
+ "apiKey": "AUTOMATION_API_KEY"
117
+ }
118
+ }
119
+ ```
120
+
121
+ Supported keys mirror the CLI flags (`port`, `host`, `ui`, `workdir`, `password`, individual
122
+ `*Command` entries, plus `ngrokApiKey`/`ngrokDomain` or `ngrok.apiKey` / `ngrok.domain`). The
123
+ automation API key can be supplied as `automation.apiKey`, `automationApiKey`, or `apiKey`. Leave
124
+ the file absent to continue using only CLI arguments. Use `terminalSessionMode` to persist the
125
+ preferred terminal backend (`auto`, `tmux`, or `pty`).
126
+
127
+ Run `agentrix --port 4001 --workdir /srv/worktrees --save` to save the provided values into
128
+ the config file without starting the server.
129
+
130
+ ### Authentication
131
+
132
+ When the CLI generates a password it prints the value once at startup. If you supply a password via
133
+ CLI flag or config file it is kept out of stdout; pass `--show-password` if you still need the value
134
+ echoed. Clients must authenticate before calling API endpoints.
135
+
136
+ Repositories that do not use `main` can set a global `defaultBranch` or repo-specific overrides in
137
+ `defaultBranches` (keyed by `org/repo`). The CLI uses these when syncing before creating worktrees.
138
+ Successful logins receive an HTTP-only session cookie; log out via the UI or `POST
139
+ /api/auth/logout`. On shutdown the backend cleans up shell sessions, tmux attachments, and WebSocket
140
+ clients.
141
+
142
+ ### Automation API
143
+
144
+ When `config.json` includes an automation API key the backend exposes a machine-consumable endpoint
145
+ for provisioning worktrees and launching agents.
146
+
147
+ - Endpoint: `POST /api/automation/launch`
148
+ - Headers: `X-API-Key: <key>` (alternatively `Authorization: Bearer <key>`)
149
+ - Body shape:
150
+
151
+ ```json
152
+ {
153
+ "repo": "org/repository",
154
+ "worktree": "type/title",
155
+ "command": "codex",
156
+ "prompt": "Kick off the task at hand",
157
+ "plan": true
158
+ }
159
+ ```
160
+
161
+ The server uses `codex`, `cursor`, or `claude` agent commands configured via `config.json`, cloning
162
+ `git@github.com:org/repository.git` if necessary, creating (or reusing) the specified worktree, and
163
+ then launching the agent inside the same tmux-backed terminal session that the UI attaches to. When
164
+ `plan` is omitted or set to `true` the submitted prompt is first transformed via the **Create Plan**
165
+ pipeline (powered by the configured local LLM); set `"plan": false` to preserve the original prompt and bypass
166
+ planning. The request responds with `202 Accepted` once the terminal session is ready and includes
167
+ metadata about the repository, worktree, agent command, process `pid`, terminal identifiers
168
+ (`terminalSessionId`, `terminalSessionCreated`, `terminalUsingTmux`, `tmuxSessionName` when
169
+ applicable), plus the automation metadata `plan`, `promptRoute`, and `automationRequestId`. Automated
170
+ launches therefore appear immediately inside the UI terminal. The effective prompt (planned or
171
+ passthrough) is exported to the session as `AGENTRIX_PROMPT` and appended to the initial
172
+ agent command so automation invocations receive it straight away.
173
+
174
+ ### Task Persistence
175
+
176
+ Automation launches and other background workflows publish task status updates that power
177
+ `/api/tasks` and the UI dashboard. The backend persists this metadata to
178
+ `<workdir>/.agentrix/tasks.json` using atomic writes so that state survives process
179
+ restarts. During bootstrap the saved snapshot is rehydrated; any task that was still `pending` or
180
+ `running` is marked as `failed` with `error.reason` set to `process_restart`, allowing the UI to show
181
+ that progress was interrupted. Completed tasks remain visible for 15 minutes before being pruned
182
+ from both memory and disk.
183
+
184
+ ### Plan Artifacts
185
+
186
+ Automation runs (and prompt-driven worktree creation) persist Markdown plans inside each worktree
187
+ under `.plans/`. Access them without SSHing into the worktree:
188
+
189
+ - `GET /api/plans?org=<org>&repo=<repo>&branch=<branch>` – returns the newest plan identifiers and
190
+ timestamps for the requested worktree.
191
+ - `GET /api/plans/content?...&planId=<file>` – streams the selected plan’s contents in Markdown.
192
+ - CLI helper: `agentrix plans list --org <org> --repo <repo> --branch <branch>` followed by
193
+ `agentrix plans show --org <org> --repo <repo> --branch <branch> --plan-id <file>` to
194
+ render Markdown locally.
195
+
196
+ The server prunes older artifacts, keeping the 20 most recent plans per branch by default. Delete
197
+ entries manually if you need to reclaim space sooner.
198
+
199
+ ### Real-time Updates
200
+
201
+ After authentication the UI opens a Server-Sent Events stream at `GET /api/events` to receive
202
+ push notifications:
203
+
204
+ - `repos:update` — emits the full repository/worktree snapshot (equivalent to `GET /api/repos`).
205
+ - `sessions:update` — lists active terminal sessions (subset of `GET /api/sessions`).
206
+
207
+ When the stream is unavailable the client automatically falls back to minute-level polling to keep
208
+ state in sync.
209
+
210
+ ### Repository Layout & Worktrees
211
+
212
+ The work directory is expected to follow:
213
+
214
+ ```
215
+ [workdir]/
216
+ org/
217
+ repo/
218
+ repository/ # main checkout
219
+ <worktree-name>/ # additional worktrees
220
+ ```
221
+
222
+ Use **Add Repo** to clone into this structure, **Create Worktree** to branch from up-to-date
223
+ `origin/main`, and **Delete Worktree** to remove worktrees (except `main`, which is intentionally
224
+ protected). Terminal sessions are backed by `node-pty` and optionally tmux so reconnects resume the
225
+ previous shell.
226
+
227
+ ## Development Workflow
228
+
229
+ - `npm run dev` – Start the backend CLI.
230
+ - `npm run dev:ui` – Run the Vite dev server (hot-module reloading React).
231
+ - `npm run preview` – Serve the production build through Vite.
232
+ - `npm run build` – Generate production assets in `ui/dist`.
233
+
234
+ During local development run the backend CLI (`npm run dev`) alongside the Vite dev server (`npm run
235
+ dev:ui`). Use the dev server URL directly in the browser while exercising APIs exposed by the CLI.
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { main } from '../dist/cli.js';
4
+
5
+ main();
@@ -0,0 +1,10 @@
1
+ import type { RequestContext } from '../types/http.js';
2
+ import type { AuthManager, CookieManager } from '../types/auth.js';
3
+ export declare function createAuthHandlers(authManager: AuthManager, { cookieManager }?: {
4
+ cookieManager?: CookieManager;
5
+ }): {
6
+ login: (context: RequestContext) => Promise<void>;
7
+ logout: (context: RequestContext) => Promise<void>;
8
+ status: (context: RequestContext) => Promise<void>;
9
+ };
10
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/api/auth.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEnE,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,WAAW,EACxB,EAAE,aAAa,EAAE,GAAE;IAAE,aAAa,CAAC,EAAE,aAAa,CAAA;CAAO;;;;EAiC1D"}
@@ -0,0 +1,30 @@
1
+ import { sendJson } from '../utils/http.js';
2
+ import { createAuthService } from '../services/index.js';
3
+ import { asyncHandler } from '../infrastructure/errors/index.js';
4
+ import { createSimpleHandler } from './base-handler.js';
5
+ export function createAuthHandlers(authManager, { cookieManager } = {}) {
6
+ const authService = createAuthService(authManager, cookieManager);
7
+ // Login requires special error handling for status codes
8
+ const login = asyncHandler(async (context) => {
9
+ const payload = await context.readJsonBody();
10
+ const password = typeof payload['password'] === 'string' ? payload['password'].trim() : '';
11
+ try {
12
+ const result = await authService.login(context.req, context.res, password);
13
+ sendJson(context.res, 200, result);
14
+ }
15
+ catch (error) {
16
+ // Auth errors need special handling for status codes
17
+ const err = error;
18
+ const statusCode = err.statusCode || (err.message === 'Invalid password' ? 401 : 400);
19
+ sendJson(context.res, statusCode, { error: err.message });
20
+ }
21
+ });
22
+ const logout = createSimpleHandler(async (context) => authService.logout(context.req, context.res));
23
+ const status = createSimpleHandler(async (context) => authService.getStatus(context.req));
24
+ return {
25
+ login,
26
+ logout,
27
+ status,
28
+ };
29
+ }
30
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/api/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACjE,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAIxD,MAAM,UAAU,kBAAkB,CAChC,WAAwB,EACxB,EAAE,aAAa,KAAwC,EAAE;IAEzD,MAAM,WAAW,GAAG,iBAAiB,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;IAElE,yDAAyD;IACzD,MAAM,KAAK,GAAG,YAAY,CAAC,KAAK,EAAE,OAAuB,EAAE,EAAE;QAC3D,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,YAAY,EAAE,CAAC;QAC7C,MAAM,QAAQ,GAAG,OAAO,OAAO,CAAC,UAAU,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAE3F,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;YAC3E,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;QACrC,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,qDAAqD;YACrD,MAAM,GAAG,GAAG,KAAiD,CAAC;YAC9D,MAAM,UAAU,GAAG,GAAG,CAAC,UAAU,IAAI,CAAC,GAAG,CAAC,OAAO,KAAK,kBAAkB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;YACtF,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,UAAU,EAAE,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,mBAAmB,CAChC,KAAK,EAAE,OAAuB,EAAE,EAAE,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,CAChF,CAAC;IAEF,MAAM,MAAM,GAAG,mBAAmB,CAChC,KAAK,EAAE,OAAuB,EAAE,EAAE,CAAC,WAAW,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,CACtE,CAAC;IAEF,OAAO;QACL,KAAK;QACL,MAAM;QACN,MAAM;KACP,CAAC;AACJ,CAAC"}
@@ -0,0 +1,52 @@
1
+ import { launchAgentProcess } from '../core/agents.js';
2
+ import { runTask } from '../core/tasks.js';
3
+ import type { Logger } from '../infrastructure/logging/index.js';
4
+ declare function ensureRepositoryExists(workdir: string, org: string, repo: string): Promise<{
5
+ repositoryPath: string;
6
+ cloned: boolean;
7
+ }>;
8
+ declare function ensureWorktreeExists(workdir: string, org: string, repo: string, branch: string, options?: unknown): Promise<{
9
+ worktreePath: string;
10
+ created: boolean;
11
+ }>;
12
+ export declare const automationPlanMetrics: {
13
+ planTrue: {
14
+ requests: number;
15
+ successes: number;
16
+ failures: number;
17
+ totalLatencyMs: number;
18
+ };
19
+ planFalse: {
20
+ requests: number;
21
+ successes: number;
22
+ failures: number;
23
+ totalLatencyMs: number;
24
+ };
25
+ };
26
+ export declare function resetAutomationPlanMetrics(): void;
27
+ export interface AutomationHandlersConfig {
28
+ workdir: string;
29
+ agentCommands: unknown;
30
+ apiKey?: string;
31
+ branchNameGenerator: unknown;
32
+ planService: unknown;
33
+ logger?: Logger;
34
+ defaultBranches: unknown;
35
+ }
36
+ export interface AutomationHandlersDependencies {
37
+ ensureRepositoryExists?: typeof ensureRepositoryExists;
38
+ ensureWorktreeExists?: typeof ensureWorktreeExists;
39
+ launchAgentProcess?: typeof launchAgentProcess;
40
+ runTaskImpl?: typeof runTask;
41
+ now?: () => number;
42
+ createRequestId?: () => string;
43
+ }
44
+ export declare function createAutomationHandlers({ workdir, agentCommands, apiKey, branchNameGenerator, planService, logger, defaultBranches, }: AutomationHandlersConfig, { ensureRepositoryExists: ensureRepoExists, ensureWorktreeExists: ensureWorktree, launchAgentProcess: launchAgent, runTaskImpl, now, createRequestId, }?: AutomationHandlersDependencies): {
45
+ launch: (context: {
46
+ req: unknown;
47
+ res: unknown;
48
+ readJsonBody: () => Promise<unknown>;
49
+ }) => Promise<void>;
50
+ };
51
+ export {};
52
+ //# sourceMappingURL=automation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"automation.d.ts","sourceRoot":"","sources":["../../src/api/automation.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAW3C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oCAAoC,CAAC;AAEjE,iBAAe,sBAAsB,CACnC,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,GACX,OAAO,CAAC;IAAE,cAAc,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,CAAC,CActD;AAED,iBAAe,oBAAoB,CACjC,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,OAAY,GACpB,OAAO,CAAC;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC,CAarD;AAED,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;CAajC,CAAC;AAEF,wBAAgB,0BAA0B,SAOzC;AAeD,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,OAAO,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,WAAW,EAAE,OAAO,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,8BAA8B;IAC7C,sBAAsB,CAAC,EAAE,OAAO,sBAAsB,CAAC;IACvD,oBAAoB,CAAC,EAAE,OAAO,oBAAoB,CAAC;IACnD,kBAAkB,CAAC,EAAE,OAAO,kBAAkB,CAAC;IAC/C,WAAW,CAAC,EAAE,OAAO,OAAO,CAAC;IAC7B,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,MAAM,CAAC;CAChC;AAED,wBAAgB,wBAAwB,CACtC,EACE,OAAO,EACP,aAAa,EACb,MAAM,EACN,mBAAmB,EACnB,WAAW,EACX,MAAM,EACN,eAAe,GAChB,EAAE,wBAAwB,EAC3B,EACE,sBAAsB,EAAE,gBAAyC,EACjE,oBAAoB,EAAE,cAAqC,EAC3D,kBAAkB,EAAE,WAAgC,EACpD,WAAqB,EACrB,GAAsB,EACtB,eAAoC,GACrC,GAAE,8BAAmC;sBASP;QAAE,GAAG,EAAE,OAAO,CAAC;QAAC,GAAG,EAAE,OAAO,CAAC;QAAC,YAAY,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAA;KAAE,KAAG,OAAO,CAAC,IAAI,CAAC;EAoHpH"}
@@ -0,0 +1,181 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { cloneRepository, createWorktree, ensureRepository, getWorktreePath, } from '../core/git.js';
3
+ import { launchAgentProcess } from '../core/agents.js';
4
+ import { runTask } from '../core/tasks.js';
5
+ import { sendJson } from '../utils/http.js';
6
+ import { validateAutomationRequest, AutomationRequestError, } from '../core/automation/request-validation.js';
7
+ import { resolveBranchName } from '../core/automation/branch.js';
8
+ import { generatePlanText } from '../core/automation/plan.js';
9
+ import { createGitOrchestrator } from '../core/automation/git-orchestration.js';
10
+ import { runAutomationTask } from '../core/automation/task-runner.js';
11
+ import { createLogger } from '../infrastructure/logging/index.js';
12
+ async function ensureRepositoryExists(workdir, org, repo) {
13
+ try {
14
+ const { repositoryPath } = await ensureRepository(workdir, org, repo);
15
+ return { repositoryPath, cloned: false };
16
+ }
17
+ catch (error) {
18
+ const err = error;
19
+ if (err && /Repository not found/i.test(err.message || '')) {
20
+ const remote = `git@github.com:${org}/${repo}.git`;
21
+ await cloneRepository(workdir, remote);
22
+ const { repositoryPath } = await ensureRepository(workdir, org, repo);
23
+ return { repositoryPath, cloned: true };
24
+ }
25
+ throw error;
26
+ }
27
+ }
28
+ async function ensureWorktreeExists(workdir, org, repo, branch, options = {}) {
29
+ try {
30
+ const { worktreePath } = await getWorktreePath(workdir, org, repo, branch);
31
+ return { worktreePath, created: false };
32
+ }
33
+ catch (error) {
34
+ const err = error;
35
+ if (err && /worktree .* not found/i.test(err.message || '')) {
36
+ await createWorktree(workdir, org, repo, branch, options);
37
+ const { worktreePath } = await getWorktreePath(workdir, org, repo, branch);
38
+ return { worktreePath, created: true };
39
+ }
40
+ throw error;
41
+ }
42
+ }
43
+ export const automationPlanMetrics = {
44
+ planTrue: {
45
+ requests: 0,
46
+ successes: 0,
47
+ failures: 0,
48
+ totalLatencyMs: 0,
49
+ },
50
+ planFalse: {
51
+ requests: 0,
52
+ successes: 0,
53
+ failures: 0,
54
+ totalLatencyMs: 0,
55
+ },
56
+ };
57
+ export function resetAutomationPlanMetrics() {
58
+ for (const bucket of Object.values(automationPlanMetrics)) {
59
+ bucket.requests = 0;
60
+ bucket.successes = 0;
61
+ bucket.failures = 0;
62
+ bucket.totalLatencyMs = 0;
63
+ }
64
+ }
65
+ function finishMetrics(key, success, durationMs) {
66
+ const bucket = automationPlanMetrics[key];
67
+ if (!bucket) {
68
+ return;
69
+ }
70
+ if (success) {
71
+ bucket.successes += 1;
72
+ }
73
+ else {
74
+ bucket.failures += 1;
75
+ }
76
+ bucket.totalLatencyMs += durationMs;
77
+ }
78
+ export function createAutomationHandlers({ workdir, agentCommands, apiKey, branchNameGenerator, planService, logger, defaultBranches, }, { ensureRepositoryExists: ensureRepoExists = ensureRepositoryExists, ensureWorktreeExists: ensureWorktree = ensureWorktreeExists, launchAgentProcess: launchAgent = launchAgentProcess, runTaskImpl = runTask, now = () => Date.now(), createRequestId = () => randomUUID(), } = {}) {
79
+ const gitOrchestrator = createGitOrchestrator({
80
+ ensureRepositoryExists: ensureRepoExists,
81
+ ensureWorktreeExists: ensureWorktree,
82
+ });
83
+ const log = createLogger(logger);
84
+ async function launch(context) {
85
+ const ctx = context;
86
+ let validation;
87
+ try {
88
+ validation = await validateAutomationRequest({
89
+ req: ctx.req,
90
+ expectedApiKey: apiKey || '',
91
+ readJsonBody: ctx.readJsonBody,
92
+ agentCommands,
93
+ });
94
+ }
95
+ catch (error) {
96
+ if (error instanceof AutomationRequestError) {
97
+ sendJson(ctx.res, error.status, { error: error.message });
98
+ return;
99
+ }
100
+ log.error('[agentrix] Automation validation failed unexpectedly.', error);
101
+ sendJson(ctx.res, 500, { error: 'Unexpected error while validating automation request' });
102
+ return;
103
+ }
104
+ const { planEnabled, prompt, org, repo, worktreeInput, agent, routeLabel } = validation;
105
+ const metricsKey = planEnabled ? 'planTrue' : 'planFalse';
106
+ automationPlanMetrics[metricsKey].requests += 1;
107
+ const requestId = createRequestId();
108
+ const startedAt = now();
109
+ const elapsedMs = () => {
110
+ const value = now() - startedAt;
111
+ return Number.isFinite(value) ? value : 0;
112
+ };
113
+ const finishSuccess = (detail) => {
114
+ const durationMs = elapsedMs();
115
+ finishMetrics(metricsKey, true, durationMs);
116
+ const suffix = detail ? `: ${detail}` : '';
117
+ log.info(`[agentrix] Automation request ${requestId} (${routeLabel}) completed in ${durationMs}ms${suffix}`);
118
+ };
119
+ const finishFailure = (message, error) => {
120
+ const durationMs = elapsedMs();
121
+ finishMetrics(metricsKey, false, durationMs);
122
+ if (error) {
123
+ log.error(`[agentrix] Automation request ${requestId} (${routeLabel}) failed after ${durationMs}ms: ${message}`, error);
124
+ }
125
+ else {
126
+ log.error(`[agentrix] Automation request ${requestId} (${routeLabel}) failed after ${durationMs}ms: ${message}`);
127
+ }
128
+ };
129
+ log.info(`[agentrix] Automation request ${requestId} (${routeLabel}) received.`);
130
+ if (planEnabled && !prompt.trim()) {
131
+ const message = 'prompt is required when plan is true';
132
+ finishFailure(message);
133
+ sendJson(ctx.res, 400, { error: message });
134
+ return;
135
+ }
136
+ const service = planService;
137
+ if (planEnabled && (!service || !service.isConfigured)) {
138
+ const message = 'Plan generation is not configured. Configure a local LLM command (set planLlm in config.json).';
139
+ finishFailure(message);
140
+ sendJson(ctx.res, 503, { error: message });
141
+ return;
142
+ }
143
+ try {
144
+ const result = (await runAutomationTask({
145
+ runTaskImpl: runTaskImpl,
146
+ resolveBranchName: resolveBranchName,
147
+ generatePlanText: generatePlanText,
148
+ gitOrchestrator,
149
+ launchAgent: launchAgent,
150
+ workdir,
151
+ planEnabled,
152
+ routeLabel,
153
+ prompt,
154
+ org,
155
+ repo,
156
+ agent: agent,
157
+ requestId,
158
+ worktreeInput,
159
+ branchNameGenerator,
160
+ defaultBranches,
161
+ planService,
162
+ finishSuccess: finishSuccess,
163
+ finishFailure: finishFailure,
164
+ onBranchResolved: (branch) => {
165
+ log.info(`[agentrix] Automation request ${requestId} (${routeLabel}) targeting ${org}/${repo}#${branch}.`);
166
+ },
167
+ }));
168
+ sendJson(ctx.res, 202, { taskId: result.taskId, data: result.queuedData });
169
+ }
170
+ catch (error) {
171
+ const status = error instanceof AutomationRequestError && typeof error.status === 'number'
172
+ ? error.status
173
+ : 500;
174
+ const message = error instanceof Error ? error.message : String(error);
175
+ finishFailure(message, error instanceof Error ? error : undefined);
176
+ sendJson(ctx.res, status, { error: message });
177
+ }
178
+ }
179
+ return { launch };
180
+ }
181
+ //# sourceMappingURL=automation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"automation.js","sourceRoot":"","sources":["../../src/api/automation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,62 @@
1
+ import type { RequestContext } from '../types/http.js';
2
+ /**
3
+ * Generic handler function type
4
+ */
5
+ export type HandlerFunction<TInput = unknown, TOutput = unknown> = (input: TInput, context: RequestContext) => Promise<TOutput>;
6
+ /**
7
+ * Validation function type
8
+ */
9
+ export type ValidationFunction<TInput = unknown> = (payload: unknown) => TInput;
10
+ /**
11
+ * Options for creating a handler
12
+ */
13
+ export interface HandlerOptions<TInput, TOutput> {
14
+ /**
15
+ * The service method to call
16
+ */
17
+ handler: HandlerFunction<TInput, TOutput>;
18
+ /**
19
+ * Optional validation function for request body
20
+ */
21
+ validator?: ValidationFunction<TInput>;
22
+ /**
23
+ * HTTP status code for successful response (default: 200)
24
+ */
25
+ successCode?: number;
26
+ /**
27
+ * Whether to read JSON body from request (default: true if validator is provided)
28
+ */
29
+ readBody?: boolean;
30
+ /**
31
+ * Custom response transformer (default: wraps result in { data: result })
32
+ */
33
+ responseTransformer?: (result: TOutput) => unknown;
34
+ }
35
+ /**
36
+ * Creates a standardized API handler with validation and error handling
37
+ *
38
+ * @example
39
+ * ```typescript
40
+ * const createUser = createHandler({
41
+ * handler: async (input, context) => userService.create(input),
42
+ * validator: validateUserCreate,
43
+ * successCode: 201
44
+ * });
45
+ * ```
46
+ */
47
+ export declare function createHandler<TInput = void, TOutput = unknown>(options: HandlerOptions<TInput, TOutput>): (context: RequestContext) => Promise<void>;
48
+ /**
49
+ * Creates a simple handler that doesn't require input validation
50
+ */
51
+ export declare function createSimpleHandler<TOutput = unknown>(handler: (context: RequestContext) => Promise<TOutput>, options?: {
52
+ successCode?: number;
53
+ responseTransformer?: (result: TOutput) => unknown;
54
+ }): (context: RequestContext) => Promise<void>;
55
+ /**
56
+ * Creates a handler for query parameter-based requests
57
+ */
58
+ export declare function createQueryHandler<TOutput = unknown>(handler: (context: RequestContext) => Promise<TOutput>, options?: {
59
+ successCode?: number;
60
+ responseTransformer?: (result: TOutput) => unknown;
61
+ }): (context: RequestContext) => Promise<void>;
62
+ //# sourceMappingURL=base-handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base-handler.d.ts","sourceRoot":"","sources":["../../src/api/base-handler.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAEvD;;GAEG;AACH,MAAM,MAAM,eAAe,CAAC,MAAM,GAAG,OAAO,EAAE,OAAO,GAAG,OAAO,IAAI,CACjE,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,cAAc,KACpB,OAAO,CAAC,OAAO,CAAC,CAAC;AAEtB;;GAEG;AACH,MAAM,MAAM,kBAAkB,CAAC,MAAM,GAAG,OAAO,IAAI,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,CAAC;AAEhF;;GAEG;AACH,MAAM,WAAW,cAAc,CAAC,MAAM,EAAE,OAAO;IAC7C;;OAEG;IACH,OAAO,EAAE,eAAe,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAE1C;;OAEG;IACH,SAAS,CAAC,EAAE,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAEvC;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;OAEG;IACH,mBAAmB,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,CAAC;CACpD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,MAAM,GAAG,IAAI,EAAE,OAAO,GAAG,OAAO,EAC5D,OAAO,EAAE,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC,GACvC,CAAC,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,CA2B5C;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,GAAG,OAAO,EACnD,OAAO,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC,OAAO,CAAC,EACtD,OAAO,GAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,mBAAmB,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,CAAA;CAAO,GACzF,CAAC,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,CAM5C;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,GAAG,OAAO,EAClD,OAAO,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC,OAAO,CAAC,EACtD,OAAO,GAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,mBAAmB,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,CAAA;CAAO,GACzF,CAAC,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,CAQ5C"}
@@ -0,0 +1,55 @@
1
+ import { sendJson } from '../utils/http.js';
2
+ import { asyncHandler } from '../infrastructure/errors/index.js';
3
+ /**
4
+ * Creates a standardized API handler with validation and error handling
5
+ *
6
+ * @example
7
+ * ```typescript
8
+ * const createUser = createHandler({
9
+ * handler: async (input, context) => userService.create(input),
10
+ * validator: validateUserCreate,
11
+ * successCode: 201
12
+ * });
13
+ * ```
14
+ */
15
+ export function createHandler(options) {
16
+ const { handler, validator, successCode = 200, readBody = Boolean(validator), responseTransformer, } = options;
17
+ return asyncHandler(async (context) => {
18
+ let input;
19
+ if (readBody) {
20
+ const payload = await context.readJsonBody();
21
+ input = validator ? validator(payload) : payload;
22
+ }
23
+ else {
24
+ input = undefined;
25
+ }
26
+ const result = await handler(input, context);
27
+ const response = responseTransformer
28
+ ? responseTransformer(result)
29
+ : result;
30
+ sendJson(context.res, successCode, response);
31
+ });
32
+ }
33
+ /**
34
+ * Creates a simple handler that doesn't require input validation
35
+ */
36
+ export function createSimpleHandler(handler, options = {}) {
37
+ return createHandler({
38
+ handler: async (_input, context) => handler(context),
39
+ readBody: false,
40
+ ...options,
41
+ });
42
+ }
43
+ /**
44
+ * Creates a handler for query parameter-based requests
45
+ */
46
+ export function createQueryHandler(handler, options = {}) {
47
+ return asyncHandler(async (context) => {
48
+ const result = await handler(context);
49
+ const response = options.responseTransformer
50
+ ? options.responseTransformer(result)
51
+ : result;
52
+ sendJson(context.res, options.successCode || 200, response);
53
+ });
54
+ }
55
+ //# sourceMappingURL=base-handler.js.map