@proletariat/cli 0.2.0 → 0.3.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 (526) hide show
  1. package/README.md +561 -251
  2. package/bin/dev.cmd +3 -0
  3. package/bin/dev.js +5 -0
  4. package/bin/run.cmd +3 -0
  5. package/bin/run.js +23 -0
  6. package/dist/commands/action/create.d.ts +21 -0
  7. package/dist/commands/action/create.js +126 -0
  8. package/dist/commands/action/delete.d.ts +17 -0
  9. package/dist/commands/action/delete.js +78 -0
  10. package/dist/commands/action/index.d.ts +15 -0
  11. package/dist/commands/action/index.js +107 -0
  12. package/dist/commands/action/list.d.ts +14 -0
  13. package/dist/commands/action/list.js +89 -0
  14. package/dist/commands/action/run.d.ts +19 -0
  15. package/dist/commands/action/run.js +179 -0
  16. package/dist/commands/action/show.d.ts +15 -0
  17. package/dist/commands/action/show.js +47 -0
  18. package/dist/commands/action/update.d.ts +22 -0
  19. package/dist/commands/action/update.js +168 -0
  20. package/dist/commands/agent/index.d.ts +13 -0
  21. package/dist/commands/agent/index.js +131 -0
  22. package/dist/commands/agent/list.d.ts +7 -0
  23. package/dist/commands/agent/list.js +126 -0
  24. package/dist/commands/agent/login.d.ts +16 -0
  25. package/dist/commands/agent/login.js +146 -0
  26. package/dist/commands/agent/rebuild.d.ts +18 -0
  27. package/dist/commands/agent/rebuild.js +133 -0
  28. package/dist/commands/agent/restart.d.ts +17 -0
  29. package/dist/commands/agent/restart.js +116 -0
  30. package/dist/commands/agent/shell.d.ts +23 -0
  31. package/dist/commands/agent/shell.js +378 -0
  32. package/dist/commands/agent/staff/add.d.ts +15 -0
  33. package/dist/commands/agent/staff/add.js +281 -0
  34. package/dist/commands/agent/staff/index.d.ts +14 -0
  35. package/dist/commands/agent/staff/index.js +90 -0
  36. package/dist/commands/agent/staff/list.d.ts +7 -0
  37. package/dist/commands/agent/staff/list.js +90 -0
  38. package/dist/commands/agent/staff/remove.d.ts +16 -0
  39. package/dist/commands/agent/staff/remove.js +137 -0
  40. package/dist/commands/agent/status.d.ts +17 -0
  41. package/dist/commands/agent/status.js +139 -0
  42. package/dist/commands/agent/temp/cleanup.d.ts +23 -0
  43. package/dist/commands/agent/temp/cleanup.js +388 -0
  44. package/dist/commands/agent/temp/index.d.ts +14 -0
  45. package/dist/commands/agent/temp/index.js +82 -0
  46. package/dist/commands/agent/temp/list.d.ts +7 -0
  47. package/dist/commands/agent/temp/list.js +108 -0
  48. package/dist/commands/agent/themes/add-names.d.ts +10 -0
  49. package/dist/commands/agent/themes/add-names.js +67 -0
  50. package/dist/commands/agent/themes/create.d.ts +13 -0
  51. package/dist/commands/agent/themes/create.js +66 -0
  52. package/dist/commands/agent/themes/index.d.ts +9 -0
  53. package/dist/commands/agent/themes/index.js +194 -0
  54. package/dist/commands/agent/themes/list.d.ts +6 -0
  55. package/dist/commands/agent/themes/list.js +41 -0
  56. package/dist/commands/agent/themes/set.d.ts +12 -0
  57. package/dist/commands/agent/themes/set.js +77 -0
  58. package/dist/commands/agent/visit.d.ts +16 -0
  59. package/dist/commands/agent/visit.js +88 -0
  60. package/dist/commands/autocomplete/setup.d.ts +14 -0
  61. package/dist/commands/autocomplete/setup.js +154 -0
  62. package/dist/commands/board/index.d.ts +17 -0
  63. package/dist/commands/board/index.js +255 -0
  64. package/dist/commands/board/watch.d.ts +13 -0
  65. package/dist/commands/board/watch.js +52 -0
  66. package/dist/commands/branch/create.d.ts +50 -0
  67. package/dist/commands/branch/create.js +624 -0
  68. package/dist/commands/branch/index.d.ts +13 -0
  69. package/dist/commands/branch/index.js +50 -0
  70. package/dist/commands/branch/list.d.ts +17 -0
  71. package/dist/commands/branch/list.js +120 -0
  72. package/dist/commands/branch/validate.d.ts +15 -0
  73. package/dist/commands/branch/validate.js +73 -0
  74. package/dist/commands/commit.d.ts +71 -0
  75. package/dist/commands/commit.js +499 -0
  76. package/dist/commands/docker/clean.d.ts +13 -0
  77. package/dist/commands/docker/clean.js +224 -0
  78. package/dist/commands/docker/index.d.ts +19 -0
  79. package/dist/commands/docker/index.js +274 -0
  80. package/dist/commands/docker/list.d.ts +16 -0
  81. package/dist/commands/docker/list.js +200 -0
  82. package/dist/commands/docker/logs.d.ts +14 -0
  83. package/dist/commands/docker/logs.js +118 -0
  84. package/dist/commands/docker/prune.d.ts +14 -0
  85. package/dist/commands/docker/prune.js +211 -0
  86. package/dist/commands/docker/restart.d.ts +14 -0
  87. package/dist/commands/docker/restart.js +129 -0
  88. package/dist/commands/docker/shell.d.ts +14 -0
  89. package/dist/commands/docker/shell.js +103 -0
  90. package/dist/commands/docker/start.d.ts +12 -0
  91. package/dist/commands/docker/start.js +92 -0
  92. package/dist/commands/docker/status.d.ts +7 -0
  93. package/dist/commands/docker/status.js +40 -0
  94. package/dist/commands/docker/stop.d.ts +14 -0
  95. package/dist/commands/docker/stop.js +134 -0
  96. package/dist/commands/docker/sync.d.ts +15 -0
  97. package/dist/commands/docker/sync.js +112 -0
  98. package/dist/commands/epic/activate.d.ts +13 -0
  99. package/dist/commands/epic/activate.js +118 -0
  100. package/dist/commands/epic/archive.d.ts +14 -0
  101. package/dist/commands/epic/archive.js +132 -0
  102. package/dist/commands/epic/create.d.ts +15 -0
  103. package/dist/commands/epic/create.js +137 -0
  104. package/dist/commands/epic/index.d.ts +13 -0
  105. package/dist/commands/epic/index.js +88 -0
  106. package/dist/commands/epic/link/block.d.ts +14 -0
  107. package/dist/commands/epic/link/block.js +79 -0
  108. package/dist/commands/epic/link/duplicates.d.ts +14 -0
  109. package/dist/commands/epic/link/duplicates.js +66 -0
  110. package/dist/commands/epic/link/index.d.ts +19 -0
  111. package/dist/commands/epic/link/index.js +242 -0
  112. package/dist/commands/epic/link/relates.d.ts +14 -0
  113. package/dist/commands/epic/link/relates.js +66 -0
  114. package/dist/commands/epic/link/remove.d.ts +16 -0
  115. package/dist/commands/epic/link/remove.js +89 -0
  116. package/dist/commands/epic/list.d.ts +11 -0
  117. package/dist/commands/epic/list.js +87 -0
  118. package/dist/commands/epic/move.d.ts +15 -0
  119. package/dist/commands/epic/move.js +184 -0
  120. package/dist/commands/epic/progress.d.ts +16 -0
  121. package/dist/commands/epic/progress.js +166 -0
  122. package/dist/commands/epic/project.d.ts +15 -0
  123. package/dist/commands/epic/project.js +219 -0
  124. package/dist/commands/epic/reorder.d.ts +21 -0
  125. package/dist/commands/epic/reorder.js +160 -0
  126. package/dist/commands/epic/spec.d.ts +15 -0
  127. package/dist/commands/epic/spec.js +191 -0
  128. package/dist/commands/epic/ticket.d.ts +18 -0
  129. package/dist/commands/epic/ticket.js +291 -0
  130. package/dist/commands/epic/view.d.ts +13 -0
  131. package/dist/commands/epic/view.js +117 -0
  132. package/dist/commands/execution/index.d.ts +13 -0
  133. package/dist/commands/execution/index.js +70 -0
  134. package/dist/commands/execution/list.d.ts +15 -0
  135. package/dist/commands/execution/list.js +144 -0
  136. package/dist/commands/execution/logs.d.ts +18 -0
  137. package/dist/commands/execution/logs.js +161 -0
  138. package/dist/commands/execution/stop.d.ts +22 -0
  139. package/dist/commands/execution/stop.js +248 -0
  140. package/dist/commands/gh/index.d.ts +9 -0
  141. package/dist/commands/gh/index.js +53 -0
  142. package/dist/commands/gh/login.d.ts +6 -0
  143. package/dist/commands/gh/login.js +57 -0
  144. package/dist/commands/gh/status.d.ts +6 -0
  145. package/dist/commands/gh/status.js +48 -0
  146. package/dist/commands/gh/token.d.ts +6 -0
  147. package/dist/commands/gh/token.js +59 -0
  148. package/dist/commands/init.d.ts +26 -0
  149. package/dist/commands/init.js +200 -0
  150. package/dist/commands/phase/create.d.ts +22 -0
  151. package/dist/commands/phase/create.js +123 -0
  152. package/dist/commands/phase/delete.d.ts +17 -0
  153. package/dist/commands/phase/delete.js +73 -0
  154. package/dist/commands/phase/list.d.ts +12 -0
  155. package/dist/commands/phase/list.js +76 -0
  156. package/dist/commands/phase/move.d.ts +17 -0
  157. package/dist/commands/phase/move.js +115 -0
  158. package/dist/commands/phase/template/apply.d.ts +17 -0
  159. package/dist/commands/phase/template/apply.js +106 -0
  160. package/dist/commands/phase/template/create.d.ts +16 -0
  161. package/dist/commands/phase/template/create.js +58 -0
  162. package/dist/commands/phase/template/delete.d.ts +17 -0
  163. package/dist/commands/phase/template/delete.js +98 -0
  164. package/dist/commands/phase/template/index.d.ts +15 -0
  165. package/dist/commands/phase/template/index.js +128 -0
  166. package/dist/commands/phase/template/list.d.ts +16 -0
  167. package/dist/commands/phase/template/list.js +95 -0
  168. package/dist/commands/phase/template/update.d.ts +17 -0
  169. package/dist/commands/phase/template/update.js +89 -0
  170. package/dist/commands/phase/update.d.ts +23 -0
  171. package/dist/commands/phase/update.js +174 -0
  172. package/dist/commands/pmo/init.d.ts +25 -0
  173. package/dist/commands/pmo/init.js +341 -0
  174. package/dist/commands/pr/create.d.ts +17 -0
  175. package/dist/commands/pr/create.js +242 -0
  176. package/dist/commands/pr/index.d.ts +9 -0
  177. package/dist/commands/pr/index.js +68 -0
  178. package/dist/commands/pr/link.d.ts +14 -0
  179. package/dist/commands/pr/link.js +212 -0
  180. package/dist/commands/pr/status.d.ts +12 -0
  181. package/dist/commands/pr/status.js +161 -0
  182. package/dist/commands/project/archive.d.ts +17 -0
  183. package/dist/commands/project/archive.js +83 -0
  184. package/dist/commands/project/create.d.ts +22 -0
  185. package/dist/commands/project/create.js +143 -0
  186. package/dist/commands/project/delete.d.ts +17 -0
  187. package/dist/commands/project/delete.js +128 -0
  188. package/dist/commands/project/index.d.ts +13 -0
  189. package/dist/commands/project/index.js +64 -0
  190. package/dist/commands/project/list.d.ts +14 -0
  191. package/dist/commands/project/list.js +96 -0
  192. package/dist/commands/project/spec.d.ts +18 -0
  193. package/dist/commands/project/spec.js +216 -0
  194. package/dist/commands/project/unarchive.d.ts +15 -0
  195. package/dist/commands/project/unarchive.js +35 -0
  196. package/dist/commands/project/view.d.ts +16 -0
  197. package/dist/commands/project/view.js +94 -0
  198. package/dist/commands/repo/add.d.ts +21 -0
  199. package/dist/commands/repo/add.js +118 -0
  200. package/dist/commands/repo/index.d.ts +13 -0
  201. package/dist/commands/repo/index.js +114 -0
  202. package/dist/commands/repo/list.d.ts +13 -0
  203. package/dist/commands/repo/list.js +96 -0
  204. package/dist/commands/repo/remove.d.ts +23 -0
  205. package/dist/commands/repo/remove.js +217 -0
  206. package/dist/commands/repo/view.d.ts +15 -0
  207. package/dist/commands/repo/view.js +99 -0
  208. package/dist/commands/session/attach.d.ts +40 -0
  209. package/dist/commands/session/attach.js +307 -0
  210. package/dist/commands/session/index.d.ts +13 -0
  211. package/dist/commands/session/index.js +64 -0
  212. package/dist/commands/session/list.d.ts +21 -0
  213. package/dist/commands/session/list.js +181 -0
  214. package/dist/commands/spec/create.d.ts +19 -0
  215. package/dist/commands/spec/create.js +130 -0
  216. package/dist/commands/spec/index.d.ts +13 -0
  217. package/dist/commands/spec/index.js +68 -0
  218. package/dist/commands/spec/link/depends.d.ts +14 -0
  219. package/dist/commands/spec/link/depends.js +64 -0
  220. package/dist/commands/spec/link/duplicates.d.ts +14 -0
  221. package/dist/commands/spec/link/duplicates.js +63 -0
  222. package/dist/commands/spec/link/index.d.ts +19 -0
  223. package/dist/commands/spec/link/index.js +200 -0
  224. package/dist/commands/spec/link/relates.d.ts +14 -0
  225. package/dist/commands/spec/link/relates.js +63 -0
  226. package/dist/commands/spec/link/remove.d.ts +16 -0
  227. package/dist/commands/spec/link/remove.js +94 -0
  228. package/dist/commands/spec/list.d.ts +12 -0
  229. package/dist/commands/spec/list.js +75 -0
  230. package/dist/commands/spec/plan.d.ts +15 -0
  231. package/dist/commands/spec/plan.js +108 -0
  232. package/dist/commands/spec/ticket.d.ts +18 -0
  233. package/dist/commands/spec/ticket.js +160 -0
  234. package/dist/commands/spec/view.d.ts +15 -0
  235. package/dist/commands/spec/view.js +163 -0
  236. package/dist/commands/status/create.d.ts +21 -0
  237. package/dist/commands/status/create.js +140 -0
  238. package/dist/commands/status/delete.d.ts +13 -0
  239. package/dist/commands/status/delete.js +77 -0
  240. package/dist/commands/status/index.d.ts +14 -0
  241. package/dist/commands/status/index.js +91 -0
  242. package/dist/commands/status/list.d.ts +12 -0
  243. package/dist/commands/status/list.js +93 -0
  244. package/dist/commands/status/move.d.ts +14 -0
  245. package/dist/commands/status/move.js +120 -0
  246. package/dist/commands/status/update.d.ts +20 -0
  247. package/dist/commands/status/update.js +180 -0
  248. package/dist/commands/template/delete.d.ts +15 -0
  249. package/dist/commands/template/delete.js +142 -0
  250. package/dist/commands/template/index.d.ts +10 -0
  251. package/dist/commands/template/index.js +64 -0
  252. package/dist/commands/template/list.d.ts +18 -0
  253. package/dist/commands/template/list.js +157 -0
  254. package/dist/commands/template/phase/apply.d.ts +14 -0
  255. package/dist/commands/template/phase/apply.js +41 -0
  256. package/dist/commands/template/phase/create.d.ts +12 -0
  257. package/dist/commands/template/phase/create.js +29 -0
  258. package/dist/commands/template/phase/delete.d.ts +13 -0
  259. package/dist/commands/template/phase/delete.js +34 -0
  260. package/dist/commands/template/phase/index.d.ts +10 -0
  261. package/dist/commands/template/phase/index.js +62 -0
  262. package/dist/commands/template/phase/list.d.ts +11 -0
  263. package/dist/commands/template/phase/list.js +34 -0
  264. package/dist/commands/template/phase/update.d.ts +13 -0
  265. package/dist/commands/template/phase/update.js +35 -0
  266. package/dist/commands/template/ticket/apply.d.ts +17 -0
  267. package/dist/commands/template/ticket/apply.js +58 -0
  268. package/dist/commands/template/ticket/delete.d.ts +13 -0
  269. package/dist/commands/template/ticket/delete.js +34 -0
  270. package/dist/commands/template/ticket/index.d.ts +10 -0
  271. package/dist/commands/template/ticket/index.js +62 -0
  272. package/dist/commands/template/ticket/list.d.ts +11 -0
  273. package/dist/commands/template/ticket/list.js +34 -0
  274. package/dist/commands/template/ticket/save.d.ts +13 -0
  275. package/dist/commands/template/ticket/save.js +35 -0
  276. package/dist/commands/ticket/bulk.d.ts +13 -0
  277. package/dist/commands/ticket/bulk.js +145 -0
  278. package/dist/commands/ticket/complete.d.ts +16 -0
  279. package/dist/commands/ticket/complete.js +170 -0
  280. package/dist/commands/ticket/create.d.ts +22 -0
  281. package/dist/commands/ticket/create.js +390 -0
  282. package/dist/commands/ticket/delete.d.ts +16 -0
  283. package/dist/commands/ticket/delete.js +178 -0
  284. package/dist/commands/ticket/edit.d.ts +27 -0
  285. package/dist/commands/ticket/edit.js +322 -0
  286. package/dist/commands/ticket/epic.d.ts +20 -0
  287. package/dist/commands/ticket/epic.js +333 -0
  288. package/dist/commands/ticket/index.d.ts +13 -0
  289. package/dist/commands/ticket/index.js +103 -0
  290. package/dist/commands/ticket/link/block.d.ts +14 -0
  291. package/dist/commands/ticket/link/block.js +94 -0
  292. package/dist/commands/ticket/link/duplicates.d.ts +14 -0
  293. package/dist/commands/ticket/link/duplicates.js +93 -0
  294. package/dist/commands/ticket/link/index.d.ts +19 -0
  295. package/dist/commands/ticket/link/index.js +239 -0
  296. package/dist/commands/ticket/link/relates.d.ts +14 -0
  297. package/dist/commands/ticket/link/relates.js +93 -0
  298. package/dist/commands/ticket/link/remove.d.ts +16 -0
  299. package/dist/commands/ticket/link/remove.js +128 -0
  300. package/dist/commands/ticket/list.d.ts +24 -0
  301. package/dist/commands/ticket/list.js +431 -0
  302. package/dist/commands/ticket/move.d.ts +18 -0
  303. package/dist/commands/ticket/move.js +212 -0
  304. package/dist/commands/ticket/project.d.ts +18 -0
  305. package/dist/commands/ticket/project.js +254 -0
  306. package/dist/commands/ticket/reassign.d.ts +19 -0
  307. package/dist/commands/ticket/reassign.js +279 -0
  308. package/dist/commands/ticket/spec.d.ts +18 -0
  309. package/dist/commands/ticket/spec.js +259 -0
  310. package/dist/commands/ticket/status.d.ts +13 -0
  311. package/dist/commands/ticket/status.js +87 -0
  312. package/dist/commands/ticket/template/apply.d.ts +25 -0
  313. package/dist/commands/ticket/template/apply.js +249 -0
  314. package/dist/commands/ticket/template/create.d.ts +19 -0
  315. package/dist/commands/ticket/template/create.js +210 -0
  316. package/dist/commands/ticket/template/delete.d.ts +17 -0
  317. package/dist/commands/ticket/template/delete.js +92 -0
  318. package/dist/commands/ticket/template/index.d.ts +15 -0
  319. package/dist/commands/ticket/template/index.js +118 -0
  320. package/dist/commands/ticket/template/list.d.ts +16 -0
  321. package/dist/commands/ticket/template/list.js +110 -0
  322. package/dist/commands/ticket/template/save.d.ts +14 -0
  323. package/dist/commands/ticket/template/save.js +110 -0
  324. package/dist/commands/ticket/update.d.ts +18 -0
  325. package/dist/commands/ticket/update.js +325 -0
  326. package/dist/commands/ticket/view.d.ts +13 -0
  327. package/dist/commands/ticket/view.js +80 -0
  328. package/dist/commands/whoami.d.ts +9 -0
  329. package/dist/commands/whoami.js +103 -0
  330. package/dist/commands/work/complete.d.ts +13 -0
  331. package/dist/commands/work/complete.js +121 -0
  332. package/dist/commands/work/index.d.ts +13 -0
  333. package/dist/commands/work/index.js +70 -0
  334. package/dist/commands/work/ready.d.ts +24 -0
  335. package/dist/commands/work/ready.js +290 -0
  336. package/dist/commands/work/revise.d.ts +19 -0
  337. package/dist/commands/work/revise.js +377 -0
  338. package/dist/commands/work/spawn-all.d.ts +17 -0
  339. package/dist/commands/work/spawn-all.js +58 -0
  340. package/dist/commands/work/spawn.d.ts +29 -0
  341. package/dist/commands/work/spawn.js +728 -0
  342. package/dist/commands/work/start.d.ts +39 -0
  343. package/dist/commands/work/start.js +1393 -0
  344. package/dist/commands/work/watch.d.ts +31 -0
  345. package/dist/commands/work/watch.js +359 -0
  346. package/dist/commands/workflow/create.d.ts +18 -0
  347. package/dist/commands/workflow/create.js +119 -0
  348. package/dist/commands/workflow/delete.d.ts +17 -0
  349. package/dist/commands/workflow/delete.js +119 -0
  350. package/dist/commands/workflow/index.d.ts +15 -0
  351. package/dist/commands/workflow/index.js +75 -0
  352. package/dist/commands/workflow/list.d.ts +15 -0
  353. package/dist/commands/workflow/list.js +75 -0
  354. package/dist/commands/workflow/switch.d.ts +13 -0
  355. package/dist/commands/workflow/switch.js +117 -0
  356. package/dist/commands/workflow/view.d.ts +16 -0
  357. package/dist/commands/workflow/view.js +114 -0
  358. package/dist/commands/workspace/add.d.ts +12 -0
  359. package/dist/commands/workspace/add.js +74 -0
  360. package/dist/commands/workspace/list.d.ts +9 -0
  361. package/dist/commands/workspace/list.js +153 -0
  362. package/dist/commands/workspace/remove.d.ts +13 -0
  363. package/dist/commands/workspace/remove.js +98 -0
  364. package/dist/commands/workspace/use.d.ts +12 -0
  365. package/dist/commands/workspace/use.js +111 -0
  366. package/dist/hooks/init.d.ts +11 -0
  367. package/dist/hooks/init.js +57 -0
  368. package/dist/index.d.ts +1 -0
  369. package/dist/index.js +1 -0
  370. package/dist/lib/agents/commands.d.ts +189 -0
  371. package/dist/lib/agents/commands.js +893 -0
  372. package/dist/lib/agents/index.d.ts +54 -0
  373. package/dist/lib/agents/index.js +382 -0
  374. package/dist/lib/branch/index.d.ts +120 -0
  375. package/dist/lib/branch/index.js +334 -0
  376. package/dist/lib/colors.d.ts +94 -0
  377. package/dist/lib/colors.js +68 -0
  378. package/dist/lib/commands/docker-command.d.ts +21 -0
  379. package/dist/lib/commands/docker-command.js +27 -0
  380. package/dist/lib/database/index.d.ts +176 -0
  381. package/dist/lib/database/index.js +581 -0
  382. package/dist/lib/docker/resolve.d.ts +38 -0
  383. package/dist/lib/docker/resolve.js +175 -0
  384. package/dist/lib/execution/config.d.ts +150 -0
  385. package/dist/lib/execution/config.js +541 -0
  386. package/dist/lib/execution/devcontainer.d.ts +85 -0
  387. package/dist/lib/execution/devcontainer.js +594 -0
  388. package/dist/lib/execution/index.d.ts +10 -0
  389. package/dist/lib/execution/index.js +10 -0
  390. package/dist/lib/execution/runners.d.ts +53 -0
  391. package/dist/lib/execution/runners.js +1182 -0
  392. package/dist/lib/execution/spawner.d.ts +85 -0
  393. package/dist/lib/execution/spawner.js +548 -0
  394. package/dist/lib/execution/storage.d.ts +159 -0
  395. package/dist/lib/execution/storage.js +425 -0
  396. package/dist/lib/execution/types.d.ts +145 -0
  397. package/dist/lib/execution/types.js +157 -0
  398. package/dist/lib/init/index.d.ts +75 -0
  399. package/dist/lib/init/index.js +355 -0
  400. package/dist/lib/machine-config.d.ts +170 -0
  401. package/dist/lib/machine-config.js +386 -0
  402. package/dist/lib/pmo/base-command.d.ts +195 -0
  403. package/dist/lib/pmo/base-command.js +319 -0
  404. package/dist/lib/pmo/create-spec-folders.d.ts +43 -0
  405. package/dist/lib/pmo/create-spec-folders.js +64 -0
  406. package/dist/lib/pmo/epic-files.d.ts +56 -0
  407. package/dist/lib/pmo/epic-files.js +195 -0
  408. package/dist/lib/pmo/find-pmo.d.ts +14 -0
  409. package/dist/lib/pmo/find-pmo.js +172 -0
  410. package/dist/lib/pmo/index.d.ts +109 -0
  411. package/dist/lib/pmo/index.js +501 -0
  412. package/dist/lib/pmo/markdown.d.ts +31 -0
  413. package/dist/lib/pmo/markdown.js +245 -0
  414. package/dist/lib/pmo/pmo-context.d.ts +27 -0
  415. package/dist/lib/pmo/pmo-context.js +44 -0
  416. package/dist/lib/pmo/schema.d.ts +82 -0
  417. package/dist/lib/pmo/schema.js +531 -0
  418. package/dist/lib/pmo/spec-parser.d.ts +25 -0
  419. package/dist/lib/pmo/spec-parser.js +205 -0
  420. package/dist/lib/pmo/spec-types.d.ts +43 -0
  421. package/dist/lib/pmo/spec-types.js +7 -0
  422. package/dist/lib/pmo/storage/actions.d.ts +34 -0
  423. package/dist/lib/pmo/storage/actions.js +177 -0
  424. package/dist/lib/pmo/storage/base.d.ts +47 -0
  425. package/dist/lib/pmo/storage/base.js +858 -0
  426. package/dist/lib/pmo/storage/dependencies.d.ts +61 -0
  427. package/dist/lib/pmo/storage/dependencies.js +267 -0
  428. package/dist/lib/pmo/storage/epics.d.ts +46 -0
  429. package/dist/lib/pmo/storage/epics.js +243 -0
  430. package/dist/lib/pmo/storage/helpers.d.ts +33 -0
  431. package/dist/lib/pmo/storage/helpers.js +148 -0
  432. package/dist/lib/pmo/storage/index.d.ts +186 -0
  433. package/dist/lib/pmo/storage/index.js +689 -0
  434. package/dist/lib/pmo/storage/phases.d.ts +65 -0
  435. package/dist/lib/pmo/storage/phases.js +392 -0
  436. package/dist/lib/pmo/storage/projects.d.ts +79 -0
  437. package/dist/lib/pmo/storage/projects.js +303 -0
  438. package/dist/lib/pmo/storage/specs.d.ts +77 -0
  439. package/dist/lib/pmo/storage/specs.js +389 -0
  440. package/dist/lib/pmo/storage/statuses.d.ts +63 -0
  441. package/dist/lib/pmo/storage/statuses.js +404 -0
  442. package/dist/lib/pmo/storage/subtasks.d.ts +37 -0
  443. package/dist/lib/pmo/storage/subtasks.js +184 -0
  444. package/dist/lib/pmo/storage/templates.d.ts +40 -0
  445. package/dist/lib/pmo/storage/templates.js +210 -0
  446. package/dist/lib/pmo/storage/tickets.d.ts +57 -0
  447. package/dist/lib/pmo/storage/tickets.js +453 -0
  448. package/dist/lib/pmo/storage/types.d.ts +200 -0
  449. package/dist/lib/pmo/storage/types.js +5 -0
  450. package/dist/lib/pmo/storage/views.d.ts +44 -0
  451. package/dist/lib/pmo/storage/views.js +355 -0
  452. package/dist/lib/pmo/storage-sqlite.d.ts +7 -0
  453. package/dist/lib/pmo/storage-sqlite.js +7 -0
  454. package/dist/lib/pmo/sync-manager.d.ts +92 -0
  455. package/dist/lib/pmo/sync-manager.js +229 -0
  456. package/dist/lib/pmo/types.d.ts +710 -0
  457. package/dist/lib/pmo/types.js +108 -0
  458. package/dist/lib/pmo/utils.d.ts +122 -0
  459. package/dist/lib/pmo/utils.js +174 -0
  460. package/dist/lib/pmo/watcher.d.ts +43 -0
  461. package/dist/lib/pmo/watcher.js +208 -0
  462. package/dist/lib/pr/index.d.ts +150 -0
  463. package/dist/lib/pr/index.js +483 -0
  464. package/dist/lib/prompt-json.d.ts +231 -0
  465. package/dist/lib/prompt-json.js +213 -0
  466. package/dist/lib/repos/index.d.ts +81 -0
  467. package/dist/lib/repos/index.js +679 -0
  468. package/dist/lib/styles.d.ts +98 -0
  469. package/dist/lib/styles.js +195 -0
  470. package/dist/lib/themes.d.ts +128 -0
  471. package/dist/lib/themes.js +301 -0
  472. package/dist/lib/ui/BoardUI.d.ts +21 -0
  473. package/dist/lib/ui/BoardUI.js +85 -0
  474. package/dist/lib/ui/ClaimTicketUI.d.ts +17 -0
  475. package/dist/lib/ui/ClaimTicketUI.js +64 -0
  476. package/dist/lib/ui/CreateTicketUI.d.ts +13 -0
  477. package/dist/lib/ui/CreateTicketUI.js +101 -0
  478. package/dist/lib/workspace.d.ts +66 -0
  479. package/dist/lib/workspace.js +204 -0
  480. package/oclif.manifest.json +10593 -0
  481. package/package.json +103 -56
  482. package/LICENSE +0 -21
  483. package/dist/bin/prlt.d.ts +0 -11
  484. package/dist/bin/prlt.d.ts.map +0 -1
  485. package/dist/bin/prlt.js +0 -144
  486. package/dist/bin/prlt.js.map +0 -1
  487. package/dist/lib/config/index.d.ts +0 -14
  488. package/dist/lib/config/index.d.ts.map +0 -1
  489. package/dist/lib/config/index.js +0 -142
  490. package/dist/lib/config/index.js.map +0 -1
  491. package/dist/lib/config/upgrade.d.ts +0 -2
  492. package/dist/lib/config/upgrade.d.ts.map +0 -1
  493. package/dist/lib/config/upgrade.js +0 -248
  494. package/dist/lib/config/upgrade.js.map +0 -1
  495. package/dist/lib/themes/index.d.ts +0 -8
  496. package/dist/lib/themes/index.d.ts.map +0 -1
  497. package/dist/lib/themes/index.js +0 -80
  498. package/dist/lib/themes/index.js.map +0 -1
  499. package/dist/lib/utils/helpers.d.ts +0 -4
  500. package/dist/lib/utils/helpers.d.ts.map +0 -1
  501. package/dist/lib/utils/helpers.js +0 -39
  502. package/dist/lib/utils/helpers.js.map +0 -1
  503. package/dist/lib/utils/logger.d.ts +0 -4
  504. package/dist/lib/utils/logger.d.ts.map +0 -1
  505. package/dist/lib/utils/logger.js +0 -28
  506. package/dist/lib/utils/logger.js.map +0 -1
  507. package/dist/lib/workspace/index.d.ts +0 -13
  508. package/dist/lib/workspace/index.d.ts.map +0 -1
  509. package/dist/lib/workspace/index.js +0 -116
  510. package/dist/lib/workspace/index.js.map +0 -1
  511. package/dist/lib/worktree/index.d.ts +0 -7
  512. package/dist/lib/worktree/index.d.ts.map +0 -1
  513. package/dist/lib/worktree/index.js +0 -362
  514. package/dist/lib/worktree/index.js.map +0 -1
  515. package/dist/lib/worktree/migrate.d.ts +0 -2
  516. package/dist/lib/worktree/migrate.d.ts.map +0 -1
  517. package/dist/lib/worktree/migrate.js +0 -214
  518. package/dist/lib/worktree/migrate.js.map +0 -1
  519. package/dist/lib/worktree/repair.d.ts +0 -3
  520. package/dist/lib/worktree/repair.d.ts.map +0 -1
  521. package/dist/lib/worktree/repair.js +0 -320
  522. package/dist/lib/worktree/repair.js.map +0 -1
  523. package/dist/types/index.d.ts +0 -57
  524. package/dist/types/index.d.ts.map +0 -1
  525. package/dist/types/index.js +0 -3
  526. package/dist/types/index.js.map +0 -1
@@ -0,0 +1,893 @@
1
+ /**
2
+ * Shared utilities for agent commands - implementing DRY principles
3
+ */
4
+ import * as fs from 'node:fs';
5
+ import * as path from 'node:path';
6
+ import { execSync } from 'node:child_process';
7
+ import inquirer from 'inquirer';
8
+ import { getWorkspaceConfig, getWorkspaceAgents, getWorkspaceRepositories, getAgentWorktrees, addAgentsToDatabase, removeAgentsFromDatabase, addEphemeralAgentToDatabase, getEphemeralAgentNames, getActiveTheme, markAgentCleaned, syncAgentsWithDisk } from '../database/index.js';
9
+ import { isValidAgentName, getSuggestedAgentNames, generateEphemeralAgentName, getThemePersistentDir, getThemeEphemeralDir, } from '../themes.js';
10
+ import { createDevcontainerConfig } from '../execution/devcontainer.js';
11
+ import { getPMOContext } from '../pmo/index.js';
12
+ /**
13
+ * Find workspace root and return workspace information.
14
+ *
15
+ * Search priority:
16
+ * 1. PRLT_HQ_PATH environment variable (ONLY when DEVCONTAINER=true - for devcontainer mounts)
17
+ * 2. Current directory tree for HQ with workspace.db
18
+ *
19
+ * NOTE: PRLT_HQ_PATH is ignored on host machines to support multiple agents
20
+ * working in different workspaces simultaneously.
21
+ */
22
+ export function getWorkspaceInfo() {
23
+ // Check PRLT_HQ_PATH environment variable (only in devcontainers)
24
+ const hqPath = process.env.PRLT_HQ_PATH;
25
+ const isDevcontainer = process.env.DEVCONTAINER === 'true';
26
+ if (hqPath && isDevcontainer) {
27
+ const dbPath = path.join(hqPath, '.proletariat', 'workspace.db');
28
+ if (fs.existsSync(dbPath)) {
29
+ try {
30
+ const config = getWorkspaceConfig(hqPath);
31
+ if (config) {
32
+ // Sync agents with disk - mark missing ones as cleaned
33
+ syncAgentsWithDisk(hqPath);
34
+ const agents = getWorkspaceAgents(hqPath);
35
+ const repositories = getWorkspaceRepositories(hqPath);
36
+ const activeTheme = getActiveTheme(hqPath);
37
+ const persistentAgentsDir = getThemePersistentDir(activeTheme?.id);
38
+ const ephemeralAgentsDir = getThemeEphemeralDir(activeTheme?.id);
39
+ const agentsPath = config.type === 'hq'
40
+ ? path.join(hqPath, 'agents', persistentAgentsDir)
41
+ : hqPath;
42
+ return {
43
+ path: hqPath,
44
+ type: config.type,
45
+ workspaceName: config.workspace_name,
46
+ hasPMO: config.has_pmo,
47
+ agents,
48
+ repositories,
49
+ agentsPath,
50
+ activeThemeId: activeTheme?.id ?? null,
51
+ persistentAgentsDir,
52
+ ephemeralAgentsDir,
53
+ };
54
+ }
55
+ }
56
+ catch {
57
+ // Continue to directory tree search if PRLT_HQ_PATH is invalid
58
+ }
59
+ }
60
+ }
61
+ // Search up the directory tree
62
+ let currentDir = process.cwd();
63
+ while (currentDir !== '/') {
64
+ const dbPath = path.join(currentDir, '.proletariat', 'workspace.db');
65
+ if (fs.existsSync(dbPath)) {
66
+ try {
67
+ const config = getWorkspaceConfig(currentDir);
68
+ if (config) {
69
+ // Sync agents with disk - mark missing ones as cleaned
70
+ syncAgentsWithDisk(currentDir);
71
+ const agents = getWorkspaceAgents(currentDir);
72
+ const repositories = getWorkspaceRepositories(currentDir);
73
+ const activeTheme = getActiveTheme(currentDir);
74
+ const persistentAgentsDir = getThemePersistentDir(activeTheme?.id);
75
+ const ephemeralAgentsDir = getThemeEphemeralDir(activeTheme?.id);
76
+ const agentsPath = config.type === 'hq'
77
+ ? path.join(currentDir, 'agents', persistentAgentsDir)
78
+ : currentDir;
79
+ return {
80
+ path: currentDir,
81
+ type: config.type,
82
+ workspaceName: config.workspace_name,
83
+ hasPMO: config.has_pmo,
84
+ agents,
85
+ repositories,
86
+ agentsPath,
87
+ activeThemeId: activeTheme?.id ?? null,
88
+ persistentAgentsDir,
89
+ ephemeralAgentsDir,
90
+ };
91
+ }
92
+ }
93
+ catch {
94
+ // Continue searching if database is corrupted
95
+ }
96
+ }
97
+ currentDir = path.dirname(currentDir);
98
+ }
99
+ throw new Error('Not in an HQ or workspace directory. Run "prlt init" first.');
100
+ }
101
+ /**
102
+ * Validate agent name
103
+ */
104
+ export { isValidAgentName } from '../themes.js';
105
+ /**
106
+ * Get suggested agent names (not yet added to workspace)
107
+ */
108
+ export function getAvailableAgentSuggestions(workspaceInfo) {
109
+ const existingAgentNames = new Set(workspaceInfo.agents.map(a => a.name));
110
+ return getSuggestedAgentNames().filter(name => !existingAgentNames.has(name));
111
+ }
112
+ /**
113
+ * Interactive agent selection - prompts user for agent names
114
+ */
115
+ export async function selectAgentsInteractively(workspaceInfo, message = 'Enter agent names:') {
116
+ const suggestions = getAvailableAgentSuggestions(workspaceInfo);
117
+ const { agentNames } = await inquirer.prompt([{
118
+ type: 'input',
119
+ name: 'agentNames',
120
+ message: `${message} (space-separated, e.g., "${suggestions.slice(0, 2).join(' ')}"):`,
121
+ validate: (input) => {
122
+ if (!input.trim()) {
123
+ return 'Please enter at least one agent name';
124
+ }
125
+ const names = input.trim().split(/\s+/);
126
+ const invalid = names.filter(n => !isValidAgentName(n));
127
+ if (invalid.length > 0) {
128
+ return `Invalid agent names: ${invalid.join(', ')}. Names must be lowercase alphanumeric with optional hyphens/underscores.`;
129
+ }
130
+ return true;
131
+ },
132
+ }]);
133
+ return agentNames.trim().split(/\s+/).filter(Boolean);
134
+ }
135
+ /**
136
+ * Interactive selection from existing agents
137
+ */
138
+ export async function selectExistingAgentsInteractively(workspaceInfo, message = 'Select agents:') {
139
+ if (workspaceInfo.agents.length === 0) {
140
+ throw new Error('No agents found in workspace.');
141
+ }
142
+ const { selected } = await inquirer.prompt([{
143
+ type: 'checkbox',
144
+ name: 'selected',
145
+ message,
146
+ choices: workspaceInfo.agents.map(agent => ({ name: agent.name, value: agent.name })),
147
+ validate: (input) => input.length > 0 || 'Please select at least one agent'
148
+ }]);
149
+ return selected;
150
+ }
151
+ /**
152
+ * Get detailed status for a specific agent
153
+ */
154
+ export function getAgentStatus(workspaceInfo, agentName) {
155
+ // Agent exists if it's in the database - the source of truth
156
+ const agentRecord = workspaceInfo.agents.find(a => a.name === agentName);
157
+ const exists = !!agentRecord;
158
+ // Get worktrees from database to find actual agent location
159
+ const worktrees = getAgentWorktrees(workspaceInfo.path, agentName);
160
+ // Derive agent directory from worktree path, or fall back to default
161
+ let agentDir = path.join(workspaceInfo.agentsPath, agentName);
162
+ if (worktrees.length > 0) {
163
+ // worktree_path is like "agents/staff/altman/proletariat-altman"
164
+ // Agent dir is the parent: "agents/staff/altman"
165
+ const worktreePath = worktrees[0].worktree_path;
166
+ const agentDirRelative = path.dirname(worktreePath);
167
+ agentDir = path.join(workspaceInfo.path, agentDirRelative);
168
+ }
169
+ const dirExists = fs.existsSync(agentDir);
170
+ const status = {
171
+ name: agentName,
172
+ exists,
173
+ assignedTickets: [],
174
+ completedTickets: [],
175
+ repositories: []
176
+ };
177
+ if (!dirExists) {
178
+ return status;
179
+ }
180
+ // Get git branch info
181
+ try {
182
+ const gitDir = path.join(agentDir, '.git');
183
+ if (fs.existsSync(gitDir)) {
184
+ const gitContent = fs.readFileSync(gitDir, 'utf-8');
185
+ const branchMatch = gitContent.match(/gitdir: (.+)/);
186
+ if (branchMatch) {
187
+ status.branch = branchMatch[1].split('/').pop()?.replace('.git', '');
188
+ }
189
+ }
190
+ }
191
+ catch {
192
+ // Ignore git reading errors
193
+ }
194
+ // Get repository status from database worktrees
195
+ status.repositories = worktrees.map(worktree => {
196
+ const repoPath = path.join(workspaceInfo.path, worktree.worktree_path);
197
+ const repoExists = fs.existsSync(repoPath);
198
+ let repoStatus = 'missing';
199
+ let commitsAhead = 0;
200
+ if (repoExists) {
201
+ try {
202
+ // Check if clean
203
+ const gitStatus = execSync('git status --porcelain', {
204
+ cwd: repoPath,
205
+ encoding: 'utf-8',
206
+ stdio: 'pipe'
207
+ });
208
+ repoStatus = gitStatus.trim() === '' ? 'clean' : 'dirty';
209
+ // Check commits ahead
210
+ try {
211
+ const ahead = execSync('git rev-list --count HEAD ^origin/main', {
212
+ cwd: repoPath,
213
+ encoding: 'utf-8',
214
+ stdio: 'pipe'
215
+ }).trim();
216
+ commitsAhead = parseInt(ahead) || 0;
217
+ }
218
+ catch {
219
+ // Ignore if can't determine commits ahead
220
+ }
221
+ }
222
+ catch {
223
+ repoStatus = 'error';
224
+ }
225
+ }
226
+ return {
227
+ name: worktree.repo_name,
228
+ status: repoStatus,
229
+ commitsAhead
230
+ };
231
+ });
232
+ // Get ticket assignments (if PMO enabled)
233
+ if (workspaceInfo.hasPMO) {
234
+ try {
235
+ const ticketsFile = path.join(workspaceInfo.path, 'pmo', 'tickets.json');
236
+ if (fs.existsSync(ticketsFile)) {
237
+ const tickets = JSON.parse(fs.readFileSync(ticketsFile, 'utf-8'));
238
+ status.assignedTickets = tickets
239
+ .filter((t) => t.assignee === agentName && t.status !== 'done')
240
+ .map((t) => t.id);
241
+ status.completedTickets = tickets
242
+ .filter((t) => t.assignee === agentName && t.status === 'done')
243
+ .map((t) => t.id);
244
+ }
245
+ }
246
+ catch {
247
+ // Ignore ticket loading errors
248
+ }
249
+ }
250
+ return status;
251
+ }
252
+ /**
253
+ * Get status for all agents
254
+ */
255
+ export function getAllAgentsStatus(workspaceInfo) {
256
+ return workspaceInfo.agents.map(agent => getAgentStatus(workspaceInfo, agent.name));
257
+ }
258
+ /**
259
+ * Validate agent names (must be valid format)
260
+ */
261
+ export function validateAgentNames(agentNames) {
262
+ const valid = [];
263
+ const invalid = [];
264
+ for (const name of agentNames) {
265
+ if (isValidAgentName(name)) {
266
+ valid.push(name);
267
+ }
268
+ else {
269
+ invalid.push(name);
270
+ }
271
+ }
272
+ return { valid, invalid };
273
+ }
274
+ /**
275
+ * Create agent worktrees and update database
276
+ */
277
+ export async function addAgentsToWorkspace(workspaceInfo, agentNames, options) {
278
+ // Import dynamically to avoid circular dependency
279
+ const { createAgentWorktrees } = await import('./index.js');
280
+ // Filter out existing agents
281
+ const existingNames = new Set(workspaceInfo.agents.map(a => a.name));
282
+ const newAgents = agentNames.filter(name => !existingNames.has(name));
283
+ if (newAgents.length === 0) {
284
+ return [];
285
+ }
286
+ // Create worktrees
287
+ if (workspaceInfo.type === 'hq') {
288
+ await createAgentWorktrees(workspaceInfo.agentsPath, newAgents, workspaceInfo.path, options);
289
+ }
290
+ else {
291
+ await createAgentWorktrees(workspaceInfo.agentsPath, newAgents, undefined, options);
292
+ }
293
+ // Add to database (with optional theme ID)
294
+ addAgentsToDatabase(workspaceInfo.path, newAgents, options?.themeId);
295
+ return newAgents;
296
+ }
297
+ /**
298
+ * Remove agents and clean up worktrees
299
+ */
300
+ export async function removeAgentsFromWorkspace(workspaceInfo, agentNames) {
301
+ const removed = [];
302
+ const failed = [];
303
+ for (const agentName of agentNames) {
304
+ try {
305
+ const agentDir = path.join(workspaceInfo.agentsPath, agentName);
306
+ // Stop and remove Docker container if it exists
307
+ try {
308
+ const containerId = execSync(`docker ps -aq --filter "label=devcontainer.local_folder=${agentDir}"`, { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] }).trim();
309
+ if (containerId) {
310
+ execSync(`docker stop ${containerId}`, { stdio: 'pipe' });
311
+ execSync(`docker rm ${containerId}`, { stdio: 'pipe' });
312
+ }
313
+ }
314
+ catch {
315
+ // Container might not exist, ignore errors
316
+ }
317
+ if (fs.existsSync(agentDir)) {
318
+ // Remove worktrees for each repository
319
+ for (const repo of workspaceInfo.repositories) {
320
+ const repoWorktreePath = path.join(agentDir, repo.name);
321
+ const sourceRepoPath = workspaceInfo.type === 'hq'
322
+ ? path.join(workspaceInfo.path, 'repos', repo.name)
323
+ : process.cwd(); // For workspace-only, source is current directory
324
+ if (fs.existsSync(repoWorktreePath)) {
325
+ try {
326
+ execSync(`git worktree remove ${path.relative(sourceRepoPath, repoWorktreePath)} --force`, {
327
+ cwd: sourceRepoPath,
328
+ stdio: 'pipe'
329
+ });
330
+ }
331
+ catch {
332
+ // If git worktree remove fails, remove directory manually
333
+ fs.rmSync(repoWorktreePath, { recursive: true, force: true });
334
+ }
335
+ }
336
+ }
337
+ // Remove agent directory
338
+ if (fs.existsSync(agentDir)) {
339
+ fs.rmSync(agentDir, { recursive: true, force: true });
340
+ }
341
+ // Clean up git worktree list
342
+ for (const repo of workspaceInfo.repositories) {
343
+ const sourceRepoPath = workspaceInfo.type === 'hq'
344
+ ? path.join(workspaceInfo.path, 'repos', repo.name)
345
+ : process.cwd();
346
+ try {
347
+ execSync('git worktree prune', {
348
+ cwd: sourceRepoPath,
349
+ stdio: 'pipe'
350
+ });
351
+ }
352
+ catch {
353
+ // Ignore prune errors
354
+ }
355
+ }
356
+ }
357
+ removed.push(agentName);
358
+ }
359
+ catch {
360
+ failed.push(agentName);
361
+ }
362
+ }
363
+ // Remove from database
364
+ if (removed.length > 0) {
365
+ removeAgentsFromDatabase(workspaceInfo.path, removed);
366
+ // Clear ticket assignees for removed agents
367
+ try {
368
+ const { storage } = await getPMOContext();
369
+ const allTickets = await storage.listTickets(undefined);
370
+ for (const ticket of allTickets) {
371
+ if (ticket.assignee && removed.includes(ticket.assignee)) {
372
+ // Pass null to clear the assignee in the database
373
+ await storage.updateTicket(ticket.id, { assignee: null });
374
+ }
375
+ }
376
+ await storage.close();
377
+ }
378
+ catch {
379
+ // PMO might not exist, ignore errors
380
+ }
381
+ }
382
+ return { removed, failed };
383
+ }
384
+ /**
385
+ * Create an ephemeral agent on-demand for a spawn operation.
386
+ * Creates worktree in agents/temp/{name}/
387
+ */
388
+ export async function createEphemeralAgent(workspaceInfo, options) {
389
+ // Get existing agent names for uniqueness check
390
+ const existingNames = new Set([
391
+ ...workspaceInfo.agents.map(a => a.name.toLowerCase()),
392
+ ...Array.from(getEphemeralAgentNames(workspaceInfo.path))
393
+ ]);
394
+ const log = options?.log;
395
+ // Get theme: use provided themeId, or fall back to workspace's active theme
396
+ let themeId = options?.themeId;
397
+ if (!themeId) {
398
+ themeId = workspaceInfo.activeThemeId ?? undefined;
399
+ }
400
+ // Use theme-specific ephemeral directory
401
+ const ephemeralDir = themeId ? getThemeEphemeralDir(themeId) : workspaceInfo.ephemeralAgentsDir;
402
+ const tempAgentsBasePath = path.join(workspaceInfo.path, 'agents', ephemeralDir);
403
+ // Create a conflict checker for external resources (tmux sessions, directories)
404
+ const checkExternalConflict = (candidateName) => {
405
+ // Check if a tmux session with this name already exists (could be from manual creation)
406
+ if (tmuxSessionExists(candidateName)) {
407
+ return { conflict: true, reason: `tmux session "${candidateName}" already exists` };
408
+ }
409
+ // Check if the directory already exists in agents/temp/
410
+ const candidateDir = path.join(tempAgentsBasePath, candidateName);
411
+ if (fs.existsSync(candidateDir)) {
412
+ return { conflict: true, reason: `directory "${candidateDir}" already exists` };
413
+ }
414
+ return { conflict: false };
415
+ };
416
+ // Log when conflicts are skipped during name generation
417
+ const onConflictSkipped = (name, reason) => {
418
+ log?.(`⚠️ Skipping name "${name}": ${reason}`);
419
+ };
420
+ // Generate unique ephemeral name using workspace theme
421
+ const nameOptions = {
422
+ themeId,
423
+ checkExternalConflict,
424
+ onConflictSkipped
425
+ };
426
+ const agentName = generateEphemeralAgentName(existingNames, nameOptions);
427
+ // Extract base name from the generated name (e.g., "bezos" from "bold-bezos-1")
428
+ const parts = agentName.split('-');
429
+ const baseName = parts.length >= 3 ? parts.slice(1, -1).join('-') : agentName;
430
+ // Create temp agents directory if it doesn't exist
431
+ if (!fs.existsSync(tempAgentsBasePath)) {
432
+ fs.mkdirSync(tempAgentsBasePath, { recursive: true });
433
+ }
434
+ const agentDir = path.join(tempAgentsBasePath, agentName);
435
+ // Create agent directory
436
+ if (!fs.existsSync(agentDir)) {
437
+ fs.mkdirSync(agentDir, { recursive: true });
438
+ }
439
+ // Create worktrees for each repository
440
+ const reposPath = path.join(workspaceInfo.path, 'repos');
441
+ if (fs.existsSync(reposPath) && workspaceInfo.repositories.length > 0) {
442
+ for (const repo of workspaceInfo.repositories) {
443
+ const sourceRepoPath = path.join(reposPath, repo.name);
444
+ const worktreePath = path.join(agentDir, repo.name);
445
+ if (fs.existsSync(sourceRepoPath) && !fs.existsSync(worktreePath)) {
446
+ try {
447
+ // Create git worktree for the repository
448
+ // Don't create a branch yet - that happens in work:start
449
+ // Use --detach to create without a branch reference
450
+ execSync(`git worktree add --detach "${worktreePath}"`, {
451
+ cwd: sourceRepoPath,
452
+ stdio: 'pipe'
453
+ });
454
+ }
455
+ catch (error) {
456
+ // If worktree creation fails, try to just create the directory
457
+ // The agent can still work without a worktree (e.g., for non-git projects)
458
+ if (!fs.existsSync(worktreePath)) {
459
+ fs.mkdirSync(worktreePath, { recursive: true });
460
+ }
461
+ }
462
+ }
463
+ }
464
+ }
465
+ // Create devcontainer config if not skipped (uses shared devcontainer generator)
466
+ if (!options?.skipDevcontainer) {
467
+ const devcontainerDir = path.join(agentDir, '.devcontainer');
468
+ if (!fs.existsSync(devcontainerDir)) {
469
+ createDevcontainerConfig({
470
+ agentName,
471
+ agentDir,
472
+ repoWorktrees: workspaceInfo.repositories.map(r => r.name)
473
+ });
474
+ }
475
+ }
476
+ // Add to database
477
+ const agent = addEphemeralAgentToDatabase(workspaceInfo.path, agentName, baseName, options?.themeId);
478
+ return {
479
+ name: agentName,
480
+ baseName,
481
+ worktreePath: agentDir,
482
+ agent
483
+ };
484
+ }
485
+ /**
486
+ * Check if a tmux session exists for a given name
487
+ */
488
+ export function tmuxSessionExists(sessionName) {
489
+ try {
490
+ execSync(`tmux has-session -t "${sessionName}" 2>/dev/null`, { stdio: 'pipe' });
491
+ return true;
492
+ }
493
+ catch {
494
+ return false;
495
+ }
496
+ }
497
+ /**
498
+ * Get list of active tmux sessions that match our pattern
499
+ * Pattern: {ticketId}-{action}-{agent}
500
+ */
501
+ export function getActiveTmuxSessions() {
502
+ try {
503
+ const output = execSync('tmux list-sessions -F "#{session_name}"', {
504
+ encoding: 'utf-8',
505
+ stdio: ['pipe', 'pipe', 'pipe']
506
+ });
507
+ return output
508
+ .trim()
509
+ .split('\n')
510
+ .filter(Boolean)
511
+ .map(name => {
512
+ // Parse session name: {ticketId}-{action}-{agent}
513
+ const parts = name.split('-');
514
+ if (parts.length >= 3) {
515
+ // TKT-123-implement-bold-bezos-1 -> ticketId: TKT-123, agent: bold-bezos-1
516
+ const ticketId = parts.slice(0, 2).join('-');
517
+ const agent = parts.slice(3).join('-');
518
+ return { name, ticketId, agent };
519
+ }
520
+ return { name, ticketId: '', agent: '' };
521
+ })
522
+ .filter(s => s.ticketId.startsWith('TKT-'));
523
+ }
524
+ catch {
525
+ return [];
526
+ }
527
+ }
528
+ /**
529
+ * Check if there's an active tmux session for a specific ticket
530
+ */
531
+ export function getTicketTmuxSession(ticketId) {
532
+ const sessions = getActiveTmuxSessions();
533
+ const session = sessions.find(s => s.ticketId === ticketId);
534
+ if (session) {
535
+ return { sessionName: session.name, agent: session.agent };
536
+ }
537
+ return null;
538
+ }
539
+ /**
540
+ * Kill a tmux session by name
541
+ */
542
+ export function killTmuxSession(sessionName) {
543
+ try {
544
+ execSync(`tmux kill-session -t "${sessionName}"`, { stdio: 'pipe' });
545
+ return true;
546
+ }
547
+ catch {
548
+ return false;
549
+ }
550
+ }
551
+ /**
552
+ * Get tmux sessions associated with an agent
553
+ */
554
+ export function getAgentTmuxSessions(agentName) {
555
+ const sessions = getActiveTmuxSessions();
556
+ return sessions
557
+ .filter(s => s.agent === agentName)
558
+ .map(s => s.name);
559
+ }
560
+ /**
561
+ * Get docker containers associated with an agent directory
562
+ */
563
+ function getAgentContainers(agentDir) {
564
+ try {
565
+ const output = execSync(`docker ps -aq --filter "label=devcontainer.local_folder=${agentDir}"`, { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] });
566
+ return output.trim().split('\n').filter(Boolean);
567
+ }
568
+ catch {
569
+ return [];
570
+ }
571
+ }
572
+ /**
573
+ * Check git status for all worktrees in an agent directory.
574
+ * Returns info about uncommitted changes and unpushed commits.
575
+ */
576
+ export function getAgentGitStatus(workspaceInfo, agentName) {
577
+ const agent = workspaceInfo.agents.find(a => a.name === agentName);
578
+ const agentDir = agent?.type === 'ephemeral'
579
+ ? path.join(workspaceInfo.path, 'agents', workspaceInfo.ephemeralAgentsDir, agentName)
580
+ : path.join(workspaceInfo.path, 'agents', workspaceInfo.persistentAgentsDir, agentName);
581
+ const result = {
582
+ agentName,
583
+ worktrees: [],
584
+ hasUnsavedWork: false
585
+ };
586
+ // Check each repository worktree
587
+ for (const repo of workspaceInfo.repositories) {
588
+ const worktreePath = path.join(agentDir, repo.name);
589
+ if (!fs.existsSync(worktreePath)) {
590
+ continue;
591
+ }
592
+ const status = {
593
+ worktreePath,
594
+ repoName: repo.name,
595
+ branch: '',
596
+ hasUncommittedChanges: false,
597
+ uncommittedFiles: [],
598
+ hasUnpushedCommits: false,
599
+ unpushedCount: 0
600
+ };
601
+ try {
602
+ // Get current branch
603
+ status.branch = execSync('git rev-parse --abbrev-ref HEAD', {
604
+ cwd: worktreePath,
605
+ encoding: 'utf-8',
606
+ stdio: ['pipe', 'pipe', 'pipe']
607
+ }).trim();
608
+ // Check for uncommitted changes (staged + unstaged + untracked)
609
+ const gitStatus = execSync('git status --porcelain', {
610
+ cwd: worktreePath,
611
+ encoding: 'utf-8',
612
+ stdio: ['pipe', 'pipe', 'pipe']
613
+ }).trim();
614
+ if (gitStatus) {
615
+ status.hasUncommittedChanges = true;
616
+ status.uncommittedFiles = gitStatus.split('\n').filter(line => line.trim());
617
+ result.hasUnsavedWork = true;
618
+ }
619
+ // Check for unpushed commits
620
+ try {
621
+ const unpushed = execSync(`git log @{u}..HEAD --oneline 2>/dev/null || echo ""`, {
622
+ cwd: worktreePath,
623
+ encoding: 'utf-8',
624
+ stdio: ['pipe', 'pipe', 'pipe']
625
+ }).trim();
626
+ if (unpushed) {
627
+ status.hasUnpushedCommits = true;
628
+ status.unpushedCount = unpushed.split('\n').filter(line => line.trim()).length;
629
+ result.hasUnsavedWork = true;
630
+ }
631
+ }
632
+ catch {
633
+ // No upstream tracking branch - check if there are any commits at all
634
+ try {
635
+ const hasCommits = execSync('git log --oneline -1', {
636
+ cwd: worktreePath,
637
+ encoding: 'utf-8',
638
+ stdio: ['pipe', 'pipe', 'pipe']
639
+ }).trim();
640
+ if (hasCommits) {
641
+ // Has commits but no upstream - consider as unpushed
642
+ status.hasUnpushedCommits = true;
643
+ status.unpushedCount = 1; // At least one
644
+ result.hasUnsavedWork = true;
645
+ }
646
+ }
647
+ catch {
648
+ // No commits at all
649
+ }
650
+ }
651
+ }
652
+ catch {
653
+ // Git commands failed - worktree might be corrupted
654
+ }
655
+ result.worktrees.push(status);
656
+ }
657
+ return result;
658
+ }
659
+ /**
660
+ * Commit and push all work in an agent's worktrees.
661
+ * - Stages all uncommitted changes (git add -A)
662
+ * - Commits with a WIP message if there are staged changes
663
+ * - Pushes all commits to remote
664
+ * Returns true if all operations succeeded.
665
+ */
666
+ export function pushAgentWork(workspaceInfo, agentName, log) {
667
+ const gitStatus = getAgentGitStatus(workspaceInfo, agentName);
668
+ let allSuccess = true;
669
+ for (const worktree of gitStatus.worktrees) {
670
+ const { worktreePath, repoName, hasUncommittedChanges, uncommittedFiles, hasUnpushedCommits, unpushedCount, branch } = worktree;
671
+ // First, commit any uncommitted changes
672
+ if (hasUncommittedChanges) {
673
+ try {
674
+ log?.(`Committing ${uncommittedFiles.length} file(s) in ${repoName}...`);
675
+ // Stage all changes
676
+ execSync('git add -A', {
677
+ cwd: worktreePath,
678
+ stdio: 'pipe'
679
+ });
680
+ // Commit with WIP message
681
+ const commitMessage = `WIP: Auto-commit before cleanup\n\nAgent: ${agentName}\nFiles: ${uncommittedFiles.length}`;
682
+ execSync(`git commit -m "${commitMessage.replace(/"/g, '\\"')}"`, {
683
+ cwd: worktreePath,
684
+ stdio: 'pipe'
685
+ });
686
+ log?.(`✓ Committed changes in ${repoName}`);
687
+ }
688
+ catch (error) {
689
+ log?.(`✗ Failed to commit ${repoName}: ${error}`);
690
+ allSuccess = false;
691
+ continue; // Skip push if commit failed
692
+ }
693
+ }
694
+ // Then push (either existing unpushed commits or the one we just made)
695
+ if (hasUnpushedCommits || hasUncommittedChanges) {
696
+ try {
697
+ const commitCount = hasUncommittedChanges ? (unpushedCount + 1) : unpushedCount;
698
+ log?.(`Pushing ${commitCount} commit(s) from ${repoName} on ${branch}...`);
699
+ // Set upstream if needed and push
700
+ execSync(`git push -u origin ${branch}`, {
701
+ cwd: worktreePath,
702
+ stdio: 'pipe'
703
+ });
704
+ log?.(`✓ Pushed ${repoName}`);
705
+ }
706
+ catch (error) {
707
+ log?.(`✗ Failed to push ${repoName}: ${error}`);
708
+ allSuccess = false;
709
+ }
710
+ }
711
+ }
712
+ return allSuccess;
713
+ }
714
+ /**
715
+ * Clean up a single agent - removes resources but keeps DB record (marked as cleaned)
716
+ */
717
+ export async function cleanupAgent(workspaceInfo, agentName, options) {
718
+ const log = options?.log ?? (() => { });
719
+ const dryRun = options?.dryRun ?? false;
720
+ const force = options?.force ?? false;
721
+ const pushFirst = options?.pushFirst ?? false;
722
+ const result = {
723
+ agent: agentName,
724
+ success: true,
725
+ tmuxSessionsKilled: [],
726
+ containersRemoved: [],
727
+ directoriesRemoved: [],
728
+ errors: []
729
+ };
730
+ // Find the agent
731
+ const agent = workspaceInfo.agents.find(a => a.name === agentName);
732
+ if (!agent) {
733
+ result.success = false;
734
+ result.errors.push(`Agent "${agentName}" not found`);
735
+ return result;
736
+ }
737
+ // Check for unsaved work (uncommitted changes or unpushed commits)
738
+ if (!force) {
739
+ const gitStatus = getAgentGitStatus(workspaceInfo, agentName);
740
+ if (gitStatus.hasUnsavedWork) {
741
+ // If pushFirst is set, try to push before cleanup
742
+ if (pushFirst) {
743
+ log('Pushing unpushed work before cleanup...');
744
+ const pushed = pushAgentWork(workspaceInfo, agentName, log);
745
+ if (!pushed) {
746
+ result.success = false;
747
+ result.blockedByGit = true;
748
+ result.gitStatus = gitStatus;
749
+ result.errors.push('Failed to push some work. Use --force to cleanup anyway.');
750
+ return result;
751
+ }
752
+ // Re-check git status after push
753
+ const newStatus = getAgentGitStatus(workspaceInfo, agentName);
754
+ if (newStatus.hasUnsavedWork) {
755
+ result.success = false;
756
+ result.blockedByGit = true;
757
+ result.gitStatus = newStatus;
758
+ result.errors.push('Agent still has uncommitted changes after push. Commit changes or use --force.');
759
+ return result;
760
+ }
761
+ }
762
+ else {
763
+ // Block cleanup - has unsaved work
764
+ result.success = false;
765
+ result.blockedByGit = true;
766
+ result.gitStatus = gitStatus;
767
+ const issues = [];
768
+ for (const wt of gitStatus.worktrees) {
769
+ if (wt.hasUncommittedChanges) {
770
+ issues.push(`${wt.repoName}: ${wt.uncommittedFiles.length} uncommitted files`);
771
+ }
772
+ if (wt.hasUnpushedCommits) {
773
+ issues.push(`${wt.repoName}: ${wt.unpushedCount} unpushed commits on ${wt.branch}`);
774
+ }
775
+ }
776
+ result.errors.push(`Agent has unsaved work: ${issues.join(', ')}. Use --push to push first or --force to cleanup anyway.`);
777
+ return result;
778
+ }
779
+ }
780
+ }
781
+ // Determine agent directory
782
+ const agentDir = agent.type === 'ephemeral'
783
+ ? path.join(workspaceInfo.path, 'agents', workspaceInfo.ephemeralAgentsDir, agentName)
784
+ : path.join(workspaceInfo.path, 'agents', workspaceInfo.persistentAgentsDir, agentName);
785
+ // 1. Kill tmux sessions for this agent
786
+ const tmuxSessions = getAgentTmuxSessions(agentName);
787
+ for (const session of tmuxSessions) {
788
+ if (dryRun) {
789
+ log(`[dry-run] Would kill tmux session: ${session}`);
790
+ }
791
+ else {
792
+ log(`Killing tmux session: ${session}`);
793
+ if (killTmuxSession(session)) {
794
+ result.tmuxSessionsKilled.push(session);
795
+ }
796
+ else {
797
+ result.errors.push(`Failed to kill tmux session: ${session}`);
798
+ }
799
+ }
800
+ }
801
+ // 2. Stop and remove docker containers
802
+ const containers = getAgentContainers(agentDir);
803
+ for (const containerId of containers) {
804
+ if (dryRun) {
805
+ log(`[dry-run] Would remove container: ${containerId}`);
806
+ }
807
+ else {
808
+ log(`Removing container: ${containerId}`);
809
+ try {
810
+ execSync(`docker rm -f ${containerId}`, { stdio: 'pipe' });
811
+ result.containersRemoved.push(containerId);
812
+ }
813
+ catch (error) {
814
+ result.errors.push(`Failed to remove container ${containerId}: ${error}`);
815
+ }
816
+ }
817
+ }
818
+ // 3. Remove git worktrees for each repository
819
+ for (const repo of workspaceInfo.repositories) {
820
+ const worktreePath = path.join(agentDir, repo.name);
821
+ const sourceRepoPath = path.join(workspaceInfo.path, 'repos', repo.name);
822
+ if (fs.existsSync(worktreePath) && fs.existsSync(sourceRepoPath)) {
823
+ if (dryRun) {
824
+ log(`[dry-run] Would remove worktree: ${worktreePath}`);
825
+ }
826
+ else {
827
+ log(`Removing worktree: ${worktreePath}`);
828
+ try {
829
+ execSync(`git worktree remove "${worktreePath}" --force`, {
830
+ cwd: sourceRepoPath,
831
+ stdio: 'pipe'
832
+ });
833
+ }
834
+ catch {
835
+ // If git worktree remove fails, we'll still try to remove the directory
836
+ }
837
+ }
838
+ }
839
+ }
840
+ // 4. Remove agent directory
841
+ if (fs.existsSync(agentDir)) {
842
+ if (dryRun) {
843
+ log(`[dry-run] Would remove directory: ${agentDir}`);
844
+ result.directoriesRemoved.push(agentDir);
845
+ }
846
+ else {
847
+ log(`Removing directory: ${agentDir}`);
848
+ try {
849
+ fs.rmSync(agentDir, { recursive: true, force: true });
850
+ result.directoriesRemoved.push(agentDir);
851
+ }
852
+ catch (error) {
853
+ result.errors.push(`Failed to remove directory ${agentDir}: ${error}`);
854
+ result.success = false;
855
+ }
856
+ }
857
+ }
858
+ // 5. Prune worktrees
859
+ if (!dryRun) {
860
+ for (const repo of workspaceInfo.repositories) {
861
+ const sourceRepoPath = path.join(workspaceInfo.path, 'repos', repo.name);
862
+ if (fs.existsSync(sourceRepoPath)) {
863
+ try {
864
+ execSync('git worktree prune', { cwd: sourceRepoPath, stdio: 'pipe' });
865
+ }
866
+ catch {
867
+ // Ignore prune errors
868
+ }
869
+ }
870
+ }
871
+ }
872
+ // 6. Mark agent as cleaned in database (not delete)
873
+ if (!dryRun && result.success) {
874
+ log(`Marking agent "${agentName}" as cleaned`);
875
+ markAgentCleaned(workspaceInfo.path, agentName);
876
+ }
877
+ return result;
878
+ }
879
+ /**
880
+ * Get agents that can be cleaned up (active ephemeral agents with no running work)
881
+ */
882
+ export function getCleanableAgents(workspaceInfo, checkRunning = true) {
883
+ // Get active ephemeral agents
884
+ const ephemeralAgents = workspaceInfo.agents.filter(a => a.type === 'ephemeral' && a.status === 'active');
885
+ if (!checkRunning) {
886
+ return ephemeralAgents;
887
+ }
888
+ // Filter out agents with active tmux sessions
889
+ return ephemeralAgents.filter(agent => {
890
+ const sessions = getAgentTmuxSessions(agent.name);
891
+ return sessions.length === 0;
892
+ });
893
+ }