crewly 1.2.1 → 1.2.4

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 (642) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +1 -1
  3. package/config/constants.ts +44 -1
  4. package/config/index.ts +4 -0
  5. package/config/roles/architect/prompt.md +7 -5
  6. package/config/roles/backend-developer/prompt.md +8 -4
  7. package/config/roles/content-strategist/prompt.md +12 -4
  8. package/config/roles/designer/prompt.md +8 -4
  9. package/config/roles/developer/prompt.md +7 -4
  10. package/config/roles/frontend-developer/prompt.md +8 -4
  11. package/config/roles/fullstack-dev/prompt.md +8 -4
  12. package/config/roles/generalist/prompt.md +7 -4
  13. package/config/roles/ops/prompt.md +7 -4
  14. package/config/roles/orchestrator/prompt.md +52 -3
  15. package/config/roles/product-manager/prompt.md +8 -4
  16. package/config/roles/qa/prompt.md +8 -4
  17. package/config/roles/qa-engineer/prompt.md +8 -4
  18. package/config/roles/sales/prompt.md +8 -4
  19. package/config/roles/support/prompt.md +8 -4
  20. package/config/roles/team-leader/prompt.md +169 -0
  21. package/config/roles/team-leader/role.json +13 -0
  22. package/config/roles/team-leader/tl-addon.md +142 -0
  23. package/config/roles/tpm/prompt.md +8 -4
  24. package/config/runtime_scripts/runtime-config.json +7 -0
  25. package/config/skills/_common/lib.sh +37 -0
  26. package/config/skills/agent/computer-use/execute.sh +228 -0
  27. package/config/skills/agent/computer-use/instructions.md +103 -0
  28. package/config/skills/agent/computer-use/lib/accessibility.sh +292 -0
  29. package/config/skills/agent/computer-use/lib/applescript.sh +117 -0
  30. package/config/skills/agent/computer-use/lib/discover.sh +122 -0
  31. package/config/skills/agent/computer-use/lib/playwright.sh +153 -0
  32. package/config/skills/agent/computer-use/lib/screenshot.sh +61 -0
  33. package/config/skills/agent/computer-use/skill.json +29 -0
  34. package/config/skills/agent/core/accept-task/execute.sh +7 -1
  35. package/config/skills/agent/core/complete-task/execute.sh +38 -1
  36. package/config/skills/agent/core/report-status/execute.sh +51 -2
  37. package/config/skills/agent/desktop-app-control/execute.sh +561 -0
  38. package/config/skills/agent/desktop-app-control/instructions.md +102 -0
  39. package/config/skills/agent/desktop-app-control/skill.json +33 -0
  40. package/config/skills/orchestrator/broadcast-to-org/execute.sh +88 -0
  41. package/config/skills/orchestrator/broadcast-to-org/instructions.md +51 -0
  42. package/config/skills/orchestrator/broadcast-to-org/skill.json +20 -0
  43. package/config/skills/orchestrator/delegate-task/execute.sh +76 -11
  44. package/config/skills/orchestrator/delegate-task/instructions.md +11 -1
  45. package/config/skills/orchestrator/handle-agent-failure/execute.sh +45 -0
  46. package/config/skills/orchestrator/handle-agent-failure/instructions.md +29 -0
  47. package/config/skills/orchestrator/handle-agent-failure/skill.json +20 -0
  48. package/config/skills/orchestrator/restart-crewly/instructions.md +9 -2
  49. package/config/skills/team-leader/_common/lib.sh +4 -0
  50. package/config/skills/team-leader/aggregate-results/execute.sh +168 -0
  51. package/config/skills/team-leader/aggregate-results/instructions.md +89 -0
  52. package/config/skills/team-leader/aggregate-results/skill.json +20 -0
  53. package/config/skills/team-leader/decompose-goal/execute.sh +86 -0
  54. package/config/skills/team-leader/decompose-goal/instructions.md +84 -0
  55. package/config/skills/team-leader/decompose-goal/skill.json +20 -0
  56. package/config/skills/team-leader/delegate-task/execute.sh +142 -0
  57. package/config/skills/team-leader/delegate-task/instructions.md +55 -0
  58. package/config/skills/team-leader/delegate-task/skill.json +20 -0
  59. package/config/skills/team-leader/handle-failure/execute.sh +119 -0
  60. package/config/skills/team-leader/handle-failure/instructions.md +93 -0
  61. package/config/skills/team-leader/handle-failure/skill.json +20 -0
  62. package/config/skills/team-leader/schedule-check/execute.sh +65 -0
  63. package/config/skills/team-leader/schedule-check/execute.test.sh +247 -0
  64. package/config/skills/team-leader/schedule-check/instructions.md +49 -0
  65. package/config/skills/team-leader/schedule-check/skill.json +20 -0
  66. package/config/skills/team-leader/start-agent/execute.sh +39 -0
  67. package/config/skills/team-leader/start-agent/instructions.md +48 -0
  68. package/config/skills/team-leader/start-agent/skill.json +20 -0
  69. package/config/skills/team-leader/stop-agent/execute.sh +39 -0
  70. package/config/skills/team-leader/stop-agent/instructions.md +49 -0
  71. package/config/skills/team-leader/stop-agent/skill.json +20 -0
  72. package/config/skills/team-leader/verify-output/execute.sh +296 -0
  73. package/config/skills/team-leader/verify-output/instructions.md +122 -0
  74. package/config/skills/team-leader/verify-output/skill.json +20 -0
  75. package/config/templates/agent-claude-md.md +10 -5
  76. package/config/templates/core-team/demo-script.md +41 -0
  77. package/config/templates/core-team/goals.md +20 -0
  78. package/config/templates/core-team/team.json +22 -0
  79. package/config/templates/dev-fullstack/template.json +115 -0
  80. package/config/templates/education-smb/README.md +27 -0
  81. package/config/templates/education-smb/goals.md +16 -0
  82. package/config/templates/education-smb/knowledge/docs/content-standards.md +24 -0
  83. package/config/templates/education-smb/knowledge/docs/education-industry-context.md +13 -0
  84. package/config/templates/education-smb/knowledge/index.json +24 -0
  85. package/config/templates/education-smb/learned-patterns.json +16 -0
  86. package/config/templates/education-smb/quality-gates.yaml +66 -0
  87. package/config/templates/education-smb/roles/analytics-specialist.md +6 -0
  88. package/config/templates/education-smb/roles/content-creator.md +6 -0
  89. package/config/templates/education-smb/roles/curriculum-designer.md +6 -0
  90. package/config/templates/education-smb/roles/engagement-manager.md +6 -0
  91. package/config/templates/education-smb/team.json +40 -0
  92. package/config/templates/education-smb/template.json +26 -0
  93. package/config/templates/education-smb/workflows/course-content-generation.yaml +44 -0
  94. package/config/templates/education-smb/workflows/reporting.yaml +31 -0
  95. package/config/templates/education-smb/workflows/student-communication.yaml +44 -0
  96. package/config/templates/education-smb/workflows.yaml +40 -0
  97. package/config/templates/insurance-smb/README.md +28 -0
  98. package/config/templates/insurance-smb/goals.md +21 -0
  99. package/config/templates/insurance-smb/knowledge/docs/compliance-checklist.md +28 -0
  100. package/config/templates/insurance-smb/knowledge/docs/insurance-industry-context.md +23 -0
  101. package/config/templates/insurance-smb/knowledge/index.json +24 -0
  102. package/config/templates/insurance-smb/learned-patterns.json +16 -0
  103. package/config/templates/insurance-smb/quality-gates.yaml +54 -0
  104. package/config/templates/insurance-smb/roles/claims-processor.md +6 -0
  105. package/config/templates/insurance-smb/roles/client-manager.md +6 -0
  106. package/config/templates/insurance-smb/roles/compliance-officer.md +6 -0
  107. package/config/templates/insurance-smb/roles/marketing-specialist.md +6 -0
  108. package/config/templates/insurance-smb/roles/policy-analyst.md +6 -0
  109. package/config/templates/insurance-smb/team.json +48 -0
  110. package/config/templates/insurance-smb/template.json +26 -0
  111. package/config/templates/insurance-smb/workflows/claims-processing.yaml +48 -0
  112. package/config/templates/insurance-smb/workflows.yaml +43 -0
  113. package/config/templates/research-analysis/template.json +88 -0
  114. package/config/templates/social-media-ops/template.json +85 -0
  115. package/config/templates/video-production/template.json +123 -0
  116. package/dist/backend/backend/src/constants.d.ts +310 -84
  117. package/dist/backend/backend/src/constants.d.ts.map +1 -1
  118. package/dist/backend/backend/src/constants.js +303 -89
  119. package/dist/backend/backend/src/constants.js.map +1 -1
  120. package/dist/backend/backend/src/controllers/chat/chat.controller.d.ts.map +1 -1
  121. package/dist/backend/backend/src/controllers/chat/chat.controller.js +86 -26
  122. package/dist/backend/backend/src/controllers/chat/chat.controller.js.map +1 -1
  123. package/dist/backend/backend/src/controllers/cloud/auth/auth.controller.d.ts +81 -0
  124. package/dist/backend/backend/src/controllers/cloud/auth/auth.controller.d.ts.map +1 -0
  125. package/dist/backend/backend/src/controllers/cloud/auth/auth.controller.js +234 -0
  126. package/dist/backend/backend/src/controllers/cloud/auth/auth.controller.js.map +1 -0
  127. package/dist/backend/backend/src/controllers/cloud/auth/auth.routes.d.ts +25 -0
  128. package/dist/backend/backend/src/controllers/cloud/auth/auth.routes.d.ts.map +1 -0
  129. package/dist/backend/backend/src/controllers/cloud/auth/auth.routes.js +38 -0
  130. package/dist/backend/backend/src/controllers/cloud/auth/auth.routes.js.map +1 -0
  131. package/dist/backend/backend/src/controllers/cloud/cloud-auth.controller.d.ts +69 -0
  132. package/dist/backend/backend/src/controllers/cloud/cloud-auth.controller.d.ts.map +1 -0
  133. package/dist/backend/backend/src/controllers/cloud/cloud-auth.controller.js +165 -0
  134. package/dist/backend/backend/src/controllers/cloud/cloud-auth.controller.js.map +1 -0
  135. package/dist/backend/backend/src/controllers/cloud/cloud-auth.routes.d.ts +23 -0
  136. package/dist/backend/backend/src/controllers/cloud/cloud-auth.routes.d.ts.map +1 -0
  137. package/dist/backend/backend/src/controllers/cloud/cloud-auth.routes.js +32 -0
  138. package/dist/backend/backend/src/controllers/cloud/cloud-auth.routes.js.map +1 -0
  139. package/dist/backend/backend/src/controllers/cloud/cloud.controller.d.ts +52 -0
  140. package/dist/backend/backend/src/controllers/cloud/cloud.controller.d.ts.map +1 -0
  141. package/dist/backend/backend/src/controllers/cloud/cloud.controller.js +122 -0
  142. package/dist/backend/backend/src/controllers/cloud/cloud.controller.js.map +1 -0
  143. package/dist/backend/backend/src/controllers/cloud/cloud.routes.d.ts +21 -0
  144. package/dist/backend/backend/src/controllers/cloud/cloud.routes.d.ts.map +1 -0
  145. package/dist/backend/backend/src/controllers/cloud/cloud.routes.js +32 -0
  146. package/dist/backend/backend/src/controllers/cloud/cloud.routes.js.map +1 -0
  147. package/dist/backend/backend/src/controllers/cloud/files/cloud-file.controller.d.ts +42 -0
  148. package/dist/backend/backend/src/controllers/cloud/files/cloud-file.controller.d.ts.map +1 -0
  149. package/dist/backend/backend/src/controllers/cloud/files/cloud-file.controller.js +138 -0
  150. package/dist/backend/backend/src/controllers/cloud/files/cloud-file.controller.js.map +1 -0
  151. package/dist/backend/backend/src/controllers/cloud/files/cloud-file.routes.d.ts +23 -0
  152. package/dist/backend/backend/src/controllers/cloud/files/cloud-file.routes.d.ts.map +1 -0
  153. package/dist/backend/backend/src/controllers/cloud/files/cloud-file.routes.js +34 -0
  154. package/dist/backend/backend/src/controllers/cloud/files/cloud-file.routes.js.map +1 -0
  155. package/dist/backend/backend/src/controllers/cloud/files/cloud-file.types.d.ts +43 -0
  156. package/dist/backend/backend/src/controllers/cloud/files/cloud-file.types.d.ts.map +1 -0
  157. package/dist/backend/backend/src/controllers/cloud/files/cloud-file.types.js +9 -0
  158. package/dist/backend/backend/src/controllers/cloud/files/cloud-file.types.js.map +1 -0
  159. package/dist/backend/backend/src/controllers/cloud/files/index.d.ts +7 -0
  160. package/dist/backend/backend/src/controllers/cloud/files/index.d.ts.map +1 -0
  161. package/dist/backend/backend/src/controllers/cloud/files/index.js +7 -0
  162. package/dist/backend/backend/src/controllers/cloud/files/index.js.map +1 -0
  163. package/dist/backend/backend/src/controllers/cloud/h5/h5-entry.controller.d.ts +47 -0
  164. package/dist/backend/backend/src/controllers/cloud/h5/h5-entry.controller.d.ts.map +1 -0
  165. package/dist/backend/backend/src/controllers/cloud/h5/h5-entry.controller.js +131 -0
  166. package/dist/backend/backend/src/controllers/cloud/h5/h5-entry.controller.js.map +1 -0
  167. package/dist/backend/backend/src/controllers/cloud/h5/h5-entry.routes.d.ts +23 -0
  168. package/dist/backend/backend/src/controllers/cloud/h5/h5-entry.routes.d.ts.map +1 -0
  169. package/dist/backend/backend/src/controllers/cloud/h5/h5-entry.routes.js +30 -0
  170. package/dist/backend/backend/src/controllers/cloud/h5/h5-entry.routes.js.map +1 -0
  171. package/dist/backend/backend/src/controllers/cloud/h5/h5-entry.types.d.ts +81 -0
  172. package/dist/backend/backend/src/controllers/cloud/h5/h5-entry.types.d.ts.map +1 -0
  173. package/dist/backend/backend/src/controllers/cloud/h5/h5-entry.types.js +85 -0
  174. package/dist/backend/backend/src/controllers/cloud/h5/h5-entry.types.js.map +1 -0
  175. package/dist/backend/backend/src/controllers/cloud/h5/index.d.ts +7 -0
  176. package/dist/backend/backend/src/controllers/cloud/h5/index.d.ts.map +1 -0
  177. package/dist/backend/backend/src/controllers/cloud/h5/index.js +7 -0
  178. package/dist/backend/backend/src/controllers/cloud/h5/index.js.map +1 -0
  179. package/dist/backend/backend/src/controllers/cloud/index.d.ts +14 -0
  180. package/dist/backend/backend/src/controllers/cloud/index.d.ts.map +1 -0
  181. package/dist/backend/backend/src/controllers/cloud/index.js +14 -0
  182. package/dist/backend/backend/src/controllers/cloud/index.js.map +1 -0
  183. package/dist/backend/backend/src/controllers/cloud/magic-moment/index.d.ts +7 -0
  184. package/dist/backend/backend/src/controllers/cloud/magic-moment/index.d.ts.map +1 -0
  185. package/dist/backend/backend/src/controllers/cloud/magic-moment/index.js +7 -0
  186. package/dist/backend/backend/src/controllers/cloud/magic-moment/index.js.map +1 -0
  187. package/dist/backend/backend/src/controllers/cloud/magic-moment/magic-moment.controller.d.ts +45 -0
  188. package/dist/backend/backend/src/controllers/cloud/magic-moment/magic-moment.controller.d.ts.map +1 -0
  189. package/dist/backend/backend/src/controllers/cloud/magic-moment/magic-moment.controller.js +155 -0
  190. package/dist/backend/backend/src/controllers/cloud/magic-moment/magic-moment.controller.js.map +1 -0
  191. package/dist/backend/backend/src/controllers/cloud/magic-moment/magic-moment.routes.d.ts +25 -0
  192. package/dist/backend/backend/src/controllers/cloud/magic-moment/magic-moment.routes.d.ts.map +1 -0
  193. package/dist/backend/backend/src/controllers/cloud/magic-moment/magic-moment.routes.js +32 -0
  194. package/dist/backend/backend/src/controllers/cloud/magic-moment/magic-moment.routes.js.map +1 -0
  195. package/dist/backend/backend/src/controllers/cloud/relay.controller.d.ts +101 -0
  196. package/dist/backend/backend/src/controllers/cloud/relay.controller.d.ts.map +1 -0
  197. package/dist/backend/backend/src/controllers/cloud/relay.controller.js +343 -0
  198. package/dist/backend/backend/src/controllers/cloud/relay.controller.js.map +1 -0
  199. package/dist/backend/backend/src/controllers/cloud/relay.routes.d.ts +29 -0
  200. package/dist/backend/backend/src/controllers/cloud/relay.routes.d.ts.map +1 -0
  201. package/dist/backend/backend/src/controllers/cloud/relay.routes.js +44 -0
  202. package/dist/backend/backend/src/controllers/cloud/relay.routes.js.map +1 -0
  203. package/dist/backend/backend/src/controllers/cloud/tasks/cloud-task.controller.d.ts +49 -0
  204. package/dist/backend/backend/src/controllers/cloud/tasks/cloud-task.controller.d.ts.map +1 -0
  205. package/dist/backend/backend/src/controllers/cloud/tasks/cloud-task.controller.js +152 -0
  206. package/dist/backend/backend/src/controllers/cloud/tasks/cloud-task.controller.js.map +1 -0
  207. package/dist/backend/backend/src/controllers/cloud/tasks/cloud-task.routes.d.ts +24 -0
  208. package/dist/backend/backend/src/controllers/cloud/tasks/cloud-task.routes.d.ts.map +1 -0
  209. package/dist/backend/backend/src/controllers/cloud/tasks/cloud-task.routes.js +34 -0
  210. package/dist/backend/backend/src/controllers/cloud/tasks/cloud-task.routes.js.map +1 -0
  211. package/dist/backend/backend/src/controllers/cloud/tasks/cloud-task.types.d.ts +90 -0
  212. package/dist/backend/backend/src/controllers/cloud/tasks/cloud-task.types.d.ts.map +1 -0
  213. package/dist/backend/backend/src/controllers/cloud/tasks/cloud-task.types.js +48 -0
  214. package/dist/backend/backend/src/controllers/cloud/tasks/cloud-task.types.js.map +1 -0
  215. package/dist/backend/backend/src/controllers/cloud/tasks/index.d.ts +7 -0
  216. package/dist/backend/backend/src/controllers/cloud/tasks/index.d.ts.map +1 -0
  217. package/dist/backend/backend/src/controllers/cloud/tasks/index.js +7 -0
  218. package/dist/backend/backend/src/controllers/cloud/tasks/index.js.map +1 -0
  219. package/dist/backend/backend/src/controllers/marketplace/index.d.ts +2 -0
  220. package/dist/backend/backend/src/controllers/marketplace/index.d.ts.map +1 -1
  221. package/dist/backend/backend/src/controllers/marketplace/index.js +3 -0
  222. package/dist/backend/backend/src/controllers/marketplace/index.js.map +1 -1
  223. package/dist/backend/backend/src/controllers/marketplace/marketplace.controller.d.ts +12 -12
  224. package/dist/backend/backend/src/controllers/marketplace/marketplace.controller.d.ts.map +1 -1
  225. package/dist/backend/backend/src/controllers/marketplace/marketplace.controller.js +1 -18
  226. package/dist/backend/backend/src/controllers/marketplace/marketplace.controller.js.map +1 -1
  227. package/dist/backend/backend/src/controllers/marketplace/marketplace.routes.d.ts.map +1 -1
  228. package/dist/backend/backend/src/controllers/marketplace/marketplace.routes.js +3 -0
  229. package/dist/backend/backend/src/controllers/marketplace/marketplace.routes.js.map +1 -1
  230. package/dist/backend/backend/src/controllers/marketplace/template-marketplace.controller.d.ts +111 -0
  231. package/dist/backend/backend/src/controllers/marketplace/template-marketplace.controller.d.ts.map +1 -0
  232. package/dist/backend/backend/src/controllers/marketplace/template-marketplace.controller.js +220 -0
  233. package/dist/backend/backend/src/controllers/marketplace/template-marketplace.controller.js.map +1 -0
  234. package/dist/backend/backend/src/controllers/marketplace/template-marketplace.routes.d.ts +33 -0
  235. package/dist/backend/backend/src/controllers/marketplace/template-marketplace.routes.d.ts.map +1 -0
  236. package/dist/backend/backend/src/controllers/marketplace/template-marketplace.routes.js +50 -0
  237. package/dist/backend/backend/src/controllers/marketplace/template-marketplace.routes.js.map +1 -0
  238. package/dist/backend/backend/src/controllers/messaging/messenger.routes.d.ts.map +1 -1
  239. package/dist/backend/backend/src/controllers/messaging/messenger.routes.js +4 -1
  240. package/dist/backend/backend/src/controllers/messaging/messenger.routes.js.map +1 -1
  241. package/dist/backend/backend/src/controllers/monitoring/terminal.controller.d.ts.map +1 -1
  242. package/dist/backend/backend/src/controllers/monitoring/terminal.controller.js +18 -2
  243. package/dist/backend/backend/src/controllers/monitoring/terminal.controller.js.map +1 -1
  244. package/dist/backend/backend/src/controllers/payment/index.d.ts +7 -0
  245. package/dist/backend/backend/src/controllers/payment/index.d.ts.map +1 -0
  246. package/dist/backend/backend/src/controllers/payment/index.js +7 -0
  247. package/dist/backend/backend/src/controllers/payment/index.js.map +1 -0
  248. package/dist/backend/backend/src/controllers/payment/payment.controller.d.ts +57 -0
  249. package/dist/backend/backend/src/controllers/payment/payment.controller.d.ts.map +1 -0
  250. package/dist/backend/backend/src/controllers/payment/payment.controller.js +136 -0
  251. package/dist/backend/backend/src/controllers/payment/payment.controller.js.map +1 -0
  252. package/dist/backend/backend/src/controllers/payment/payment.routes.d.ts +27 -0
  253. package/dist/backend/backend/src/controllers/payment/payment.routes.d.ts.map +1 -0
  254. package/dist/backend/backend/src/controllers/payment/payment.routes.js +38 -0
  255. package/dist/backend/backend/src/controllers/payment/payment.routes.js.map +1 -0
  256. package/dist/backend/backend/src/controllers/payment/payment.types.d.ts +109 -0
  257. package/dist/backend/backend/src/controllers/payment/payment.types.d.ts.map +1 -0
  258. package/dist/backend/backend/src/controllers/payment/payment.types.js +54 -0
  259. package/dist/backend/backend/src/controllers/payment/payment.types.js.map +1 -0
  260. package/dist/backend/backend/src/controllers/request-types.d.ts +34 -5
  261. package/dist/backend/backend/src/controllers/request-types.d.ts.map +1 -1
  262. package/dist/backend/backend/src/controllers/session/session.controller.d.ts +14 -0
  263. package/dist/backend/backend/src/controllers/session/session.controller.d.ts.map +1 -1
  264. package/dist/backend/backend/src/controllers/session/session.controller.js +48 -0
  265. package/dist/backend/backend/src/controllers/session/session.controller.js.map +1 -1
  266. package/dist/backend/backend/src/controllers/session/session.routes.d.ts.map +1 -1
  267. package/dist/backend/backend/src/controllers/session/session.routes.js +3 -1
  268. package/dist/backend/backend/src/controllers/session/session.routes.js.map +1 -1
  269. package/dist/backend/backend/src/controllers/system/scheduler.controller.d.ts.map +1 -1
  270. package/dist/backend/backend/src/controllers/system/scheduler.controller.js +4 -3
  271. package/dist/backend/backend/src/controllers/system/scheduler.controller.js.map +1 -1
  272. package/dist/backend/backend/src/controllers/system/system.controller.d.ts.map +1 -1
  273. package/dist/backend/backend/src/controllers/system/system.controller.js +13 -15
  274. package/dist/backend/backend/src/controllers/system/system.controller.js.map +1 -1
  275. package/dist/backend/backend/src/controllers/task-management/assignments.controller.d.ts.map +1 -1
  276. package/dist/backend/backend/src/controllers/task-management/assignments.controller.js.map +1 -1
  277. package/dist/backend/backend/src/controllers/task-management/task-management.controller.d.ts.map +1 -1
  278. package/dist/backend/backend/src/controllers/task-management/task-management.controller.js +40 -4
  279. package/dist/backend/backend/src/controllers/task-management/task-management.controller.js.map +1 -1
  280. package/dist/backend/backend/src/controllers/task-management/tasks.controller.js.map +1 -1
  281. package/dist/backend/backend/src/controllers/team/team.controller.d.ts.map +1 -1
  282. package/dist/backend/backend/src/controllers/team/team.controller.js +259 -13
  283. package/dist/backend/backend/src/controllers/team/team.controller.js.map +1 -1
  284. package/dist/backend/backend/src/controllers/template/index.d.ts +8 -0
  285. package/dist/backend/backend/src/controllers/template/index.d.ts.map +1 -0
  286. package/dist/backend/backend/src/controllers/template/index.js +8 -0
  287. package/dist/backend/backend/src/controllers/template/index.js.map +1 -0
  288. package/dist/backend/backend/src/controllers/template/template.controller.d.ts +63 -0
  289. package/dist/backend/backend/src/controllers/template/template.controller.d.ts.map +1 -0
  290. package/dist/backend/backend/src/controllers/template/template.controller.js +112 -0
  291. package/dist/backend/backend/src/controllers/template/template.controller.js.map +1 -0
  292. package/dist/backend/backend/src/controllers/template/template.routes.d.ts +24 -0
  293. package/dist/backend/backend/src/controllers/template/template.routes.d.ts.map +1 -0
  294. package/dist/backend/backend/src/controllers/template/template.routes.js +33 -0
  295. package/dist/backend/backend/src/controllers/template/template.routes.js.map +1 -0
  296. package/dist/backend/backend/src/index.d.ts.map +1 -1
  297. package/dist/backend/backend/src/index.js +105 -13
  298. package/dist/backend/backend/src/index.js.map +1 -1
  299. package/dist/backend/backend/src/middleware/agent-heartbeat.middleware.js +3 -3
  300. package/dist/backend/backend/src/middleware/agent-heartbeat.middleware.js.map +1 -1
  301. package/dist/backend/backend/src/models/Team.d.ts +5 -0
  302. package/dist/backend/backend/src/models/Team.d.ts.map +1 -1
  303. package/dist/backend/backend/src/models/Team.js +24 -0
  304. package/dist/backend/backend/src/models/Team.js.map +1 -1
  305. package/dist/backend/backend/src/routes/api.routes.d.ts.map +1 -1
  306. package/dist/backend/backend/src/routes/api.routes.js +21 -0
  307. package/dist/backend/backend/src/routes/api.routes.js.map +1 -1
  308. package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts +3 -19
  309. package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
  310. package/dist/backend/backend/src/services/agent/agent-registration.service.js +274 -398
  311. package/dist/backend/backend/src/services/agent/agent-registration.service.js.map +1 -1
  312. package/dist/backend/backend/src/services/agent/claude-runtime.service.d.ts +7 -1
  313. package/dist/backend/backend/src/services/agent/claude-runtime.service.d.ts.map +1 -1
  314. package/dist/backend/backend/src/services/agent/claude-runtime.service.js +11 -2
  315. package/dist/backend/backend/src/services/agent/claude-runtime.service.js.map +1 -1
  316. package/dist/backend/backend/src/services/agent/gemini-runtime.service.d.ts +2 -1
  317. package/dist/backend/backend/src/services/agent/gemini-runtime.service.d.ts.map +1 -1
  318. package/dist/backend/backend/src/services/agent/gemini-runtime.service.js +38 -51
  319. package/dist/backend/backend/src/services/agent/gemini-runtime.service.js.map +1 -1
  320. package/dist/backend/backend/src/services/agent/oauth-relogin-monitor.service.d.ts +216 -0
  321. package/dist/backend/backend/src/services/agent/oauth-relogin-monitor.service.d.ts.map +1 -0
  322. package/dist/backend/backend/src/services/agent/oauth-relogin-monitor.service.js +496 -0
  323. package/dist/backend/backend/src/services/agent/oauth-relogin-monitor.service.js.map +1 -0
  324. package/dist/backend/backend/src/services/agent/openhands-runtime.service.d.ts +70 -0
  325. package/dist/backend/backend/src/services/agent/openhands-runtime.service.d.ts.map +1 -0
  326. package/dist/backend/backend/src/services/agent/openhands-runtime.service.js +131 -0
  327. package/dist/backend/backend/src/services/agent/openhands-runtime.service.js.map +1 -0
  328. package/dist/backend/backend/src/services/agent/pty-activity-tracker.service.d.ts +21 -1
  329. package/dist/backend/backend/src/services/agent/pty-activity-tracker.service.d.ts.map +1 -1
  330. package/dist/backend/backend/src/services/agent/pty-activity-tracker.service.js +32 -1
  331. package/dist/backend/backend/src/services/agent/pty-activity-tracker.service.js.map +1 -1
  332. package/dist/backend/backend/src/services/agent/runtime-exit-monitor.service.d.ts +77 -3
  333. package/dist/backend/backend/src/services/agent/runtime-exit-monitor.service.d.ts.map +1 -1
  334. package/dist/backend/backend/src/services/agent/runtime-exit-monitor.service.js +281 -30
  335. package/dist/backend/backend/src/services/agent/runtime-exit-monitor.service.js.map +1 -1
  336. package/dist/backend/backend/src/services/agent/runtime-service.factory.d.ts.map +1 -1
  337. package/dist/backend/backend/src/services/agent/runtime-service.factory.js +9 -0
  338. package/dist/backend/backend/src/services/agent/runtime-service.factory.js.map +1 -1
  339. package/dist/backend/backend/src/services/ai/prompt-builder.service.d.ts +49 -2
  340. package/dist/backend/backend/src/services/ai/prompt-builder.service.d.ts.map +1 -1
  341. package/dist/backend/backend/src/services/ai/prompt-builder.service.js +124 -2
  342. package/dist/backend/backend/src/services/ai/prompt-builder.service.js.map +1 -1
  343. package/dist/backend/backend/src/services/chat/chat.service.d.ts +10 -2
  344. package/dist/backend/backend/src/services/chat/chat.service.d.ts.map +1 -1
  345. package/dist/backend/backend/src/services/chat/chat.service.js +49 -8
  346. package/dist/backend/backend/src/services/chat/chat.service.js.map +1 -1
  347. package/dist/backend/backend/src/services/cloud/auth/auth.service.d.ts +174 -0
  348. package/dist/backend/backend/src/services/cloud/auth/auth.service.d.ts.map +1 -0
  349. package/dist/backend/backend/src/services/cloud/auth/auth.service.js +402 -0
  350. package/dist/backend/backend/src/services/cloud/auth/auth.service.js.map +1 -0
  351. package/dist/backend/backend/src/services/cloud/auth/auth.types.d.ts +110 -0
  352. package/dist/backend/backend/src/services/cloud/auth/auth.types.d.ts.map +1 -0
  353. package/dist/backend/backend/src/services/cloud/auth/auth.types.js +54 -0
  354. package/dist/backend/backend/src/services/cloud/auth/auth.types.js.map +1 -0
  355. package/dist/backend/backend/src/services/cloud/auth/auth.utils.d.ts +36 -0
  356. package/dist/backend/backend/src/services/cloud/auth/auth.utils.d.ts.map +1 -0
  357. package/dist/backend/backend/src/services/cloud/auth/auth.utils.js +31 -0
  358. package/dist/backend/backend/src/services/cloud/auth/auth.utils.js.map +1 -0
  359. package/dist/backend/backend/src/services/cloud/auth/jwt-auth.middleware.d.ts +47 -0
  360. package/dist/backend/backend/src/services/cloud/auth/jwt-auth.middleware.d.ts.map +1 -0
  361. package/dist/backend/backend/src/services/cloud/auth/jwt-auth.middleware.js +116 -0
  362. package/dist/backend/backend/src/services/cloud/auth/jwt-auth.middleware.js.map +1 -0
  363. package/dist/backend/backend/src/services/cloud/auth/supabase-auth.middleware.d.ts +61 -0
  364. package/dist/backend/backend/src/services/cloud/auth/supabase-auth.middleware.d.ts.map +1 -0
  365. package/dist/backend/backend/src/services/cloud/auth/supabase-auth.middleware.js +203 -0
  366. package/dist/backend/backend/src/services/cloud/auth/supabase-auth.middleware.js.map +1 -0
  367. package/dist/backend/backend/src/services/cloud/cloud-auth.middleware.d.ts +46 -0
  368. package/dist/backend/backend/src/services/cloud/cloud-auth.middleware.d.ts.map +1 -0
  369. package/dist/backend/backend/src/services/cloud/cloud-auth.middleware.js +95 -0
  370. package/dist/backend/backend/src/services/cloud/cloud-auth.middleware.js.map +1 -0
  371. package/dist/backend/backend/src/services/cloud/cloud-auth.service.d.ts +136 -0
  372. package/dist/backend/backend/src/services/cloud/cloud-auth.service.d.ts.map +1 -0
  373. package/dist/backend/backend/src/services/cloud/cloud-auth.service.js +204 -0
  374. package/dist/backend/backend/src/services/cloud/cloud-auth.service.js.map +1 -0
  375. package/dist/backend/backend/src/services/cloud/cloud-client.service.d.ts +179 -0
  376. package/dist/backend/backend/src/services/cloud/cloud-client.service.d.ts.map +1 -0
  377. package/dist/backend/backend/src/services/cloud/cloud-client.service.js +237 -0
  378. package/dist/backend/backend/src/services/cloud/cloud-client.service.js.map +1 -0
  379. package/dist/backend/backend/src/services/cloud/cloud-file.service.d.ts +97 -0
  380. package/dist/backend/backend/src/services/cloud/cloud-file.service.d.ts.map +1 -0
  381. package/dist/backend/backend/src/services/cloud/cloud-file.service.js +184 -0
  382. package/dist/backend/backend/src/services/cloud/cloud-file.service.js.map +1 -0
  383. package/dist/backend/backend/src/services/cloud/cloud-image-analysis.service.d.ts +114 -0
  384. package/dist/backend/backend/src/services/cloud/cloud-image-analysis.service.d.ts.map +1 -0
  385. package/dist/backend/backend/src/services/cloud/cloud-image-analysis.service.js +196 -0
  386. package/dist/backend/backend/src/services/cloud/cloud-image-analysis.service.js.map +1 -0
  387. package/dist/backend/backend/src/services/cloud/cloud-task-processor.service.d.ts +118 -0
  388. package/dist/backend/backend/src/services/cloud/cloud-task-processor.service.d.ts.map +1 -0
  389. package/dist/backend/backend/src/services/cloud/cloud-task-processor.service.js +322 -0
  390. package/dist/backend/backend/src/services/cloud/cloud-task-processor.service.js.map +1 -0
  391. package/dist/backend/backend/src/services/cloud/cloud-task.service.d.ts +115 -0
  392. package/dist/backend/backend/src/services/cloud/cloud-task.service.d.ts.map +1 -0
  393. package/dist/backend/backend/src/services/cloud/cloud-task.service.js +265 -0
  394. package/dist/backend/backend/src/services/cloud/cloud-task.service.js.map +1 -0
  395. package/dist/backend/backend/src/services/cloud/relay-client.service.d.ts +175 -0
  396. package/dist/backend/backend/src/services/cloud/relay-client.service.d.ts.map +1 -0
  397. package/dist/backend/backend/src/services/cloud/relay-client.service.js +392 -0
  398. package/dist/backend/backend/src/services/cloud/relay-client.service.js.map +1 -0
  399. package/dist/backend/backend/src/services/cloud/relay-crypto.service.d.ts +87 -0
  400. package/dist/backend/backend/src/services/cloud/relay-crypto.service.d.ts.map +1 -0
  401. package/dist/backend/backend/src/services/cloud/relay-crypto.service.js +140 -0
  402. package/dist/backend/backend/src/services/cloud/relay-crypto.service.js.map +1 -0
  403. package/dist/backend/backend/src/services/cloud/relay-server.service.d.ts +183 -0
  404. package/dist/backend/backend/src/services/cloud/relay-server.service.d.ts.map +1 -0
  405. package/dist/backend/backend/src/services/cloud/relay-server.service.js +523 -0
  406. package/dist/backend/backend/src/services/cloud/relay-server.service.js.map +1 -0
  407. package/dist/backend/backend/src/services/cloud/relay.types.d.ts +170 -0
  408. package/dist/backend/backend/src/services/cloud/relay.types.d.ts.map +1 -0
  409. package/dist/backend/backend/src/services/cloud/relay.types.js +69 -0
  410. package/dist/backend/backend/src/services/cloud/relay.types.js.map +1 -0
  411. package/dist/backend/backend/src/services/continuation/patterns/idle-patterns.d.ts +9 -1
  412. package/dist/backend/backend/src/services/continuation/patterns/idle-patterns.d.ts.map +1 -1
  413. package/dist/backend/backend/src/services/continuation/patterns/idle-patterns.js +18 -4
  414. package/dist/backend/backend/src/services/continuation/patterns/idle-patterns.js.map +1 -1
  415. package/dist/backend/backend/src/services/core/env.config.d.ts +147 -0
  416. package/dist/backend/backend/src/services/core/env.config.d.ts.map +1 -0
  417. package/dist/backend/backend/src/services/core/env.config.js +226 -0
  418. package/dist/backend/backend/src/services/core/env.config.js.map +1 -0
  419. package/dist/backend/backend/src/services/core/storage.service.d.ts.map +1 -1
  420. package/dist/backend/backend/src/services/core/storage.service.js +5 -0
  421. package/dist/backend/backend/src/services/core/storage.service.js.map +1 -1
  422. package/dist/backend/backend/src/services/event-bus/event-bus.service.d.ts +20 -7
  423. package/dist/backend/backend/src/services/event-bus/event-bus.service.d.ts.map +1 -1
  424. package/dist/backend/backend/src/services/event-bus/event-bus.service.js +35 -31
  425. package/dist/backend/backend/src/services/event-bus/event-bus.service.js.map +1 -1
  426. package/dist/backend/backend/src/services/hierarchy/hierarchy-escalation.service.d.ts +160 -0
  427. package/dist/backend/backend/src/services/hierarchy/hierarchy-escalation.service.d.ts.map +1 -0
  428. package/dist/backend/backend/src/services/hierarchy/hierarchy-escalation.service.js +261 -0
  429. package/dist/backend/backend/src/services/hierarchy/hierarchy-escalation.service.js.map +1 -0
  430. package/dist/backend/backend/src/services/hierarchy/hierarchy-reporting.service.d.ts +161 -0
  431. package/dist/backend/backend/src/services/hierarchy/hierarchy-reporting.service.d.ts.map +1 -0
  432. package/dist/backend/backend/src/services/hierarchy/hierarchy-reporting.service.js +276 -0
  433. package/dist/backend/backend/src/services/hierarchy/hierarchy-reporting.service.js.map +1 -0
  434. package/dist/backend/backend/src/services/marketplace/index.d.ts +1 -0
  435. package/dist/backend/backend/src/services/marketplace/index.d.ts.map +1 -1
  436. package/dist/backend/backend/src/services/marketplace/index.js +2 -0
  437. package/dist/backend/backend/src/services/marketplace/index.js.map +1 -1
  438. package/dist/backend/backend/src/services/marketplace/marketplace.service.js +2 -2
  439. package/dist/backend/backend/src/services/marketplace/template-marketplace.service.d.ts +149 -0
  440. package/dist/backend/backend/src/services/marketplace/template-marketplace.service.d.ts.map +1 -0
  441. package/dist/backend/backend/src/services/marketplace/template-marketplace.service.js +500 -0
  442. package/dist/backend/backend/src/services/marketplace/template-marketplace.service.js.map +1 -0
  443. package/dist/backend/backend/src/services/mcp-server.js +1 -1
  444. package/dist/backend/backend/src/services/mcp-server.js.map +1 -1
  445. package/dist/backend/backend/src/services/messaging/adapters/google-chat-messenger.adapter.d.ts +90 -0
  446. package/dist/backend/backend/src/services/messaging/adapters/google-chat-messenger.adapter.d.ts.map +1 -0
  447. package/dist/backend/backend/src/services/messaging/adapters/google-chat-messenger.adapter.js +233 -0
  448. package/dist/backend/backend/src/services/messaging/adapters/google-chat-messenger.adapter.js.map +1 -0
  449. package/dist/backend/backend/src/services/messaging/messenger-adapter.interface.d.ts +1 -1
  450. package/dist/backend/backend/src/services/messaging/messenger-adapter.interface.d.ts.map +1 -1
  451. package/dist/backend/backend/src/services/messaging/queue-processor.service.js +1 -1
  452. package/dist/backend/backend/src/services/messaging/queue-processor.service.js.map +1 -1
  453. package/dist/backend/backend/src/services/monitoring/activity-monitor.service.d.ts +28 -4
  454. package/dist/backend/backend/src/services/monitoring/activity-monitor.service.d.ts.map +1 -1
  455. package/dist/backend/backend/src/services/monitoring/activity-monitor.service.js +113 -60
  456. package/dist/backend/backend/src/services/monitoring/activity-monitor.service.js.map +1 -1
  457. package/dist/backend/backend/src/services/orchestrator/orchestrator-heartbeat-monitor.service.d.ts.map +1 -1
  458. package/dist/backend/backend/src/services/orchestrator/orchestrator-heartbeat-monitor.service.js +29 -8
  459. package/dist/backend/backend/src/services/orchestrator/orchestrator-heartbeat-monitor.service.js.map +1 -1
  460. package/dist/backend/backend/src/services/payment/magic-moment.service.d.ts +69 -0
  461. package/dist/backend/backend/src/services/payment/magic-moment.service.d.ts.map +1 -0
  462. package/dist/backend/backend/src/services/payment/magic-moment.service.js +158 -0
  463. package/dist/backend/backend/src/services/payment/magic-moment.service.js.map +1 -0
  464. package/dist/backend/backend/src/services/payment/magic-moment.types.d.ts +95 -0
  465. package/dist/backend/backend/src/services/payment/magic-moment.types.d.ts.map +1 -0
  466. package/dist/backend/backend/src/services/payment/magic-moment.types.js +91 -0
  467. package/dist/backend/backend/src/services/payment/magic-moment.types.js.map +1 -0
  468. package/dist/backend/backend/src/services/payment/stripe.service.d.ts +122 -0
  469. package/dist/backend/backend/src/services/payment/stripe.service.d.ts.map +1 -0
  470. package/dist/backend/backend/src/services/payment/stripe.service.js +403 -0
  471. package/dist/backend/backend/src/services/payment/stripe.service.js.map +1 -0
  472. package/dist/backend/backend/src/services/plugin/index.d.ts +9 -0
  473. package/dist/backend/backend/src/services/plugin/index.d.ts.map +1 -0
  474. package/dist/backend/backend/src/services/plugin/index.js +8 -0
  475. package/dist/backend/backend/src/services/plugin/index.js.map +1 -0
  476. package/dist/backend/backend/src/services/plugin/plugin.service.d.ts +102 -0
  477. package/dist/backend/backend/src/services/plugin/plugin.service.d.ts.map +1 -0
  478. package/dist/backend/backend/src/services/plugin/plugin.service.js +179 -0
  479. package/dist/backend/backend/src/services/plugin/plugin.service.js.map +1 -0
  480. package/dist/backend/backend/src/services/plugin/plugin.types.d.ts +88 -0
  481. package/dist/backend/backend/src/services/plugin/plugin.types.d.ts.map +1 -0
  482. package/dist/backend/backend/src/services/plugin/plugin.types.js +17 -0
  483. package/dist/backend/backend/src/services/plugin/plugin.types.js.map +1 -0
  484. package/dist/backend/backend/src/services/project/task-tracking.service.d.ts +17 -0
  485. package/dist/backend/backend/src/services/project/task-tracking.service.d.ts.map +1 -1
  486. package/dist/backend/backend/src/services/project/task-tracking.service.js +63 -0
  487. package/dist/backend/backend/src/services/project/task-tracking.service.js.map +1 -1
  488. package/dist/backend/backend/src/services/session/pty/pty-session-backend.js +1 -1
  489. package/dist/backend/backend/src/services/session/pty/pty-session-backend.js.map +1 -1
  490. package/dist/backend/backend/src/services/session/session-command-helper.d.ts +14 -0
  491. package/dist/backend/backend/src/services/session/session-command-helper.d.ts.map +1 -1
  492. package/dist/backend/backend/src/services/session/session-command-helper.js +70 -4
  493. package/dist/backend/backend/src/services/session/session-command-helper.js.map +1 -1
  494. package/dist/backend/backend/src/services/settings/settings.service.d.ts.map +1 -1
  495. package/dist/backend/backend/src/services/settings/settings.service.js +1 -0
  496. package/dist/backend/backend/src/services/settings/settings.service.js.map +1 -1
  497. package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.d.ts.map +1 -1
  498. package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.js +15 -5
  499. package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.js.map +1 -1
  500. package/dist/backend/backend/src/services/template/template.service.d.ts +153 -0
  501. package/dist/backend/backend/src/services/template/template.service.d.ts.map +1 -0
  502. package/dist/backend/backend/src/services/template/template.service.js +372 -0
  503. package/dist/backend/backend/src/services/template/template.service.js.map +1 -0
  504. package/dist/backend/backend/src/services/workflow/scheduler.service.d.ts +51 -0
  505. package/dist/backend/backend/src/services/workflow/scheduler.service.d.ts.map +1 -1
  506. package/dist/backend/backend/src/services/workflow/scheduler.service.js +118 -2
  507. package/dist/backend/backend/src/services/workflow/scheduler.service.js.map +1 -1
  508. package/dist/backend/backend/src/types/chat.types.d.ts +39 -1
  509. package/dist/backend/backend/src/types/chat.types.d.ts.map +1 -1
  510. package/dist/backend/backend/src/types/chat.types.js +45 -2
  511. package/dist/backend/backend/src/types/chat.types.js.map +1 -1
  512. package/dist/backend/backend/src/types/event-bus.types.d.ts +14 -2
  513. package/dist/backend/backend/src/types/event-bus.types.d.ts.map +1 -1
  514. package/dist/backend/backend/src/types/event-bus.types.js +15 -0
  515. package/dist/backend/backend/src/types/event-bus.types.js.map +1 -1
  516. package/dist/backend/backend/src/types/hierarchy-message.types.d.ts +101 -0
  517. package/dist/backend/backend/src/types/hierarchy-message.types.d.ts.map +1 -0
  518. package/dist/backend/backend/src/types/hierarchy-message.types.js +15 -0
  519. package/dist/backend/backend/src/types/hierarchy-message.types.js.map +1 -0
  520. package/dist/backend/backend/src/types/index.d.ts +54 -4
  521. package/dist/backend/backend/src/types/index.d.ts.map +1 -1
  522. package/dist/backend/backend/src/types/index.js.map +1 -1
  523. package/dist/backend/backend/src/types/marketplace.types.d.ts +99 -0
  524. package/dist/backend/backend/src/types/marketplace.types.d.ts.map +1 -1
  525. package/dist/backend/backend/src/types/settings.types.d.ts +1 -1
  526. package/dist/backend/backend/src/types/settings.types.d.ts.map +1 -1
  527. package/dist/backend/backend/src/types/settings.types.js +4 -0
  528. package/dist/backend/backend/src/types/settings.types.js.map +1 -1
  529. package/dist/backend/backend/src/types/task-tracking.types.d.ts +79 -1
  530. package/dist/backend/backend/src/types/task-tracking.types.d.ts.map +1 -1
  531. package/dist/backend/backend/src/types/task-tracking.types.js.map +1 -1
  532. package/dist/backend/backend/src/types/team-template.types.d.ts +166 -0
  533. package/dist/backend/backend/src/types/team-template.types.d.ts.map +1 -0
  534. package/dist/backend/backend/src/types/team-template.types.js +139 -0
  535. package/dist/backend/backend/src/types/team-template.types.js.map +1 -0
  536. package/dist/backend/backend/src/utils/async-handler.d.ts +20 -0
  537. package/dist/backend/backend/src/utils/async-handler.d.ts.map +1 -0
  538. package/dist/backend/backend/src/utils/async-handler.js +29 -0
  539. package/dist/backend/backend/src/utils/async-handler.js.map +1 -0
  540. package/dist/backend/backend/src/utils/defaultPrompts.d.ts +4 -4
  541. package/dist/backend/backend/src/utils/defaultPrompts.d.ts.map +1 -1
  542. package/dist/backend/backend/src/utils/defaultPrompts.js +16 -0
  543. package/dist/backend/backend/src/utils/defaultPrompts.js.map +1 -1
  544. package/dist/backend/backend/src/utils/gemini-trusted-folders.d.ts +43 -0
  545. package/dist/backend/backend/src/utils/gemini-trusted-folders.d.ts.map +1 -0
  546. package/dist/backend/backend/src/utils/gemini-trusted-folders.js +94 -0
  547. package/dist/backend/backend/src/utils/gemini-trusted-folders.js.map +1 -0
  548. package/dist/backend/backend/src/utils/message-serializer.d.ts +74 -0
  549. package/dist/backend/backend/src/utils/message-serializer.d.ts.map +1 -0
  550. package/dist/backend/backend/src/utils/message-serializer.js +380 -0
  551. package/dist/backend/backend/src/utils/message-serializer.js.map +1 -0
  552. package/dist/backend/backend/src/utils/terminal-output.utils.d.ts +2 -1
  553. package/dist/backend/backend/src/utils/terminal-output.utils.d.ts.map +1 -1
  554. package/dist/backend/backend/src/utils/terminal-output.utils.js +2 -28
  555. package/dist/backend/backend/src/utils/terminal-output.utils.js.map +1 -1
  556. package/dist/backend/backend/src/utils/terminal-string-ops.d.ts +183 -0
  557. package/dist/backend/backend/src/utils/terminal-string-ops.d.ts.map +1 -0
  558. package/dist/backend/backend/src/utils/terminal-string-ops.js +726 -0
  559. package/dist/backend/backend/src/utils/terminal-string-ops.js.map +1 -0
  560. package/dist/backend/backend/src/websocket/terminal.gateway.d.ts.map +1 -1
  561. package/dist/backend/backend/src/websocket/terminal.gateway.js +22 -27
  562. package/dist/backend/backend/src/websocket/terminal.gateway.js.map +1 -1
  563. package/dist/backend/config/constants.d.ts +40 -1
  564. package/dist/backend/config/constants.d.ts.map +1 -1
  565. package/dist/backend/config/constants.js +41 -1
  566. package/dist/backend/config/constants.js.map +1 -1
  567. package/dist/backend/config/index.d.ts +2 -2
  568. package/dist/backend/config/index.d.ts.map +1 -1
  569. package/dist/backend/config/index.js +2 -2
  570. package/dist/backend/config/index.js.map +1 -1
  571. package/dist/cli/backend/src/constants.d.ts +310 -84
  572. package/dist/cli/backend/src/constants.d.ts.map +1 -1
  573. package/dist/cli/backend/src/constants.js +303 -89
  574. package/dist/cli/backend/src/constants.js.map +1 -1
  575. package/dist/cli/backend/src/models/Team.d.ts +5 -0
  576. package/dist/cli/backend/src/models/Team.d.ts.map +1 -1
  577. package/dist/cli/backend/src/models/Team.js +24 -0
  578. package/dist/cli/backend/src/models/Team.js.map +1 -1
  579. package/dist/cli/backend/src/services/core/storage.service.d.ts.map +1 -1
  580. package/dist/cli/backend/src/services/core/storage.service.js +5 -0
  581. package/dist/cli/backend/src/services/core/storage.service.js.map +1 -1
  582. package/dist/cli/backend/src/services/mcp-server.js +1 -1
  583. package/dist/cli/backend/src/services/mcp-server.js.map +1 -1
  584. package/dist/cli/backend/src/types/chat.types.d.ts +39 -1
  585. package/dist/cli/backend/src/types/chat.types.d.ts.map +1 -1
  586. package/dist/cli/backend/src/types/chat.types.js +45 -2
  587. package/dist/cli/backend/src/types/chat.types.js.map +1 -1
  588. package/dist/cli/backend/src/types/index.d.ts +54 -4
  589. package/dist/cli/backend/src/types/index.d.ts.map +1 -1
  590. package/dist/cli/backend/src/types/index.js.map +1 -1
  591. package/dist/cli/backend/src/types/settings.types.d.ts +1 -1
  592. package/dist/cli/backend/src/types/settings.types.d.ts.map +1 -1
  593. package/dist/cli/backend/src/types/settings.types.js +4 -0
  594. package/dist/cli/backend/src/types/settings.types.js.map +1 -1
  595. package/dist/cli/backend/src/utils/gemini-trusted-folders.d.ts +43 -0
  596. package/dist/cli/backend/src/utils/gemini-trusted-folders.d.ts.map +1 -0
  597. package/dist/cli/backend/src/utils/gemini-trusted-folders.js +94 -0
  598. package/dist/cli/backend/src/utils/gemini-trusted-folders.js.map +1 -0
  599. package/dist/cli/backend/src/utils/terminal-output.utils.d.ts +2 -1
  600. package/dist/cli/backend/src/utils/terminal-output.utils.d.ts.map +1 -1
  601. package/dist/cli/backend/src/utils/terminal-output.utils.js +2 -28
  602. package/dist/cli/backend/src/utils/terminal-output.utils.js.map +1 -1
  603. package/dist/cli/backend/src/utils/terminal-string-ops.d.ts +183 -0
  604. package/dist/cli/backend/src/utils/terminal-string-ops.d.ts.map +1 -0
  605. package/dist/cli/backend/src/utils/terminal-string-ops.js +726 -0
  606. package/dist/cli/backend/src/utils/terminal-string-ops.js.map +1 -0
  607. package/dist/cli/cli/src/commands/onboard.d.ts +2 -1
  608. package/dist/cli/cli/src/commands/onboard.d.ts.map +1 -1
  609. package/dist/cli/cli/src/commands/onboard.js +21 -8
  610. package/dist/cli/cli/src/commands/onboard.js.map +1 -1
  611. package/dist/cli/cli/src/commands/start.d.ts +1 -0
  612. package/dist/cli/cli/src/commands/start.d.ts.map +1 -1
  613. package/dist/cli/cli/src/commands/start.js +71 -23
  614. package/dist/cli/cli/src/commands/start.js.map +1 -1
  615. package/dist/cli/cli/src/constants.d.ts +1 -1
  616. package/dist/cli/cli/src/constants.d.ts.map +1 -1
  617. package/dist/cli/cli/src/constants.js +1 -1
  618. package/dist/cli/cli/src/constants.js.map +1 -1
  619. package/dist/cli/cli/src/index.js +1 -0
  620. package/dist/cli/cli/src/index.js.map +1 -1
  621. package/dist/cli/cli/src/utils/project-scaffold.d.ts +109 -0
  622. package/dist/cli/cli/src/utils/project-scaffold.d.ts.map +1 -0
  623. package/dist/cli/cli/src/utils/project-scaffold.js +346 -0
  624. package/dist/cli/cli/src/utils/project-scaffold.js.map +1 -0
  625. package/dist/cli/cli/src/utils/templates.d.ts +7 -2
  626. package/dist/cli/cli/src/utils/templates.d.ts.map +1 -1
  627. package/dist/cli/cli/src/utils/templates.js +76 -7
  628. package/dist/cli/cli/src/utils/templates.js.map +1 -1
  629. package/dist/cli/config/constants.d.ts +40 -1
  630. package/dist/cli/config/constants.d.ts.map +1 -1
  631. package/dist/cli/config/constants.js +41 -1
  632. package/dist/cli/config/constants.js.map +1 -1
  633. package/dist/cli/config/index.d.ts +2 -2
  634. package/dist/cli/config/index.d.ts.map +1 -1
  635. package/dist/cli/config/index.js +2 -2
  636. package/dist/cli/config/index.js.map +1 -1
  637. package/frontend/dist/assets/index-510ab719.css +33 -0
  638. package/frontend/dist/assets/index-935cd846.js +4961 -0
  639. package/frontend/dist/index.html +2 -2
  640. package/package.json +9 -4
  641. package/frontend/dist/assets/index-a23214ae.js +0 -4919
  642. package/frontend/dist/assets/index-c407fe13.css +0 -33
@@ -4,16 +4,20 @@ import { readFile, readdir, stat, mkdir, writeFile, access } from 'fs/promises';
4
4
  import { LoggerService } from '../core/logger.service.js';
5
5
  import { createSessionCommandHelper, getSessionBackendSync, createSessionBackend, getSessionStatePersistence, } from '../session/index.js';
6
6
  import { RuntimeServiceFactory } from './runtime-service.factory.js';
7
- import { CREWLY_CONSTANTS, ENV_CONSTANTS, AGENT_TIMEOUTS, ORCHESTRATOR_SESSION_NAME, ORCHESTRATOR_ROLE, RUNTIME_TYPES, SESSION_COMMAND_DELAYS, EVENT_DELIVERY_CONSTANTS, TERMINAL_PATTERNS, GEMINI_SHELL_MODE_CONSTANTS, } from '../../constants.js';
7
+ import { CREWLY_CONSTANTS, ENV_CONSTANTS, AGENT_TIMEOUTS, ORCHESTRATOR_SESSION_NAME, ORCHESTRATOR_ROLE, RUNTIME_TYPES, SESSION_COMMAND_DELAYS, EVENT_DELIVERY_CONSTANTS, TERMINAL_PATTERNS, GEMINI_SHELL_MODE_CONSTANTS, GEMINI_STUCK_CONNECTIVITY_PATTERN, GEMINI_ERROR_STATE_CONSTANTS, } from '../../constants.js';
8
8
  import { WEB_CONSTANTS } from '../../../../config/constants.js';
9
9
  import { delay } from '../../utils/async.utils.js';
10
10
  import { getSettingsService } from '../settings/settings.service.js';
11
11
  import { SessionMemoryService } from '../memory/session-memory.service.js';
12
12
  import { RuntimeExitMonitorService } from './runtime-exit-monitor.service.js';
13
13
  import { ContextWindowMonitorService } from './context-window-monitor.service.js';
14
+ import { OAuthReloginMonitorService } from './oauth-relogin-monitor.service.js';
14
15
  import { SubAgentMessageQueue } from '../messaging/sub-agent-message-queue.service.js';
15
16
  import { AgentSuspendService } from './agent-suspend.service.js';
17
+ import { PromptBuilderService } from '../ai/prompt-builder.service.js';
16
18
  import { stripAnsiCodes } from '../../utils/terminal-output.utils.js';
19
+ import { isPromptLine, containsSpinnerOrWorkingIndicator, containsProcessingIndicator, containsBusyStatusBar, containsRewindMode, containsGeminiProcessingKeywords, extractChatPrefix, stripTuiLineBorders, matchTuiPromptLine, } from '../../utils/terminal-string-ops.js';
20
+ import { PtyActivityTrackerService } from './pty-activity-tracker.service.js';
17
21
  /**
18
22
  * Service responsible for the complex, multi-step process of agent initialization and registration.
19
23
  * Isolates the complex state management of agent startup with progressive escalation.
@@ -46,17 +50,14 @@ export class AgentRegistrationService {
46
50
  // Prevents concurrent sendMessageWithRetry calls to the same session,
47
51
  // which causes multiple Ctrl+C presses that can crash the runtime.
48
52
  sessionDeliveryMutex = new Map();
53
+ // Per-session hash of last sent message to prevent duplicate writes (#128).
54
+ // Key: sessionName, Value: { hash, sentAt }
55
+ lastSentMessageHash = new Map();
49
56
  // Terminal patterns are now centralized in TERMINAL_PATTERNS constant
50
- // Keeping these as static getters for backwards compatibility within the class
57
+ // Keeping prompt chars as static getter for backwards compatibility within the class
51
58
  static get CLAUDE_PROMPT_INDICATORS() {
52
59
  return TERMINAL_PATTERNS.PROMPT_CHARS;
53
60
  }
54
- static get CLAUDE_PROMPT_STREAM_PATTERN() {
55
- return TERMINAL_PATTERNS.PROMPT_STREAM;
56
- }
57
- static get CLAUDE_PROCESSING_INDICATORS() {
58
- return TERMINAL_PATTERNS.PROCESSING_INDICATORS;
59
- }
60
61
  constructor(_legacyTmuxService, // Legacy parameter for backwards compatibility
61
62
  projectRoot, storageService) {
62
63
  this.logger = LoggerService.getInstance().createComponentLogger('AgentRegistrationService');
@@ -455,6 +456,8 @@ export class AgentRegistrationService {
455
456
  // Must be before postInitialize and sendRegistrationPromptAsync so exits
456
457
  // during those phases are detected and the abort signal fires in time.
457
458
  RuntimeExitMonitorService.getInstance().startMonitoring(sessionName, runtimeType, role);
459
+ // Start OAuth relogin monitoring for automatic re-authentication
460
+ OAuthReloginMonitorService.getInstance().startMonitoring(sessionName, runtimeType);
458
461
  // Look up per-agent browser automation override from member config
459
462
  let browserAutomationOverride;
460
463
  if (memberId) {
@@ -691,6 +694,8 @@ export class AgentRegistrationService {
691
694
  }
692
695
  // Start runtime exit monitoring immediately after runtime is ready
693
696
  RuntimeExitMonitorService.getInstance().startMonitoring(sessionName, runtimeType, role);
697
+ // Start OAuth relogin monitoring for automatic re-authentication
698
+ OAuthReloginMonitorService.getInstance().startMonitoring(sessionName, runtimeType);
694
699
  // Additional verification: Use runtime detection to confirm runtime is responding
695
700
  // Wait a bit longer for runtime to fully load after showing welcome message
696
701
  this.logger.debug('Runtime ready detected for orchestrator, waiting for full startup before verification', { sessionName, runtimeType });
@@ -733,6 +738,8 @@ export class AgentRegistrationService {
733
738
  }
734
739
  // Start runtime exit monitoring immediately after runtime is ready
735
740
  RuntimeExitMonitorService.getInstance().startMonitoring(sessionName, runtimeType, role);
741
+ // Start OAuth relogin monitoring for automatic re-authentication
742
+ OAuthReloginMonitorService.getInstance().startMonitoring(sessionName, runtimeType);
736
743
  }
737
744
  // Look up per-agent browser automation override from member config
738
745
  let browserOverrideForRecreation;
@@ -840,17 +847,23 @@ export class AgentRegistrationService {
840
847
  // For orchestrator or cases without member ID, remove the memberId parameter
841
848
  prompt = prompt.replace(/,\s*"memberId":\s*"\{\{MEMBER_ID\}\}"/g, '');
842
849
  }
843
- // Look up project path for team members
850
+ // Look up project path and TL hierarchy for team members
844
851
  let projectPath = process.cwd();
852
+ let foundTeam = null;
853
+ let foundMember = null;
845
854
  try {
846
855
  const teams = await this.storageService.getTeams();
847
856
  for (const team of teams) {
848
857
  const member = team.members?.find((m) => m.sessionName === sessionName);
849
- if (member && team.projectIds[0]) {
850
- const projects = await this.storageService.getProjects();
851
- const project = projects.find((p) => p.id === team.projectIds[0]);
852
- if (project?.path) {
853
- projectPath = project.path;
858
+ if (member) {
859
+ foundTeam = team;
860
+ foundMember = member;
861
+ if (team.projectIds[0]) {
862
+ const projects = await this.storageService.getProjects();
863
+ const project = projects.find((p) => p.id === team.projectIds[0]);
864
+ if (project?.path) {
865
+ projectPath = project.path;
866
+ }
854
867
  }
855
868
  break;
856
869
  }
@@ -892,6 +905,53 @@ export class AgentRegistrationService {
892
905
  // Replace marketplace skills path placeholder
893
906
  const marketplaceSkillsPath = path.join(os.homedir(), '.crewly', 'marketplace', 'skills');
894
907
  prompt = prompt.replace(/\{\{MARKETPLACE_SKILLS_PATH\}\}/g, marketplaceSkillsPath);
908
+ // Inject Team Lead addon for members with canDelegate=true and subordinates
909
+ if (foundMember?.canDelegate && foundMember.subordinateIds && foundMember.subordinateIds.length > 0 && foundTeam) {
910
+ try {
911
+ // Resolve subordinateIds to SubordinateInfo[]
912
+ const subordinates = foundMember.subordinateIds
913
+ .map((subId) => {
914
+ const subMember = foundTeam.members?.find((m) => m.id === subId);
915
+ if (!subMember)
916
+ return null;
917
+ return {
918
+ name: subMember.name,
919
+ sessionName: subMember.sessionName || '',
920
+ role: subMember.role || 'developer',
921
+ };
922
+ })
923
+ .filter((s) => s !== null);
924
+ if (subordinates.length > 0) {
925
+ const tlConfig = {
926
+ name: sessionName,
927
+ role: role,
928
+ systemPrompt: '',
929
+ projectPath,
930
+ memberId,
931
+ teamId: foundTeam.id,
932
+ canDelegate: true,
933
+ subordinates,
934
+ };
935
+ const promptBuilder = new PromptBuilderService(this.projectRoot);
936
+ const tlSection = await promptBuilder.buildTeamLeadSection(tlConfig);
937
+ if (tlSection) {
938
+ prompt += `\n\n---\n\n${tlSection}`;
939
+ this.logger.info('TL addon injected into init prompt', {
940
+ sessionName,
941
+ subordinateCount: subordinates.length,
942
+ subordinateNames: subordinates.map((s) => s.name),
943
+ tlSectionLength: tlSection.length,
944
+ });
945
+ }
946
+ }
947
+ }
948
+ catch (tlError) {
949
+ this.logger.warn('Failed to inject TL addon (non-critical)', {
950
+ sessionName,
951
+ error: tlError instanceof Error ? tlError.message : String(tlError),
952
+ });
953
+ }
954
+ }
895
955
  // Generate and inject startup briefing from session memory
896
956
  try {
897
957
  const sessionMemoryService = SessionMemoryService.getInstance();
@@ -1444,6 +1504,8 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
1444
1504
  if (role !== ORCHESTRATOR_ROLE && config.teamId && config.memberId) {
1445
1505
  ContextWindowMonitorService.getInstance().startSessionMonitoring(sessionName, config.memberId, config.teamId, role, runtimeType);
1446
1506
  }
1507
+ // Start OAuth relogin monitoring for recovered session
1508
+ OAuthReloginMonitorService.getInstance().startMonitoring(sessionName, runtimeType);
1447
1509
  return {
1448
1510
  success: true,
1449
1511
  sessionName,
@@ -1508,6 +1570,14 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
1508
1570
  await sessionHelper.setEnvironmentVariable(sessionName, ENV_CONSTANTS.CREWLY_SESSION_NAME, sessionName);
1509
1571
  await sessionHelper.setEnvironmentVariable(sessionName, ENV_CONSTANTS.CREWLY_ROLE, role);
1510
1572
  await sessionHelper.setEnvironmentVariable(sessionName, ENV_CONSTANTS.CREWLY_API_URL, `http://localhost:${WEB_CONSTANTS.PORTS.BACKEND}`);
1573
+ // Pass Gemini API key to gemini-cli agents so they authenticate
1574
+ // with the paid API key instead of the free-tier Google login.
1575
+ if (runtimeType === RUNTIME_TYPES.GEMINI_CLI) {
1576
+ const geminiApiKey = process.env[ENV_CONSTANTS.GEMINI_API_KEY];
1577
+ if (geminiApiKey) {
1578
+ await sessionHelper.setEnvironmentVariable(sessionName, ENV_CONSTANTS.GEMINI_API_KEY, geminiApiKey);
1579
+ }
1580
+ }
1511
1581
  this.logger.info('Agent session created and environment variables set, initializing with registration', {
1512
1582
  sessionName,
1513
1583
  role,
@@ -1529,6 +1599,8 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
1529
1599
  if (role !== ORCHESTRATOR_ROLE && config.teamId && config.memberId) {
1530
1600
  ContextWindowMonitorService.getInstance().startSessionMonitoring(sessionName, config.memberId, config.teamId, role, runtimeType);
1531
1601
  }
1602
+ // Start OAuth relogin monitoring for newly created session
1603
+ OAuthReloginMonitorService.getInstance().startMonitoring(sessionName, runtimeType);
1532
1604
  return {
1533
1605
  success: true,
1534
1606
  sessionName,
@@ -1560,6 +1632,8 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
1560
1632
  this.logger.info('Terminating agent session (unified approach)', { sessionName, role });
1561
1633
  // Stop runtime exit monitoring before killing the session
1562
1634
  RuntimeExitMonitorService.getInstance().stopMonitoring(sessionName);
1635
+ // Stop OAuth relogin monitoring before killing the session
1636
+ OAuthReloginMonitorService.getInstance().stopMonitoring(sessionName);
1563
1637
  // Stop context window monitoring before killing the session
1564
1638
  ContextWindowMonitorService.getInstance().stopSessionMonitoring(sessionName);
1565
1639
  // Get session helper once to avoid repeated async calls
@@ -1701,9 +1775,9 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
1701
1775
  if (!delivered) {
1702
1776
  // Check if the agent is actively processing (busy) — the queue
1703
1777
  // processor can re-queue instead of permanently failing the message.
1704
- const busyOutput = sessionHelper.capturePane(sessionName).slice(-2000);
1705
- const isBusy = TERMINAL_PATTERNS.BUSY_STATUS_BAR.test(busyOutput) ||
1706
- TERMINAL_PATTERNS.PROCESSING_WITH_TEXT.test(busyOutput);
1778
+ // Use PTY idle time instead of regex patterns for robust cross-runtime detection.
1779
+ const idleMs = PtyActivityTrackerService.getInstance().getIdleTimeMs(sessionName);
1780
+ const isBusy = idleMs < SESSION_COMMAND_DELAYS.AGENT_BUSY_IDLE_THRESHOLD_MS;
1707
1781
  return {
1708
1782
  success: false,
1709
1783
  error: isBusy
@@ -1768,9 +1842,6 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
1768
1842
  if (!session) {
1769
1843
  return false;
1770
1844
  }
1771
- // Use runtime-specific pattern for stream detection to avoid false positives
1772
- // (e.g. Gemini's `> ` pattern matching markdown blockquotes in Claude Code output)
1773
- const streamPattern = this.getPromptPatternForRuntime(runtimeType);
1774
1845
  return new Promise((resolve) => {
1775
1846
  let resolved = false;
1776
1847
  const pollInterval = EVENT_DELIVERY_CONSTANTS.AGENT_READY_POLL_INTERVAL;
@@ -1817,9 +1888,11 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
1817
1888
  if (resolved)
1818
1889
  return;
1819
1890
  // Strip ANSI escape sequences before testing — raw PTY data contains
1820
- // cursor positioning, color codes, etc. that break regex matching (#106)
1891
+ // cursor positioning, color codes, etc. that break pattern matching (#106)
1821
1892
  const cleanData = stripAnsiCodes(data);
1822
- if (streamPattern.test(cleanData)) {
1893
+ // Check each line for prompt pattern (string-based, no regex)
1894
+ const hasPromptInStream = cleanData.split('\n').some(line => line.trim().length > 0 && isPromptLine(line, runtimeType));
1895
+ if (hasPromptInStream) {
1823
1896
  // Double-check with capturePane to avoid false positives from partial data
1824
1897
  const output = sessionHelper.capturePane(sessionName);
1825
1898
  if (this.isClaudeAtPrompt(output, runtimeType)) {
@@ -1831,256 +1904,6 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
1831
1904
  });
1832
1905
  });
1833
1906
  }
1834
- /**
1835
- * @deprecated Replaced by SessionCommandHelper.sendMessage() in sendMessageWithRetry.
1836
- * Complex event-driven state machine was fragile — Enter key often got lost.
1837
- * Kept as dead code for reference during transition.
1838
- */
1839
- async _deprecated_sendMessageEventDriven(sessionName, message, timeoutMs = EVENT_DELIVERY_CONSTANTS.TOTAL_DELIVERY_TIMEOUT) {
1840
- const sessionHelper = await this.getSessionHelper();
1841
- const session = sessionHelper.getSession(sessionName);
1842
- if (!session) {
1843
- this.logger.error('Session not found for event-driven delivery', { sessionName });
1844
- return false;
1845
- }
1846
- return new Promise((resolve) => {
1847
- let buffer = '';
1848
- let messageSent = false;
1849
- let enterSent = false;
1850
- let enterAccepted = false;
1851
- let deliveryConfirmed = false;
1852
- let resolved = false;
1853
- // Track all timeouts to prevent memory leaks (P1.1 fix)
1854
- const pendingTimeouts = [];
1855
- const scheduleTimeout = (fn, delayMs) => {
1856
- const id = setTimeout(fn, delayMs);
1857
- pendingTimeouts.push(id);
1858
- return id;
1859
- };
1860
- const cleanup = () => {
1861
- // Immediately mark as resolved to prevent race conditions (P1.2 fix)
1862
- const wasResolved = resolved;
1863
- resolved = true;
1864
- if (!wasResolved) {
1865
- // Clear all pending timeouts to prevent memory leaks
1866
- pendingTimeouts.forEach((id) => clearTimeout(id));
1867
- clearTimeout(timeoutId);
1868
- unsubscribe();
1869
- }
1870
- };
1871
- // Use centralized patterns from TERMINAL_PATTERNS
1872
- const PASTE_PATTERN = TERMINAL_PATTERNS.PASTE_INDICATOR;
1873
- const PROCESSING_PATTERN = TERMINAL_PATTERNS.PROCESSING;
1874
- // Use centralized timing from EVENT_DELIVERY_CONSTANTS
1875
- const INITIAL_DELAY = EVENT_DELIVERY_CONSTANTS.INITIAL_MESSAGE_DELAY;
1876
- const PASTE_CHECK_DELAY = EVENT_DELIVERY_CONSTANTS.PASTE_CHECK_DELAY;
1877
- const ENTER_RETRY_DELAY = EVENT_DELIVERY_CONSTANTS.ENTER_RETRY_DELAY;
1878
- const MAX_ENTER_RETRIES = EVENT_DELIVERY_CONSTANTS.MAX_ENTER_RETRIES;
1879
- const MAX_BUFFER_SIZE = EVENT_DELIVERY_CONSTANTS.MAX_BUFFER_SIZE;
1880
- // Helper to send the message when prompt is detected
1881
- const sendMessageNow = () => {
1882
- if (messageSent || resolved)
1883
- return;
1884
- this.logger.debug('Claude at prompt, sending message', {
1885
- sessionName,
1886
- messageLength: message.length,
1887
- isMultiLine: message.includes('\n'),
1888
- });
1889
- // Send the message text
1890
- session.write(message);
1891
- messageSent = true;
1892
- const isMultiLine = message.includes('\n');
1893
- // Track Enter key state
1894
- let enterAttempts = 0;
1895
- let processingDetected = false;
1896
- const bufferAtSend = buffer;
1897
- // Function to send Enter and track attempts
1898
- const sendEnterKey = (reason) => {
1899
- if (resolved || processingDetected)
1900
- return;
1901
- enterAttempts++;
1902
- session.write('\r');
1903
- enterSent = true;
1904
- this.logger.debug('Enter key sent', {
1905
- sessionName,
1906
- attempt: enterAttempts,
1907
- reason,
1908
- });
1909
- };
1910
- // Function to check if Enter was accepted (processing started)
1911
- const checkProcessingStarted = () => {
1912
- const newData = buffer.slice(bufferAtSend.length);
1913
- return PROCESSING_PATTERN.test(newData);
1914
- };
1915
- // Function to check for paste indicator
1916
- const checkPasteIndicator = () => {
1917
- const newData = buffer.slice(bufferAtSend.length);
1918
- return PASTE_PATTERN.test(newData);
1919
- };
1920
- // Strategy: Send Enter with progressive timing, retry if not accepted
1921
- const attemptEnter = (attemptNum) => {
1922
- if (resolved || processingDetected)
1923
- return;
1924
- // Check if processing already started
1925
- if (checkProcessingStarted()) {
1926
- processingDetected = true;
1927
- enterAccepted = true;
1928
- this.logger.debug('Processing detected, message accepted', { sessionName, attemptNum });
1929
- buffer = ''; // Reset for processing indicator detection
1930
- return;
1931
- }
1932
- if (attemptNum > MAX_ENTER_RETRIES) {
1933
- this.logger.warn('Max Enter retries reached, verifying message acceptance', { sessionName });
1934
- scheduleTimeout(async () => {
1935
- if (resolved)
1936
- return;
1937
- const stuck = await this.isMessageStuckAtPrompt(sessionName, message);
1938
- if (stuck) {
1939
- this.logger.warn('Message stuck at prompt after all Enter retries', { sessionName });
1940
- const stuckHelper = await this.getSessionHelper();
1941
- await stuckHelper.clearCurrentCommandLine(sessionName);
1942
- enterAccepted = false;
1943
- }
1944
- else {
1945
- this.logger.debug('Message appears accepted (no longer at prompt)', { sessionName });
1946
- enterAccepted = true;
1947
- buffer = '';
1948
- }
1949
- }, EVENT_DELIVERY_CONSTANTS.POST_ENTER_VERIFICATION_DELAY);
1950
- return;
1951
- }
1952
- sendEnterKey(attemptNum === 1 ? 'initial' : `retry-${attemptNum}`);
1953
- // Schedule check and possible retry (using tracked timeout to prevent leaks)
1954
- scheduleTimeout(() => {
1955
- if (resolved)
1956
- return;
1957
- if (checkProcessingStarted()) {
1958
- processingDetected = true;
1959
- enterAccepted = true;
1960
- this.logger.debug('Processing detected after Enter', { sessionName, attemptNum });
1961
- buffer = '';
1962
- }
1963
- else {
1964
- // Not accepted yet, retry
1965
- this.logger.debug('Enter may not have been accepted, retrying', {
1966
- sessionName,
1967
- attemptNum,
1968
- bufferLength: buffer.length,
1969
- });
1970
- attemptEnter(attemptNum + 1);
1971
- }
1972
- }, ENTER_RETRY_DELAY);
1973
- };
1974
- // For multi-line messages, wait longer for paste indicator
1975
- // For single-line messages, send Enter sooner
1976
- const initialWait = isMultiLine ? PASTE_CHECK_DELAY : INITIAL_DELAY;
1977
- scheduleTimeout(() => {
1978
- if (resolved)
1979
- return;
1980
- // For multi-line: check if paste indicator appeared
1981
- if (isMultiLine && checkPasteIndicator()) {
1982
- this.logger.debug('Paste indicator detected', { sessionName });
1983
- }
1984
- // Start Enter key attempts
1985
- attemptEnter(1);
1986
- }, initialWait);
1987
- };
1988
- const timeoutId = setTimeout(async () => {
1989
- this.logger.debug('Event-driven delivery timed out', {
1990
- sessionName,
1991
- messageSent,
1992
- enterSent,
1993
- enterAccepted,
1994
- deliveryConfirmed,
1995
- bufferLength: buffer.length,
1996
- });
1997
- // If Enter was sent but not confirmed accepted, verify via terminal capture
1998
- if (enterSent && !enterAccepted && !deliveryConfirmed) {
1999
- const timeoutHelper = await this.getSessionHelper();
2000
- const stuck = await this.isMessageStuckAtPrompt(sessionName, message);
2001
- if (stuck) {
2002
- this.logger.warn('Timeout: message stuck at prompt, clearing and failing', { sessionName });
2003
- await timeoutHelper.clearCurrentCommandLine(sessionName);
2004
- cleanup();
2005
- resolve(false);
2006
- return;
2007
- }
2008
- this.logger.debug('Timeout: message not at prompt, treating as accepted', { sessionName });
2009
- }
2010
- cleanup();
2011
- resolve(enterAccepted || deliveryConfirmed);
2012
- }, timeoutMs);
2013
- // IMPORTANT: Check current terminal state, but wait for output to settle first.
2014
- // If the orchestrator just finished outputting (greeting, notification, status bar),
2015
- // the prompt may not be cleanly detectable. We capture the pane, wait briefly,
2016
- // and re-capture. If output is still changing, wait again before checking prompt.
2017
- // Use 50 lines to account for status bars and notifications that can
2018
- // wrap across many lines and push the prompt out of a smaller window.
2019
- const waitForSettled = async () => {
2020
- let prevOutput = sessionHelper.capturePane(sessionName);
2021
- for (let i = 0; i < 5; i++) { // Max 5 checks, 500ms apart = 2.5s max
2022
- if (resolved)
2023
- return;
2024
- await delay(500);
2025
- if (resolved)
2026
- return;
2027
- const currentOutput = sessionHelper.capturePane(sessionName);
2028
- if (currentOutput === prevOutput) {
2029
- // Output settled
2030
- if (this.isClaudeAtPrompt(currentOutput)) {
2031
- this.logger.debug('Claude at prompt after output settled', { sessionName, settleChecks: i + 1 });
2032
- sendMessageNow();
2033
- }
2034
- return;
2035
- }
2036
- prevOutput = currentOutput;
2037
- }
2038
- // Output still changing after 2.5s - check anyway
2039
- if (!resolved && this.isClaudeAtPrompt(prevOutput)) {
2040
- this.logger.debug('Claude at prompt (output still changing, checking anyway)', { sessionName });
2041
- sendMessageNow();
2042
- }
2043
- };
2044
- waitForSettled();
2045
- const unsubscribe = session.onData((data) => {
2046
- if (resolved)
2047
- return;
2048
- // Accumulate data with size limit to prevent memory exhaustion (P2.3 fix)
2049
- buffer += data;
2050
- if (buffer.length > MAX_BUFFER_SIZE) {
2051
- buffer = buffer.slice(-MAX_BUFFER_SIZE);
2052
- }
2053
- // Phase 1: Wait for Claude to be at prompt before sending
2054
- if (!messageSent) {
2055
- const isAtPrompt = AgentRegistrationService.CLAUDE_PROMPT_STREAM_PATTERN.test(buffer);
2056
- if (isAtPrompt) {
2057
- sendMessageNow();
2058
- }
2059
- return;
2060
- }
2061
- // Phase 2: Only check for processing indicators AFTER Enter has been sent
2062
- if (!enterSent) {
2063
- return; // Wait for Enter to be sent
2064
- }
2065
- // Look for processing indicators confirming delivery
2066
- const hasProcessingIndicator = AgentRegistrationService.CLAUDE_PROCESSING_INDICATORS.some((pattern) => pattern.test(buffer));
2067
- // Also check if prompt disappeared (Claude is working)
2068
- const promptStillVisible = AgentRegistrationService.CLAUDE_PROMPT_STREAM_PATTERN.test(buffer);
2069
- // Use constant for minimum buffer check (P3.2 fix)
2070
- if (hasProcessingIndicator || (!promptStillVisible && buffer.length > EVENT_DELIVERY_CONSTANTS.MIN_BUFFER_FOR_PROCESSING_DETECTION)) {
2071
- this.logger.debug('Message delivery confirmed (event-driven)', {
2072
- sessionName,
2073
- hasProcessingIndicator,
2074
- promptStillVisible,
2075
- bufferLength: buffer.length,
2076
- });
2077
- deliveryConfirmed = true;
2078
- cleanup();
2079
- resolve(true);
2080
- }
2081
- });
2082
- });
2083
- }
2084
1907
  /**
2085
1908
  * Send message with retry logic for reliable delivery to Claude Code.
2086
1909
  * Uses SessionCommandHelper.sendMessage() (proven two-step write pattern)
@@ -2111,15 +1934,24 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
2111
1934
  });
2112
1935
  // Verify agent is at prompt before sending
2113
1936
  const output = sessionHelper.capturePane(sessionName);
1937
+ // Gemini CLI stuck-connectivity guard (#128): If the CLI is in a
1938
+ // "Trying to reach <model>" retry loop, it will never process
1939
+ // new messages. Bail out immediately so the caller gets a clear
1940
+ // failure signal and the runtime-exit-monitor can trigger recovery.
1941
+ if (runtimeType === RUNTIME_TYPES.GEMINI_CLI && GEMINI_STUCK_CONNECTIVITY_PATTERN.test(output)) {
1942
+ this.logger.warn('Gemini CLI stuck in connectivity retry loop, aborting message delivery (#128)', {
1943
+ sessionName,
1944
+ attempt,
1945
+ });
1946
+ return false;
1947
+ }
2114
1948
  if (!this.isClaudeAtPrompt(output, runtimeType)) {
2115
1949
  if (attempt === maxAttempts) {
2116
1950
  // On the final attempt, check if the agent is DEFINITELY busy
2117
- // before force-delivering. If we see "esc to interrupt" or
2118
- // processing indicators, the agent is actively working and
2119
- // force-delivery risks corrupting its current task.
2120
- const tailForBusyCheck = output.slice(-2000);
2121
- const isBusy = TERMINAL_PATTERNS.BUSY_STATUS_BAR.test(tailForBusyCheck) ||
2122
- TERMINAL_PATTERNS.PROCESSING_WITH_TEXT.test(tailForBusyCheck);
1951
+ // before force-delivering. Use PTY idle time for robust
1952
+ // cross-runtime detection instead of fragile regex patterns.
1953
+ const idleMs = PtyActivityTrackerService.getInstance().getIdleTimeMs(sessionName);
1954
+ const isBusy = idleMs < SESSION_COMMAND_DELAYS.AGENT_BUSY_IDLE_THRESHOLD_MS;
2123
1955
  if (isBusy) {
2124
1956
  this.logger.warn('Agent is busy (processing indicators detected), skipping force delivery', {
2125
1957
  sessionName,
@@ -2182,20 +2014,49 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
2182
2014
  // for focus cycling and overlay dismissal.
2183
2015
  if (isClaudeCode) {
2184
2016
  if (attempt > 1) {
2017
+ // On retry: Ctrl+C to cancel stale input, then PTY resize to force
2018
+ // TUI re-render (SIGWINCH), then Tab to cycle Ink focus.
2185
2019
  await sessionHelper.sendCtrlC(sessionName);
2186
2020
  await delay(300);
2187
2021
  }
2022
+ // PTY resize on ALL attempts to force SIGWINCH → Ink TUI re-render.
2023
+ // Claude Code's Ink TUI can lose internal input focus after stop hooks
2024
+ // (especially ones that error), state transitions, or idle periods.
2025
+ // When defocused, the `❯` prompt is visible in the terminal buffer
2026
+ // but writes are silently consumed by the framework — NOT routed to
2027
+ // the InputPrompt. Tab alone was insufficient; PTY resize forces a
2028
+ // full TUI re-render that reliably restores focus state.
2029
+ // This matches the manual workaround where pressing a key in the
2030
+ // frontend terminal "wakes up" the input handler.
2031
+ try {
2032
+ const session = sessionHelper.getSession(sessionName);
2033
+ if (session) {
2034
+ session.resize(81, 25);
2035
+ await delay(200);
2036
+ session.resize(80, 24);
2037
+ await delay(300);
2038
+ }
2039
+ }
2040
+ catch { /* non-fatal */ }
2041
+ await sessionHelper.sendKey(sessionName, 'Tab');
2042
+ await delay(300);
2188
2043
  }
2189
2044
  else {
2190
2045
  // Detect recent /compress — Ink TUI loses internal focus after
2191
2046
  // /compress re-renders, causing subsequent messages to be silently
2192
2047
  // dropped even though the prompt `>` is visible (#114).
2193
2048
  // Always force PTY resize on attempt 1 if /compress detected.
2049
+ // Also detect ✖ error state (#130) — MCP connection errors
2050
+ // cause a persistent error indicator that steals TUI focus.
2194
2051
  const recentOutput = sessionHelper.capturePane(sessionName, 40);
2195
2052
  const compressDetected = recentOutput.includes('/compress') ||
2196
2053
  recentOutput.includes('Context compressed') ||
2197
2054
  recentOutput.includes('Compressing context');
2198
- const needsResize = attempt > 1 || compressDetected;
2055
+ // Check for Gemini CLI error indicators in the status bar area (#130).
2056
+ const statusArea = recentOutput.split('\n').slice(-GEMINI_ERROR_STATE_CONSTANTS.STATUS_AREA_LINES).join('\n');
2057
+ const errorStateDetected = recentOutput.includes(GEMINI_ERROR_STATE_CONSTANTS.ERROR_MARKER) ||
2058
+ GEMINI_ERROR_STATE_CONSTANTS.ERROR_COUNT_PATTERN.test(statusArea);
2059
+ const needsResize = attempt > 1 || compressDetected || errorStateDetected;
2199
2060
  // Force a PTY resize to trigger SIGWINCH, making Ink
2200
2061
  // re-render the TUI and potentially restore focus state.
2201
2062
  if (needsResize) {
@@ -2221,19 +2082,39 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
2221
2082
  });
2222
2083
  }
2223
2084
  }
2085
+ // If error state detected (✖), dismiss the error overlay first (#130).
2086
+ // F12 toggles the error details panel in Gemini CLI, Enter dismisses
2087
+ // any overlay/notification, and the combination restores the TUI to a
2088
+ // state where the InputPrompt can accept input.
2089
+ if (errorStateDetected) {
2090
+ this.logger.info('Gemini CLI error state detected (✖), dismissing before delivery (#130)', {
2091
+ sessionName,
2092
+ attempt,
2093
+ });
2094
+ // F12 to close error details panel if open
2095
+ await sessionHelper.sendKey(sessionName, 'F12');
2096
+ await delay(300);
2097
+ // Enter to dismiss any remaining overlay/notification
2098
+ await sessionHelper.sendEnter(sessionName);
2099
+ await delay(500);
2100
+ }
2224
2101
  // Send Tab to cycle Ink focus. In Ink v6, Tab triggers
2225
2102
  // focusNext() in FocusContext, which moves focus to the next
2226
2103
  // focusable component (InputPrompt). This works even when the
2227
2104
  // input is defocused because the Tab handler runs at the Ink
2228
2105
  // framework level, not the component level.
2106
+ // Send two Tabs to cycle through error/notification components
2107
+ // that may be in the focus chain (#130).
2108
+ await sessionHelper.sendKey(sessionName, 'Tab');
2109
+ await delay(200);
2229
2110
  await sessionHelper.sendKey(sessionName, 'Tab');
2230
2111
  await delay(300);
2231
2112
  // Then Enter to dismiss any notification overlay and ensure
2232
2113
  // the input is engaged. Enter on an empty `> ` prompt is a
2233
2114
  // safe no-op (just shows a new blank prompt line).
2234
2115
  await sessionHelper.sendEnter(sessionName);
2235
- // Extra settling time after /compress to let Ink TUI stabilize
2236
- await delay(compressDetected ? 1000 : 500);
2116
+ // Extra settling time after /compress or error state to let Ink TUI stabilize
2117
+ await delay((compressDetected || errorStateDetected) ? 1000 : 500);
2237
2118
  }
2238
2119
  // For Gemini CLI: detect and gently escape interactive modes before
2239
2120
  // sending the message. Avoid Ctrl-C here — Gemini interprets it as
@@ -2266,6 +2147,50 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
2266
2147
  // border redraws that can cause length changes unrelated to delivery.
2267
2148
  const beforeOutput = sessionHelper.capturePane(sessionName, 20);
2268
2149
  const beforeLength = beforeOutput.length;
2150
+ // Deduplication guard (#128): Check if the agent is already
2151
+ // processing on ALL attempts (not just retries). A previous
2152
+ // write may have succeeded but verification failed. Re-writing
2153
+ // the same message creates a duplicate in the input buffer.
2154
+ {
2155
+ const preWriteCheck = sessionHelper.capturePane(sessionName);
2156
+ const hasSpinner = containsSpinnerOrWorkingIndicator(preWriteCheck);
2157
+ if (hasSpinner) {
2158
+ // Hash-based dedup: if the same message was recently sent
2159
+ // and the agent is processing, it's very likely our message.
2160
+ const msgHash = message.substring(0, 200);
2161
+ const lastSent = this.lastSentMessageHash.get(sessionName);
2162
+ const isRecentDuplicate = lastSent
2163
+ && lastSent.hash === msgHash
2164
+ && (Date.now() - lastSent.sentAt) < 60000;
2165
+ if (isRecentDuplicate || attempt > 1) {
2166
+ this.logger.info('Agent already processing — skipping write to prevent duplicate (#128)', {
2167
+ sessionName,
2168
+ attempt,
2169
+ isRecentDuplicate: !!isRecentDuplicate,
2170
+ });
2171
+ return true;
2172
+ }
2173
+ }
2174
+ // On retries: also check if agent is not at prompt AND our
2175
+ // message text is NOT stuck at the bottom.
2176
+ if (attempt > 1) {
2177
+ const notAtPrompt = !this.isClaudeAtPrompt(preWriteCheck, runtimeType);
2178
+ if (notAtPrompt) {
2179
+ const msgSnippet = (message.length > 20
2180
+ ? message.substring(0, 80)
2181
+ : message).replace(/\s+/g, ' ').trim();
2182
+ const bottomLines = preWriteCheck.split('\n').slice(-10).join(' ').replace(/\s+/g, ' ');
2183
+ const textStuck = bottomLines.includes(msgSnippet);
2184
+ if (!textStuck) {
2185
+ this.logger.info('Agent not at prompt and message not stuck — skipping re-write (#128)', {
2186
+ sessionName,
2187
+ attempt,
2188
+ });
2189
+ return true;
2190
+ }
2191
+ }
2192
+ }
2193
+ }
2269
2194
  // Use SessionCommandHelper.sendMessage() — proven two-step write:
2270
2195
  // 1. session.write(message) — triggers bracketed paste
2271
2196
  // 2. await delay(scaled) — waits for paste processing
@@ -2276,6 +2201,11 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
2276
2201
  // If progressive verification below misses an Enter drop, the
2277
2202
  // background scanner will catch it within 30s.
2278
2203
  this.trackSentMessage(sessionName, message);
2204
+ // Track message hash for deduplication on retry (#128)
2205
+ this.lastSentMessageHash.set(sessionName, {
2206
+ hash: message.substring(0, 200),
2207
+ sentAt: Date.now(),
2208
+ });
2279
2209
  // Wait for agent to start processing, then verify delivery.
2280
2210
  // TUI runtimes need a longer delay (3s) for the TUI to redraw
2281
2211
  // and show processing indicators after accepting input.
@@ -2318,7 +2248,7 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
2318
2248
  // definitive proof the agent accepted and is working.
2319
2249
  // Only check spinner/⏺ chars — NOT text words like
2320
2250
  // "thinking" which appear in historical response text.
2321
- if (TERMINAL_PATTERNS.PROCESSING.test(currentOutput)) {
2251
+ if (containsSpinnerOrWorkingIndicator(currentOutput)) {
2322
2252
  this.logger.debug('Processing indicators detected — message accepted', {
2323
2253
  sessionName,
2324
2254
  attempt,
@@ -2342,18 +2272,24 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
2342
2272
  : message).replace(/\s+/g, ' ').trim();
2343
2273
  const promptBottomLines = currentOutput.split('\n').slice(-10).join(' ').replace(/\s+/g, ' ');
2344
2274
  if (promptBottomLines.includes(promptMsgSnippet)) {
2345
- this.logger.warn('At prompt with message text at bottom — pressing Enter', {
2275
+ this.logger.warn('At prompt with message text at bottom — pressing Tab+Enter', {
2346
2276
  sessionName,
2347
2277
  attempt,
2348
2278
  intervalMs,
2349
2279
  });
2280
+ // Tab restores Ink TUI focus before Enter — without this,
2281
+ // Enter may be consumed by the framework but not routed to
2282
+ // the input component if focus was lost during a re-render
2283
+ // (e.g., after stop hooks, state transitions).
2284
+ await sessionHelper.sendKey(sessionName, 'Tab');
2285
+ await delay(200);
2350
2286
  await sessionHelper.sendEnter(sessionName);
2351
2287
  await delay(500);
2352
2288
  await sessionHelper.sendEnter(sessionName); // backup
2353
2289
  await delay(SESSION_COMMAND_DELAYS.MESSAGE_PROCESSING_DELAY);
2354
2290
  // Verify recovery
2355
2291
  const postEnterOutput = sessionHelper.capturePane(sessionName);
2356
- if (TERMINAL_PATTERNS.PROCESSING.test(postEnterOutput) ||
2292
+ if (containsSpinnerOrWorkingIndicator(postEnterOutput) ||
2357
2293
  !this.isClaudeAtPrompt(postEnterOutput, runtimeType)) {
2358
2294
  this.logger.info('Enter recovery from prompt successful', {
2359
2295
  sessionName,
@@ -2387,12 +2323,14 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
2387
2323
  // Message text is at the bottom of the terminal but the
2388
2324
  // prompt is no longer in its idle form — Enter was dropped.
2389
2325
  // Instead of waiting and doing a full Ctrl+C + resend retry,
2390
- // press Enter immediately to submit the already-pasted text.
2391
- this.logger.warn('Message text stuck at bottom — pressing Enter to recover', {
2326
+ // use Tab to restore TUI focus, then Enter to submit.
2327
+ this.logger.warn('Message text stuck at bottom — pressing Tab+Enter to recover', {
2392
2328
  sessionName,
2393
2329
  attempt,
2394
2330
  intervalMs,
2395
2331
  });
2332
+ await sessionHelper.sendKey(sessionName, 'Tab');
2333
+ await delay(200);
2396
2334
  await sessionHelper.sendEnter(sessionName);
2397
2335
  await delay(500);
2398
2336
  await sessionHelper.sendEnter(sessionName); // backup Enter
@@ -2400,7 +2338,7 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
2400
2338
  await delay(SESSION_COMMAND_DELAYS.MESSAGE_PROCESSING_DELAY);
2401
2339
  // Verify recovery: check if processing started
2402
2340
  const recoveryOutput = sessionHelper.capturePane(sessionName);
2403
- if (TERMINAL_PATTERNS.PROCESSING.test(recoveryOutput)) {
2341
+ if (containsSpinnerOrWorkingIndicator(recoveryOutput)) {
2404
2342
  this.logger.info('Enter recovery successful — processing started', {
2405
2343
  sessionName,
2406
2344
  attempt,
@@ -2487,9 +2425,9 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
2487
2425
  .filter((line) => !beforeLines.has(line))
2488
2426
  .join('\n');
2489
2427
  }
2490
- const hasProcessingIndicators = TERMINAL_PATTERNS.PROCESSING_WITH_TEXT.test(newContent || afterOutput.slice(-500));
2428
+ const hasProcessingIndicators = containsProcessingIndicator(newContent || afterOutput.slice(-500));
2491
2429
  const hasGeminiIndicators = newContent.length > 0
2492
- && /reading|thinking|processing|analyzing|generating|searching/i.test(newContent);
2430
+ && containsGeminiProcessingKeywords(newContent);
2493
2431
  const significantLengthChange = Math.abs(lengthDiff) > 10;
2494
2432
  // For Gemini CLI, contentChanged alone is sufficient evidence of
2495
2433
  // delivery. The TUI redraws minimally (lengthDiff can be as low as
@@ -2568,19 +2506,11 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
2568
2506
  }
2569
2507
  }
2570
2508
  }
2571
- // Verification failed, but the message was physically written to the PTY.
2572
- // If the session is still alive, the agent will likely process it — return
2573
- // true to avoid false "Failed to deliver" errors shown to users (#99).
2574
- const backend = getSessionBackendSync();
2575
- const childAlive = backend?.isChildProcessAlive?.(sessionName);
2576
- if (childAlive !== false) {
2577
- this.logger.warn('Message delivery verification inconclusive but session alive — assuming success', {
2578
- sessionName,
2579
- maxAttempts,
2580
- messageLength: message.length,
2581
- });
2582
- return true;
2583
- }
2509
+ this.logger.warn('Message delivery verification failed all attempts exhausted', {
2510
+ sessionName,
2511
+ maxAttempts,
2512
+ messageLength: message.length,
2513
+ });
2584
2514
  this.logger.error('Message delivery failed after all retry attempts', {
2585
2515
  sessionName,
2586
2516
  maxAttempts,
@@ -2608,13 +2538,13 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
2608
2538
  }
2609
2539
  // Extract a search token from the message:
2610
2540
  // Strip [CHAT:uuid] prefix if present, then take the first 40 chars
2611
- const chatPrefixMatch = message.match(/^\[CHAT:[^\]]+\]\s*/);
2612
- const contentAfterPrefix = chatPrefixMatch
2613
- ? message.slice(chatPrefixMatch[0].length)
2541
+ const { prefixLength } = extractChatPrefix(message);
2542
+ const contentAfterPrefix = prefixLength > 0
2543
+ ? message.slice(prefixLength)
2614
2544
  : message;
2615
2545
  const searchToken = contentAfterPrefix.slice(0, 40).trim();
2616
2546
  // Also use [CHAT: as a secondary token if message has a CHAT prefix
2617
- const chatToken = chatPrefixMatch ? '[CHAT:' : null;
2547
+ const chatToken = prefixLength > 0 ? '[CHAT:' : null;
2618
2548
  // Check last 20 non-empty lines for either token.
2619
2549
  // Gemini CLI TUI has status bars at the bottom (branch, sandbox, model info)
2620
2550
  // that push input content further up. 5 lines was insufficient.
@@ -2622,7 +2552,7 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
2622
2552
  const linesToCheck = lines.slice(-20);
2623
2553
  const isStuck = linesToCheck.some((line) => {
2624
2554
  // Strip TUI box-drawing borders before checking (Gemini CLI wraps content in │...│)
2625
- const stripped = line.replace(/^[│┃║|\s]+/, '').replace(/[│┃║|\s]+$/, '');
2555
+ const stripped = stripTuiLineBorders(line);
2626
2556
  if (searchToken && (line.includes(searchToken) || stripped.includes(searchToken)))
2627
2557
  return true;
2628
2558
  if (chatToken && (line.includes(chatToken) || stripped.includes(chatToken)))
@@ -2672,9 +2602,9 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
2672
2602
  return false;
2673
2603
  // Extract search token: first 30 chars of the message content
2674
2604
  // (after stripping any [CHAT:uuid] prefix)
2675
- const chatPrefixMatch = message.match(/^\[CHAT:[^\]]+\]\s*/);
2676
- const contentAfterPrefix = chatPrefixMatch
2677
- ? message.slice(chatPrefixMatch[0].length)
2605
+ const { prefixLength } = extractChatPrefix(message);
2606
+ const contentAfterPrefix = prefixLength > 0
2607
+ ? message.slice(prefixLength)
2678
2608
  : message;
2679
2609
  const searchToken = contentAfterPrefix.slice(0, 30).trim();
2680
2610
  if (!searchToken)
@@ -2684,14 +2614,13 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
2684
2614
  // Or without borders: > text
2685
2615
  // The prompt line is the line with `> ` followed by actual content.
2686
2616
  const lines = output.split('\n');
2687
- const promptLineRegex = /^[│┃║|\s]*>\s+(.+)/;
2688
2617
  for (let i = lines.length - 1; i >= Math.max(0, lines.length - 25); i--) {
2689
2618
  const line = lines[i];
2690
- const match = line.match(promptLineRegex);
2691
- if (match) {
2692
- const promptContent = match[1].replace(/[│┃║|\s]+$/, '').trim();
2619
+ const promptContent = matchTuiPromptLine(line);
2620
+ if (promptContent !== null) {
2621
+ const trimmedContent = stripTuiLineBorders(promptContent).trim();
2693
2622
  // Check if the prompt line content contains our message text
2694
- if (promptContent.length > 5 && promptContent.includes(searchToken)) {
2623
+ if (trimmedContent.length > 5 && trimmedContent.includes(searchToken)) {
2695
2624
  this.logger.warn('Text stuck at TUI prompt — Enter was not pressed', {
2696
2625
  sessionName,
2697
2626
  searchToken: searchToken.slice(0, 20),
@@ -2721,8 +2650,12 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
2721
2650
  */
2722
2651
  async recoverStuckTuiMessage(sessionName, message) {
2723
2652
  const sessionHelper = await this.getSessionHelper();
2724
- // Press Enter to submit the stuck text
2725
- this.logger.info('Pressing Enter to recover stuck TUI message', { sessionName });
2653
+ // Tab restores Ink TUI focus, then Enter to submit the stuck text.
2654
+ // Without Tab, Enter may be consumed by the framework but not routed
2655
+ // to the input component if focus was lost during a re-render.
2656
+ this.logger.info('Pressing Tab+Enter to recover stuck TUI message', { sessionName });
2657
+ await sessionHelper.sendKey(sessionName, 'Tab');
2658
+ await delay(200);
2726
2659
  await sessionHelper.sendEnter(sessionName);
2727
2660
  await delay(500);
2728
2661
  // Double-tap: send a backup Enter in case the first was consumed
@@ -2797,7 +2730,7 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
2797
2730
  for (const sessionName of sessionHelper.listSessions()) {
2798
2731
  try {
2799
2732
  const output = sessionHelper.capturePane(sessionName);
2800
- if (TERMINAL_PATTERNS.REWIND_MODE.test(output)) {
2733
+ if (containsRewindMode(output)) {
2801
2734
  this.logger.warn('Rewind mode detected, sending q to exit', { sessionName });
2802
2735
  sessionHelper.writeRaw(sessionName, 'q');
2803
2736
  await delay(500);
@@ -2820,27 +2753,29 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
2820
2753
  continue;
2821
2754
  // Look for any text sitting on the prompt line
2822
2755
  const lines = output.split('\n');
2823
- const promptLineRegex = /^[│┃║|\s]*>\s+(.+)/;
2824
2756
  for (let i = lines.length - 1; i >= Math.max(0, lines.length - 25); i--) {
2825
- const match = lines[i].match(promptLineRegex);
2826
- if (match) {
2827
- const promptContent = match[1].replace(/[│┃║|\s]+$/, '').trim();
2757
+ const promptContent = matchTuiPromptLine(lines[i]);
2758
+ if (promptContent !== null) {
2759
+ const trimmedContent = stripTuiLineBorders(promptContent).trim();
2828
2760
  // Only act on substantial text (> 10 chars) to avoid false positives
2829
2761
  // from TUI rendering artifacts or short status text
2830
- if (promptContent.length > 10) {
2762
+ if (trimmedContent.length > 10) {
2831
2763
  // Skip known Gemini CLI idle placeholder text that sits at
2832
2764
  // the `> ` prompt when no user input is present. These are
2833
2765
  // NOT stuck messages — they are TUI decoration.
2834
- const isPlaceholder = /^Type your message/i.test(promptContent) ||
2835
- /^@[\w/.]+/.test(promptContent); // e.g., "@path/to/file"
2766
+ const lowerContent = trimmedContent.toLowerCase();
2767
+ const isPlaceholder = lowerContent.startsWith('type your message') ||
2768
+ trimmedContent.startsWith('@'); // e.g., "@path/to/file"
2836
2769
  if (isPlaceholder) {
2837
2770
  break;
2838
2771
  }
2839
- this.logger.warn('Background scan: text stuck at TUI prompt, pressing Enter', {
2772
+ this.logger.warn('Background scan: text stuck at TUI prompt, pressing Tab+Enter', {
2840
2773
  sessionName,
2841
2774
  promptContent: promptContent.slice(0, 80),
2842
2775
  });
2843
- // Press Enter to submit the stuck text
2776
+ // Tab restores Ink TUI focus before Enter
2777
+ await sessionHelper.sendKey(sessionName, 'Tab');
2778
+ await delay(200);
2844
2779
  await sessionHelper.sendEnter(sessionName);
2845
2780
  await delay(500);
2846
2781
  // Backup Enter
@@ -2876,11 +2811,14 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
2876
2811
  if (now - entry.sentAt < MIN_AGE_MS)
2877
2812
  continue;
2878
2813
  if (bottomText.includes(entry.snippet)) {
2879
- this.logger.warn('Background scan: tracked message stuck, pressing Enter', {
2814
+ this.logger.warn('Background scan: tracked message stuck, pressing Tab+Enter', {
2880
2815
  sessionName,
2881
2816
  snippet: entry.snippet.slice(0, 50),
2882
2817
  ageMs: now - entry.sentAt,
2883
2818
  });
2819
+ // Tab restores Ink TUI focus before Enter
2820
+ await sessionHelper.sendKey(sessionName, 'Tab');
2821
+ await delay(200);
2884
2822
  await sessionHelper.sendEnter(sessionName);
2885
2823
  await delay(500);
2886
2824
  await sessionHelper.sendEnter(sessionName); // backup
@@ -2927,8 +2865,8 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
2927
2865
  */
2928
2866
  trackSentMessage(sessionName, message) {
2929
2867
  // Extract a search snippet: skip [CHAT:uuid] prefix, take first 80 chars
2930
- const prefixMatch = message.match(/^\[CHAT:[^\]]+\]\s*/);
2931
- const contentStart = prefixMatch ? prefixMatch[0].length : 0;
2868
+ const { prefixLength } = extractChatPrefix(message);
2869
+ const contentStart = prefixLength;
2932
2870
  // Normalize whitespace: messages may contain \n from enhanced templates.
2933
2871
  // Terminal bottom text is join(' '), so \n in snippet would never match.
2934
2872
  const snippet = message.slice(contentStart, contentStart + 80).replace(/\s+/g, ' ').trim();
@@ -2942,27 +2880,10 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
2942
2880
  // Ensure the background scanner is running
2943
2881
  this.startStuckMessageDetector();
2944
2882
  }
2945
- /**
2946
- * Get the runtime-specific prompt regex pattern.
2947
- * Avoids false positives by using narrow patterns when runtime is known.
2948
- *
2949
- * @param runtimeType - The runtime type (claude-code, gemini-cli, etc.)
2950
- * @returns The appropriate prompt detection regex
2951
- */
2952
- getPromptPatternForRuntime(runtimeType) {
2953
- if (runtimeType === RUNTIME_TYPES.CLAUDE_CODE)
2954
- return TERMINAL_PATTERNS.CLAUDE_CODE_PROMPT;
2955
- if (runtimeType === RUNTIME_TYPES.GEMINI_CLI)
2956
- return TERMINAL_PATTERNS.GEMINI_CLI_PROMPT;
2957
- if (runtimeType === RUNTIME_TYPES.CODEX_CLI)
2958
- return TERMINAL_PATTERNS.CODEX_CLI_PROMPT;
2959
- return TERMINAL_PATTERNS.PROMPT_STREAM;
2960
- }
2961
2883
  /**
2962
2884
  * Check if the agent appears to be at an input prompt.
2963
- * Looks for prompt indicators (❯, ⏵, $, ❯❯, ⏵⏵) in terminal output.
2964
- * Also checks for busy indicators (esc to interrupt, spinners, ⏺)
2965
- * to avoid false negatives when the agent is processing.
2885
+ * Delegates to the regex-free isAgentAtPrompt() from terminal-string-ops,
2886
+ * with additional logging and per-line prompt detection using isPromptLine().
2966
2887
  *
2967
2888
  * @param terminalOutput - The terminal output to check
2968
2889
  * @param runtimeType - The runtime type for pattern selection
@@ -2979,57 +2900,12 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
2979
2900
  // Use 5000 chars to accommodate large tool outputs that push the prompt
2980
2901
  // further back in the buffer (#106).
2981
2902
  const tailSection = terminalOutput.slice(-5000);
2982
- const isGemini = runtimeType === RUNTIME_TYPES.GEMINI_CLI;
2983
- const isClaudeCode = runtimeType === RUNTIME_TYPES.CLAUDE_CODE;
2984
- const isCodex = runtimeType === RUNTIME_TYPES.CODEX_CLI;
2985
- const streamPattern = this.getPromptPatternForRuntime(runtimeType);
2986
2903
  // Check for prompt FIRST. Processing indicators like "thinking" or "analyzing"
2987
2904
  // can appear in the agent's previous response text and persist in the terminal
2988
2905
  // scroll buffer, causing false negatives if checked before the prompt.
2989
- if (streamPattern.test(tailSection)) {
2990
- return true;
2991
- }
2992
- // Fallback: check last several lines for prompt indicators.
2993
- // The prompt may not be on the very last line due to status bars,
2994
- // notifications, or terminal wrapping below the prompt.
2995
2906
  const lines = tailSection.split('\n').filter((line) => line.trim().length > 0);
2996
2907
  const linesToCheck = lines.slice(-10);
2997
- const hasPrompt = linesToCheck.some((line) => {
2998
- const trimmed = line.trim();
2999
- // Strip TUI box-drawing borders that Gemini CLI and other TUI frameworks
3000
- // wrap around prompts. Covers full Unicode box-drawing range (#106).
3001
- const stripped = trimmed
3002
- .replace(/^[\u2500-\u257F|+\-═║╭╮╰╯]+\s*/, '')
3003
- .replace(/\s*[\u2500-\u257F|+\-═║╭╮╰╯]+$/, '');
3004
- // Claude Code prompts: ❯, ⏵, $ alone on a line
3005
- if (!isGemini && !isCodex) {
3006
- if (['❯', '⏵', '$'].some(ch => trimmed === ch || stripped === ch)) {
3007
- return true;
3008
- }
3009
- // ❯❯ = bypass permissions prompt (idle).
3010
- // Matches "❯❯", "❯❯ ", and "❯❯ bypass permissions on (shift+tab to cycle)".
3011
- // Note: ⏵⏵ appears in the status bar but is visible both when idle AND
3012
- // busy, so it cannot be used as a reliable prompt indicator.
3013
- if (trimmed.startsWith('❯❯')) {
3014
- return true;
3015
- }
3016
- }
3017
- // Gemini CLI prompts: > or ! followed by space
3018
- if (!isClaudeCode) {
3019
- if (isCodex) {
3020
- // Codex prompt uses `›`; avoid plain `> ` to prevent false-positives
3021
- // from markdown blockquotes in agent output.
3022
- if (trimmed.startsWith('› ') || stripped.startsWith('› ')) {
3023
- return true;
3024
- }
3025
- }
3026
- else if (trimmed.startsWith('> ') || trimmed.startsWith('! ') ||
3027
- stripped.startsWith('> ') || stripped.startsWith('! ')) {
3028
- return true;
3029
- }
3030
- }
3031
- return false;
3032
- });
2908
+ const hasPrompt = linesToCheck.some(line => isPromptLine(line, runtimeType));
3033
2909
  if (hasPrompt) {
3034
2910
  return true;
3035
2911
  }
@@ -3037,14 +2913,14 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
3037
2913
  // Check last 10 lines (not just 5) because tool output can push processing
3038
2914
  // indicators further up while the status bar stays at the bottom.
3039
2915
  const recentLines = linesToCheck.join('\n');
3040
- if (TERMINAL_PATTERNS.PROCESSING_WITH_TEXT.test(recentLines)) {
2916
+ if (containsProcessingIndicator(recentLines)) {
3041
2917
  this.logger.debug('Processing indicators present near bottom of output');
3042
2918
  return false;
3043
2919
  }
3044
2920
  // Check for "esc to interrupt" in the status bar — this is a definitive
3045
2921
  // busy signal. Claude Code only shows this text while actively processing.
3046
2922
  // It disappears when the agent returns to idle at the prompt.
3047
- if (TERMINAL_PATTERNS.BUSY_STATUS_BAR.test(recentLines)) {
2923
+ if (containsBusyStatusBar(recentLines)) {
3048
2924
  this.logger.debug('Busy status bar detected (esc to interrupt)');
3049
2925
  return false;
3050
2926
  }
@@ -3302,7 +3178,7 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
3302
3178
  return false;
3303
3179
  const currentOutput = sessionHelper.capturePane(sessionName);
3304
3180
  // Processing indicators (spinners) = definitive success
3305
- if (TERMINAL_PATTERNS.PROCESSING.test(currentOutput)) {
3181
+ if (containsSpinnerOrWorkingIndicator(currentOutput)) {
3306
3182
  this.logger.debug('Kickoff delivered — processing indicators detected', {
3307
3183
  sessionName, checkIndex: i,
3308
3184
  });