@ebowwa/coder 0.2.1 → 0.7.64

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 (401) hide show
  1. package/README.md +31 -32
  2. package/dist/core/__tests__/permissions.test.d.ts +12 -0
  3. package/dist/core/__tests__/permissions.test.d.ts.map +1 -0
  4. package/dist/core/__tests__/permissions.test.js +851 -0
  5. package/dist/core/agent-loop/__tests__/compaction.test.d.ts +5 -0
  6. package/dist/core/agent-loop/__tests__/compaction.test.d.ts.map +1 -0
  7. package/dist/core/agent-loop/__tests__/compaction.test.js +209 -0
  8. package/dist/core/agent-loop/__tests__/formatters.test.d.ts +5 -0
  9. package/dist/core/agent-loop/__tests__/formatters.test.d.ts.map +1 -0
  10. package/dist/core/agent-loop/__tests__/formatters.test.js +195 -0
  11. package/dist/core/agent-loop/__tests__/index.test.d.ts +5 -0
  12. package/dist/core/agent-loop/__tests__/index.test.d.ts.map +1 -0
  13. package/dist/core/agent-loop/__tests__/index.test.js +121 -0
  14. package/dist/core/agent-loop/__tests__/loop-state.test.d.ts +5 -0
  15. package/dist/core/agent-loop/__tests__/loop-state.test.d.ts.map +1 -0
  16. package/dist/core/agent-loop/__tests__/loop-state.test.js +340 -0
  17. package/dist/core/agent-loop/__tests__/message-builder.test.d.ts +5 -0
  18. package/dist/core/agent-loop/__tests__/message-builder.test.d.ts.map +1 -0
  19. package/dist/core/agent-loop/__tests__/message-builder.test.js +178 -0
  20. package/dist/core/agent-loop/__tests__/tool-executor.test.d.ts +5 -0
  21. package/dist/core/agent-loop/__tests__/tool-executor.test.d.ts.map +1 -0
  22. package/dist/core/agent-loop/__tests__/tool-executor.test.js +331 -0
  23. package/dist/core/agent-loop/compaction.d.ts +39 -0
  24. package/dist/core/agent-loop/compaction.d.ts.map +1 -0
  25. package/dist/core/agent-loop/compaction.js +51 -0
  26. package/dist/core/agent-loop/formatters.d.ts +21 -0
  27. package/dist/core/agent-loop/formatters.d.ts.map +1 -0
  28. package/dist/core/agent-loop/formatters.js +42 -0
  29. package/dist/core/agent-loop/index.d.ts +25 -0
  30. package/dist/core/agent-loop/index.d.ts.map +1 -0
  31. package/dist/core/agent-loop/index.js +83 -0
  32. package/dist/core/agent-loop/loop-state.d.ts +74 -0
  33. package/dist/core/agent-loop/loop-state.d.ts.map +1 -0
  34. package/dist/core/agent-loop/loop-state.js +147 -0
  35. package/dist/core/agent-loop/message-builder.d.ts +13 -0
  36. package/dist/core/agent-loop/message-builder.d.ts.map +1 -0
  37. package/dist/core/agent-loop/message-builder.js +49 -0
  38. package/dist/core/agent-loop/tool-executor.d.ts +23 -0
  39. package/dist/core/agent-loop/tool-executor.d.ts.map +1 -0
  40. package/dist/core/agent-loop/tool-executor.js +152 -0
  41. package/dist/core/agent-loop/turn-executor.d.ts +57 -0
  42. package/dist/core/agent-loop/turn-executor.d.ts.map +1 -0
  43. package/dist/core/agent-loop/turn-executor.js +124 -0
  44. package/dist/core/agent-loop/types.d.ts +141 -0
  45. package/dist/core/agent-loop/types.d.ts.map +1 -0
  46. package/dist/core/agent-loop/types.js +4 -0
  47. package/dist/core/agent-loop.d.ts +17 -0
  48. package/dist/core/agent-loop.d.ts.map +1 -0
  49. package/dist/core/agent-loop.js +16 -0
  50. package/dist/core/api-client-impl.d.ts +62 -0
  51. package/dist/core/api-client-impl.d.ts.map +1 -0
  52. package/dist/core/api-client-impl.js +479 -0
  53. package/dist/core/api-client.d.ts +6 -0
  54. package/dist/core/api-client.d.ts.map +1 -0
  55. package/dist/core/api-client.js +5 -0
  56. package/dist/core/checkpoints.d.ts +128 -0
  57. package/dist/core/checkpoints.d.ts.map +1 -0
  58. package/dist/core/checkpoints.js +438 -0
  59. package/dist/core/claude-md.d.ts +71 -0
  60. package/dist/core/claude-md.d.ts.map +1 -0
  61. package/dist/core/claude-md.js +198 -0
  62. package/dist/core/cognitive-security/hooks.d.ts +138 -0
  63. package/dist/core/cognitive-security/hooks.d.ts.map +1 -0
  64. package/dist/core/cognitive-security/hooks.js +389 -0
  65. package/dist/core/cognitive-security/index.d.ts +751 -0
  66. package/dist/core/cognitive-security/index.d.ts.map +1 -0
  67. package/dist/core/cognitive-security/index.js +1123 -0
  68. package/dist/core/cognitive-security/middleware.d.ts +136 -0
  69. package/dist/core/cognitive-security/middleware.d.ts.map +1 -0
  70. package/dist/core/cognitive-security/middleware.js +376 -0
  71. package/dist/core/config-loader.d.ts +127 -0
  72. package/dist/core/config-loader.d.ts.map +1 -0
  73. package/dist/core/config-loader.js +219 -0
  74. package/dist/core/context-compaction.d.ts +87 -0
  75. package/dist/core/context-compaction.d.ts.map +1 -0
  76. package/dist/core/context-compaction.js +428 -0
  77. package/dist/core/git-status.d.ts +25 -0
  78. package/dist/core/git-status.d.ts.map +1 -0
  79. package/dist/core/git-status.js +204 -0
  80. package/dist/core/image.d.ts +69 -0
  81. package/dist/core/image.d.ts.map +1 -0
  82. package/dist/core/image.js +290 -0
  83. package/dist/core/image.test.d.ts +2 -0
  84. package/dist/core/image.test.d.ts.map +1 -0
  85. package/dist/core/image.test.js +149 -0
  86. package/dist/core/models.d.ts +123 -0
  87. package/dist/core/models.d.ts.map +1 -0
  88. package/dist/core/models.js +325 -0
  89. package/dist/core/permissions.d.ts +81 -0
  90. package/dist/core/permissions.d.ts.map +1 -0
  91. package/dist/core/permissions.js +327 -0
  92. package/dist/core/retry.d.ts +25 -0
  93. package/dist/core/retry.d.ts.map +1 -0
  94. package/dist/core/retry.js +121 -0
  95. package/dist/core/session-store.d.ts +9 -0
  96. package/dist/core/session-store.d.ts.map +1 -0
  97. package/dist/core/session-store.js +10 -0
  98. package/dist/core/sessions/export.d.ts +47 -0
  99. package/dist/core/sessions/export.d.ts.map +1 -0
  100. package/dist/core/sessions/export.js +256 -0
  101. package/dist/core/sessions/index.d.ts +132 -0
  102. package/dist/core/sessions/index.d.ts.map +1 -0
  103. package/dist/core/sessions/index.js +442 -0
  104. package/dist/core/sessions/metadata.d.ts +77 -0
  105. package/dist/core/sessions/metadata.d.ts.map +1 -0
  106. package/dist/core/sessions/metadata.js +233 -0
  107. package/dist/core/sessions/persistence.d.ts +72 -0
  108. package/dist/core/sessions/persistence.d.ts.map +1 -0
  109. package/dist/core/sessions/persistence.js +201 -0
  110. package/dist/core/sessions/types.d.ts +110 -0
  111. package/dist/core/sessions/types.d.ts.map +1 -0
  112. package/dist/core/sessions/types.js +4 -0
  113. package/dist/core/stream-highlighter.d.ts +18 -0
  114. package/dist/core/stream-highlighter.d.ts.map +1 -0
  115. package/dist/core/stream-highlighter.js +916 -0
  116. package/dist/core/system-reminders.d.ts +89 -0
  117. package/dist/core/system-reminders.d.ts.map +1 -0
  118. package/dist/core/system-reminders.js +285 -0
  119. package/dist/ecosystem/hooks/__tests__/index.test.d.ts +5 -0
  120. package/dist/ecosystem/hooks/__tests__/index.test.d.ts.map +1 -0
  121. package/dist/ecosystem/hooks/__tests__/index.test.js +458 -0
  122. package/dist/ecosystem/hooks/index.d.ts +59 -0
  123. package/dist/ecosystem/hooks/index.d.ts.map +1 -0
  124. package/dist/ecosystem/hooks/index.js +294 -0
  125. package/dist/ecosystem/hooks/prompt-evaluator.d.ts +32 -0
  126. package/dist/ecosystem/hooks/prompt-evaluator.d.ts.map +1 -0
  127. package/dist/ecosystem/hooks/prompt-evaluator.js +229 -0
  128. package/dist/ecosystem/skills/index.d.ts +55 -0
  129. package/dist/ecosystem/skills/index.d.ts.map +1 -0
  130. package/dist/ecosystem/skills/index.js +258 -0
  131. package/dist/ecosystem/tools/__tests__/index.test.d.ts +7 -0
  132. package/dist/ecosystem/tools/__tests__/index.test.d.ts.map +1 -0
  133. package/dist/ecosystem/tools/__tests__/index.test.js +856 -0
  134. package/dist/ecosystem/tools/index.d.ts +24 -0
  135. package/dist/ecosystem/tools/index.d.ts.map +1 -0
  136. package/dist/ecosystem/tools/index.js +1709 -0
  137. package/dist/index.d.ts +24 -0
  138. package/dist/index.d.ts.map +1 -0
  139. package/dist/index.js +32 -2
  140. package/dist/interfaces/mcp/client.d.ts +40 -0
  141. package/dist/interfaces/mcp/client.d.ts.map +1 -0
  142. package/dist/interfaces/mcp/client.js +309 -0
  143. package/dist/interfaces/ui/index.d.ts +36 -0
  144. package/dist/interfaces/ui/index.d.ts.map +1 -0
  145. package/dist/interfaces/ui/index.js +61 -0
  146. package/dist/interfaces/ui/spinner.d.ts +140 -0
  147. package/dist/interfaces/ui/spinner.d.ts.map +1 -0
  148. package/dist/interfaces/ui/spinner.js +342 -0
  149. package/dist/interfaces/ui/terminal/cli/index.d.ts +12 -0
  150. package/dist/interfaces/ui/terminal/cli/index.d.ts.map +1 -0
  151. package/dist/interfaces/ui/terminal/cli/index.js +167 -0
  152. package/dist/interfaces/ui/terminal/shared/args.d.ts +39 -0
  153. package/dist/interfaces/ui/terminal/shared/args.d.ts.map +1 -0
  154. package/dist/interfaces/ui/terminal/shared/args.js +176 -0
  155. package/dist/interfaces/ui/terminal/shared/index.d.ts +11 -0
  156. package/dist/interfaces/ui/terminal/shared/index.d.ts.map +1 -0
  157. package/dist/interfaces/ui/terminal/shared/index.js +16 -0
  158. package/dist/interfaces/ui/terminal/shared/loading-state.d.ts +124 -0
  159. package/dist/interfaces/ui/terminal/shared/loading-state.d.ts.map +1 -0
  160. package/dist/interfaces/ui/terminal/shared/loading-state.js +246 -0
  161. package/dist/interfaces/ui/terminal/shared/query.d.ts +22 -0
  162. package/dist/interfaces/ui/terminal/shared/query.d.ts.map +1 -0
  163. package/dist/interfaces/ui/terminal/shared/query.js +100 -0
  164. package/dist/interfaces/ui/terminal/shared/setup.d.ts +33 -0
  165. package/dist/interfaces/ui/terminal/shared/setup.d.ts.map +1 -0
  166. package/dist/interfaces/ui/terminal/shared/setup.js +226 -0
  167. package/dist/interfaces/ui/terminal/shared/status-line.d.ts +117 -0
  168. package/dist/interfaces/ui/terminal/shared/status-line.d.ts.map +1 -0
  169. package/dist/interfaces/ui/terminal/shared/status-line.js +267 -0
  170. package/dist/interfaces/ui/terminal/shared/system-prompt.d.ts +38 -0
  171. package/dist/interfaces/ui/terminal/shared/system-prompt.d.ts.map +1 -0
  172. package/dist/interfaces/ui/terminal/shared/system-prompt.js +102 -0
  173. package/dist/interfaces/ui/terminal/tui/HelpPanel.d.ts +39 -0
  174. package/dist/interfaces/ui/terminal/tui/HelpPanel.d.ts.map +1 -0
  175. package/dist/interfaces/ui/terminal/tui/HelpPanel.js +215 -0
  176. package/dist/interfaces/ui/terminal/tui/InputContext.d.ts +91 -0
  177. package/dist/interfaces/ui/terminal/tui/InputContext.d.ts.map +1 -0
  178. package/dist/interfaces/ui/terminal/tui/InputContext.js +154 -0
  179. package/dist/interfaces/ui/terminal/tui/InputField.d.ts +18 -0
  180. package/dist/interfaces/ui/terminal/tui/InputField.d.ts.map +1 -0
  181. package/dist/interfaces/ui/terminal/tui/InputField.js +41 -0
  182. package/dist/interfaces/ui/terminal/tui/InteractiveTUI.d.ts +16 -0
  183. package/dist/interfaces/ui/terminal/tui/InteractiveTUI.d.ts.map +1 -0
  184. package/dist/interfaces/ui/terminal/tui/InteractiveTUI.js +451 -0
  185. package/dist/interfaces/ui/terminal/tui/MessageArea.d.ts +10 -0
  186. package/dist/interfaces/ui/terminal/tui/MessageArea.d.ts.map +1 -0
  187. package/dist/interfaces/ui/terminal/tui/MessageArea.js +91 -0
  188. package/dist/interfaces/ui/terminal/tui/MessageStore.d.ts +48 -0
  189. package/dist/interfaces/ui/terminal/tui/MessageStore.d.ts.map +1 -0
  190. package/dist/interfaces/ui/terminal/tui/MessageStore.js +151 -0
  191. package/dist/interfaces/ui/terminal/tui/StatusBar.d.ts +9 -0
  192. package/dist/interfaces/ui/terminal/tui/StatusBar.d.ts.map +1 -0
  193. package/dist/interfaces/ui/terminal/tui/StatusBar.js +36 -0
  194. package/dist/interfaces/ui/terminal/tui/commands.d.ts +21 -0
  195. package/dist/interfaces/ui/terminal/tui/commands.d.ts.map +1 -0
  196. package/dist/interfaces/ui/terminal/tui/commands.js +359 -0
  197. package/dist/interfaces/ui/terminal/tui/components/InteractiveElements.d.ts +115 -0
  198. package/dist/interfaces/ui/terminal/tui/components/InteractiveElements.d.ts.map +1 -0
  199. package/dist/interfaces/ui/terminal/tui/components/InteractiveElements.js +306 -0
  200. package/dist/interfaces/ui/terminal/tui/components/MultilineInput.d.ts +92 -0
  201. package/dist/interfaces/ui/terminal/tui/components/MultilineInput.d.ts.map +1 -0
  202. package/dist/interfaces/ui/terminal/tui/components/MultilineInput.js +399 -0
  203. package/dist/interfaces/ui/terminal/tui/components/PaneManager.d.ts +59 -0
  204. package/dist/interfaces/ui/terminal/tui/components/PaneManager.d.ts.map +1 -0
  205. package/dist/interfaces/ui/terminal/tui/components/PaneManager.js +139 -0
  206. package/dist/interfaces/ui/terminal/tui/components/Sidebar.d.ts +68 -0
  207. package/dist/interfaces/ui/terminal/tui/components/Sidebar.d.ts.map +1 -0
  208. package/dist/interfaces/ui/terminal/tui/components/Sidebar.js +340 -0
  209. package/dist/interfaces/ui/terminal/tui/components/index.d.ts +23 -0
  210. package/dist/interfaces/ui/terminal/tui/components/index.d.ts.map +1 -0
  211. package/dist/interfaces/ui/terminal/tui/components/index.js +51 -0
  212. package/dist/interfaces/ui/terminal/tui/console.d.ts +20 -0
  213. package/dist/interfaces/ui/terminal/tui/console.d.ts.map +1 -0
  214. package/dist/interfaces/ui/terminal/tui/console.js +46 -0
  215. package/dist/interfaces/ui/terminal/tui/index.d.ts +20 -0
  216. package/dist/interfaces/ui/terminal/tui/index.d.ts.map +1 -0
  217. package/dist/interfaces/ui/terminal/tui/index.js +28 -0
  218. package/dist/interfaces/ui/terminal/tui/run.d.ts +13 -0
  219. package/dist/interfaces/ui/terminal/tui/run.d.ts.map +1 -0
  220. package/dist/interfaces/ui/terminal/tui/run.js +31 -0
  221. package/dist/interfaces/ui/terminal/tui/spinner.d.ts +44 -0
  222. package/dist/interfaces/ui/terminal/tui/spinner.d.ts.map +1 -0
  223. package/dist/interfaces/ui/terminal/tui/spinner.js +59 -0
  224. package/dist/interfaces/ui/terminal/tui/tui-app.d.ts +39 -0
  225. package/dist/interfaces/ui/terminal/tui/tui-app.d.ts.map +1 -0
  226. package/dist/interfaces/ui/terminal/tui/tui-app.js +198 -0
  227. package/dist/interfaces/ui/terminal/tui/tui-footer.d.ts +167 -0
  228. package/dist/interfaces/ui/terminal/tui/tui-footer.d.ts.map +1 -0
  229. package/dist/interfaces/ui/terminal/tui/tui-footer.js +330 -0
  230. package/dist/interfaces/ui/terminal/tui/types.d.ts +165 -0
  231. package/dist/interfaces/ui/terminal/tui/types.d.ts.map +1 -0
  232. package/dist/interfaces/ui/terminal/tui/types.js +5 -0
  233. package/dist/interfaces/ui/terminal/tui/useInputHandler.d.ts +23 -0
  234. package/dist/interfaces/ui/terminal/tui/useInputHandler.d.ts.map +1 -0
  235. package/dist/interfaces/ui/terminal/tui/useInputHandler.js +72 -0
  236. package/dist/interfaces/ui/terminal/tui/useNativeInput.d.ts +90 -0
  237. package/dist/interfaces/ui/terminal/tui/useNativeInput.d.ts.map +1 -0
  238. package/dist/interfaces/ui/terminal/tui/useNativeInput.js +188 -0
  239. package/dist/native/index.d.ts +480 -0
  240. package/dist/native/index.d.ts.map +1 -0
  241. package/dist/native/index.js +1625 -0
  242. package/dist/teammates/index.d.ts +161 -0
  243. package/dist/teammates/index.d.ts.map +1 -0
  244. package/dist/teammates/index.js +827 -0
  245. package/dist/types/index.d.ts +482 -0
  246. package/dist/types/index.d.ts.map +1 -0
  247. package/dist/types/index.js +52 -0
  248. package/native/README.md +5 -5
  249. package/native/index.darwin-arm64.node +0 -0
  250. package/native/index.node +0 -0
  251. package/native/package.json +4 -4
  252. package/package.json +33 -16
  253. package/packages/src/core/__tests__/permissions.test.ts +1091 -0
  254. package/packages/src/core/agent-loop/__tests__/compaction.test.ts +280 -0
  255. package/packages/src/core/agent-loop/__tests__/formatters.test.ts +234 -0
  256. package/packages/src/core/agent-loop/__tests__/index.test.ts +162 -0
  257. package/packages/src/core/agent-loop/__tests__/loop-state.test.ts +413 -0
  258. package/packages/src/core/agent-loop/__tests__/message-builder.test.ts +229 -0
  259. package/packages/src/core/agent-loop/__tests__/tool-executor.test.ts +457 -0
  260. package/packages/src/core/agent-loop/compaction.ts +88 -0
  261. package/packages/src/core/agent-loop/formatters.ts +50 -0
  262. package/packages/src/core/agent-loop/index.ts +135 -0
  263. package/packages/src/core/agent-loop/loop-state.ts +187 -0
  264. package/packages/src/core/agent-loop/message-builder.ts +62 -0
  265. package/packages/src/core/agent-loop/tool-executor.ts +211 -0
  266. package/packages/src/core/agent-loop/turn-executor.ts +222 -0
  267. package/packages/src/core/agent-loop/types.ts +148 -0
  268. package/packages/src/core/agent-loop.ts +18 -0
  269. package/packages/src/core/api-client-impl.ts +619 -0
  270. package/packages/src/core/api-client.ts +6 -0
  271. package/packages/src/core/checkpoints.ts +606 -0
  272. package/packages/src/core/claude-md.ts +272 -0
  273. package/packages/src/core/cognitive-security/hooks.ts +590 -0
  274. package/packages/src/core/cognitive-security/index.ts +2041 -0
  275. package/packages/src/core/cognitive-security/middleware.ts +536 -0
  276. package/packages/src/core/config-loader.ts +324 -0
  277. package/packages/src/core/context-compaction.ts +578 -0
  278. package/packages/src/core/git-status.ts +262 -0
  279. package/packages/src/core/image.test.ts +180 -0
  280. package/packages/src/core/image.ts +350 -0
  281. package/packages/src/core/lmdb.db +0 -0
  282. package/packages/src/core/lmdb.db-lock +0 -0
  283. package/packages/src/core/models.ts +430 -0
  284. package/packages/src/core/normalizers/todo +4 -0
  285. package/packages/src/core/permissions.ts +431 -0
  286. package/packages/src/core/retry.ts +170 -0
  287. package/packages/src/core/session-store.ts +36 -0
  288. package/packages/src/core/sessions/export.ts +329 -0
  289. package/packages/src/core/sessions/index.ts +587 -0
  290. package/packages/src/core/sessions/metadata.ts +309 -0
  291. package/packages/src/core/sessions/persistence.ts +244 -0
  292. package/packages/src/core/sessions/types.ts +169 -0
  293. package/packages/src/core/stream-highlighter.ts +1123 -0
  294. package/packages/src/core/system-reminders.ts +402 -0
  295. package/packages/src/core/todo +8 -0
  296. package/packages/src/ecosystem/hooks/__tests__/index.test.ts +561 -0
  297. package/packages/src/ecosystem/hooks/index.ts +341 -0
  298. package/packages/src/ecosystem/hooks/prompt-evaluator.ts +300 -0
  299. package/packages/src/ecosystem/skills/index.ts +295 -0
  300. package/packages/src/ecosystem/tools/__tests__/index.test.ts +1335 -0
  301. package/packages/src/ecosystem/tools/index.ts +1877 -0
  302. package/packages/src/index.ts +120 -0
  303. package/packages/src/interfaces/mcp/client.ts +389 -0
  304. package/packages/src/interfaces/ui/Screenshot 2026-03-02 at 9.23.10/342/200/257PM.png +0 -0
  305. package/packages/src/interfaces/ui/Screenshot 2026-03-03 at 10.55.11/342/200/257AM.png +0 -0
  306. package/packages/src/interfaces/ui/index.ts +161 -0
  307. package/packages/src/interfaces/ui/lmdb.db +0 -0
  308. package/packages/src/interfaces/ui/lmdb.db-lock +0 -0
  309. package/packages/src/interfaces/ui/spinner.ts +451 -0
  310. package/packages/src/interfaces/ui/terminal/cli/index.ts +228 -0
  311. package/packages/src/interfaces/ui/terminal/lmdb.db +0 -0
  312. package/packages/src/interfaces/ui/terminal/lmdb.db-lock +0 -0
  313. package/packages/src/interfaces/ui/terminal/shared/args.ts +222 -0
  314. package/packages/src/interfaces/ui/terminal/shared/index.ts +71 -0
  315. package/packages/src/interfaces/ui/terminal/shared/loading-state.ts +322 -0
  316. package/packages/src/interfaces/ui/terminal/shared/query.ts +146 -0
  317. package/packages/src/interfaces/ui/terminal/shared/setup.ts +295 -0
  318. package/packages/src/interfaces/ui/terminal/shared/status-line.ts +358 -0
  319. package/packages/src/interfaces/ui/terminal/shared/system-prompt.ts +146 -0
  320. package/packages/src/interfaces/ui/terminal/tui/HelpPanel.tsx +262 -0
  321. package/packages/src/interfaces/ui/terminal/tui/InputContext.tsx +232 -0
  322. package/packages/src/interfaces/ui/terminal/tui/InputField.tsx +62 -0
  323. package/packages/src/interfaces/ui/terminal/tui/InteractiveTUI.tsx +537 -0
  324. package/packages/src/interfaces/ui/terminal/tui/MessageArea.tsx +107 -0
  325. package/packages/src/interfaces/ui/terminal/tui/MessageStore.tsx +240 -0
  326. package/packages/src/interfaces/ui/terminal/tui/StatusBar.tsx +54 -0
  327. package/packages/src/interfaces/ui/terminal/tui/commands.ts +438 -0
  328. package/packages/src/interfaces/ui/terminal/tui/components/InteractiveElements.tsx +584 -0
  329. package/packages/src/interfaces/ui/terminal/tui/components/MultilineInput.tsx +614 -0
  330. package/packages/src/interfaces/ui/terminal/tui/components/PaneManager.tsx +333 -0
  331. package/packages/src/interfaces/ui/terminal/tui/components/Sidebar.tsx +604 -0
  332. package/packages/src/interfaces/ui/terminal/tui/components/index.ts +118 -0
  333. package/packages/src/interfaces/ui/terminal/tui/console.ts +49 -0
  334. package/packages/src/interfaces/ui/terminal/tui/index.ts +90 -0
  335. package/packages/src/interfaces/ui/terminal/tui/run.tsx +42 -0
  336. package/packages/src/interfaces/ui/terminal/tui/spinner.ts +69 -0
  337. package/packages/src/interfaces/ui/terminal/tui/tui-app.tsx +390 -0
  338. package/packages/src/interfaces/ui/terminal/tui/tui-footer.ts +422 -0
  339. package/packages/src/interfaces/ui/terminal/tui/types.ts +186 -0
  340. package/packages/src/interfaces/ui/terminal/tui/useInputHandler.ts +104 -0
  341. package/packages/src/interfaces/ui/terminal/tui/useNativeInput.ts +239 -0
  342. package/packages/src/lmdb.db +0 -0
  343. package/packages/src/lmdb.db-lock +0 -0
  344. package/packages/src/native/index.ts +2345 -0
  345. package/packages/src/teammates/index.ts +982 -0
  346. package/packages/src/types/index.ts +722 -0
  347. package/dist/cli.js +0 -148
  348. package/dist/index-0pkak453.js +0 -136
  349. package/dist/index-0qd0x8b4.js +0 -110
  350. package/dist/index-0x3kprq6.js +0 -240
  351. package/dist/index-1eawy937.js +0 -308
  352. package/dist/index-24m2aygy.js +0 -240
  353. package/dist/index-29xcjnne.js +0 -280
  354. package/dist/index-2avyytn5.js +0 -349
  355. package/dist/index-4ms367ey.js +0 -136
  356. package/dist/index-4w2t3b0m.js +0 -240
  357. package/dist/index-4xfgd8nz.js +0 -261
  358. package/dist/index-5acjp9gc.js +0 -157
  359. package/dist/index-5s15hr56.js +0 -136
  360. package/dist/index-6e4wf341.js +0 -349
  361. package/dist/index-6fvnkedw.js +0 -240
  362. package/dist/index-6rqpmd4g.js +0 -128
  363. package/dist/index-77ckwnbm.js +0 -280
  364. package/dist/index-9knxy49k.js +0 -128
  365. package/dist/index-9zrnw4zx.js +0 -128
  366. package/dist/index-bk21w99v.js +0 -280
  367. package/dist/index-c41n76fv.js +0 -240
  368. package/dist/index-cb4ppjdt.js +0 -255
  369. package/dist/index-cfb2edt6.js +0 -240
  370. package/dist/index-cmfa38hh.js +0 -308
  371. package/dist/index-datjz8q1.js +0 -257
  372. package/dist/index-eadf4wvn.js +0 -240
  373. package/dist/index-em5k0m3z.js +0 -345
  374. package/dist/index-gh8r333a.js +0 -110
  375. package/dist/index-gkx6k2tr.js +0 -261
  376. package/dist/index-h5cabfks.js +0 -155
  377. package/dist/index-hcrpwyy3.js +0 -261
  378. package/dist/index-hk7fwwa8.js +0 -257
  379. package/dist/index-jb8cw7f8.js +0 -136
  380. package/dist/index-kbyw4th1.js +0 -347
  381. package/dist/index-kgj5gqnm.js +0 -345
  382. package/dist/index-mdf6xp1z.js +0 -255
  383. package/dist/index-mrhv8kvc.js +0 -280
  384. package/dist/index-mt4743dd.js +0 -161
  385. package/dist/index-qnwsg97q.js +0 -240
  386. package/dist/index-qwdy6x44.js +0 -261
  387. package/dist/index-rmj77261.js +0 -157
  388. package/dist/index-sbbw1a61.js +0 -349
  389. package/dist/index-svy5bcpn.js +0 -345
  390. package/dist/index-tvmy7tm9.js +0 -261
  391. package/dist/index-tzz4vzkj.js +0 -312
  392. package/dist/index-vz80zmhe.js +0 -110
  393. package/dist/index-wed2fk67.js +0 -240
  394. package/dist/index-wksgzz8e.js +0 -280
  395. package/dist/index-wn2m4wma.js +0 -240
  396. package/dist/index-xha05vjc.js +0 -257
  397. package/dist/index-yc6eh8p8.js +0 -136
  398. package/dist/index-ycjxx9ft.js +0 -240
  399. package/dist/index-z0gzd0fc.js +0 -110
  400. package/dist/index-z8cwtf8j.js +0 -240
  401. package/dist/index-zy5mtt00.js +0 -128
@@ -0,0 +1,827 @@
1
+ /**
2
+ * Teammate System - Multi-agent coordination
3
+ *
4
+ * Messaging Architecture:
5
+ * - File-based inbox system for cross-process communication
6
+ * - Messages stored as JSON files in ~/.claude/teams/{team}/inboxes/{teammateId}/
7
+ * - pending/ for unread messages, processed/ for read messages
8
+ */
9
+ import { spawn } from "child_process";
10
+ import { mkdirSync, rmSync, existsSync, readFileSync, readdirSync, renameSync, writeFileSync, statSync } from "fs";
11
+ import { join, basename } from "path";
12
+ // ============================================
13
+ // TEAMMATE MANAGER
14
+ // ============================================
15
+ export class TeammateManager {
16
+ teams = new Map();
17
+ teammates = new Map();
18
+ storagePath;
19
+ constructor(storagePath = "~/.claude/teams") {
20
+ this.storagePath = storagePath.replace("~", process.env.HOME || "");
21
+ // Ensure storage directory exists
22
+ if (!existsSync(this.storagePath)) {
23
+ mkdirSync(this.storagePath, { recursive: true });
24
+ }
25
+ // Load existing teams from disk
26
+ this.loadTeams();
27
+ // Ensure inbox directories exist for all teammates
28
+ this.ensureInboxDirectories();
29
+ }
30
+ // ============================================
31
+ // INBOX PATH HELPERS
32
+ // ============================================
33
+ getInboxPath(teamName, teammateId) {
34
+ return join(this.storagePath, teamName, "inboxes", teammateId);
35
+ }
36
+ getPendingPath(teamName, teammateId) {
37
+ return join(this.getInboxPath(teamName, teammateId), "pending");
38
+ }
39
+ getProcessedPath(teamName, teammateId) {
40
+ return join(this.getInboxPath(teamName, teammateId), "processed");
41
+ }
42
+ ensureInboxDirectories() {
43
+ for (const team of this.teams.values()) {
44
+ for (const teammate of team.teammates) {
45
+ const pendingPath = this.getPendingPath(team.name, teammate.teammateId);
46
+ const processedPath = this.getProcessedPath(team.name, teammate.teammateId);
47
+ if (!existsSync(pendingPath)) {
48
+ mkdirSync(pendingPath, { recursive: true });
49
+ }
50
+ if (!existsSync(processedPath)) {
51
+ mkdirSync(processedPath, { recursive: true });
52
+ }
53
+ }
54
+ }
55
+ }
56
+ generateMessageId() {
57
+ return `msg_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
58
+ }
59
+ // ============================================
60
+ // TEAM MANAGEMENT
61
+ // ============================================
62
+ createTeam(config) {
63
+ const team = {
64
+ ...config,
65
+ status: "active",
66
+ };
67
+ this.teams.set(config.name, team);
68
+ // Store teammates
69
+ for (const teammate of config.teammates) {
70
+ this.teammates.set(teammate.teammateId, teammate);
71
+ }
72
+ // Create inbox directories for all teammates
73
+ for (const teammate of config.teammates) {
74
+ const pendingPath = this.getPendingPath(config.name, teammate.teammateId);
75
+ const processedPath = this.getProcessedPath(config.name, teammate.teammateId);
76
+ if (!existsSync(pendingPath)) {
77
+ mkdirSync(pendingPath, { recursive: true });
78
+ }
79
+ if (!existsSync(processedPath)) {
80
+ mkdirSync(processedPath, { recursive: true });
81
+ }
82
+ }
83
+ // Persist to disk (fire and forget)
84
+ this.persistTeam(team).catch((err) => {
85
+ console.error(`Failed to persist team ${config.name}:`, err);
86
+ });
87
+ return team;
88
+ }
89
+ getTeam(name) {
90
+ return this.teams.get(name);
91
+ }
92
+ listTeams() {
93
+ return Array.from(this.teams.values());
94
+ }
95
+ deleteTeam(name) {
96
+ const team = this.teams.get(name);
97
+ if (team) {
98
+ // Remove teammates and their message queues
99
+ for (const teammate of team.teammates) {
100
+ this.teammates.delete(teammate.teammateId);
101
+ }
102
+ this.teams.delete(name);
103
+ // Delete team directory from disk
104
+ const teamDir = join(this.storagePath, name);
105
+ try {
106
+ rmSync(teamDir, { recursive: true, force: true });
107
+ }
108
+ catch (err) {
109
+ console.error(`Failed to delete team directory ${teamDir}:`, err);
110
+ }
111
+ }
112
+ }
113
+ // ============================================
114
+ // TEAMMATE MANAGEMENT
115
+ // ============================================
116
+ getTeammate(id) {
117
+ return this.teammates.get(id);
118
+ }
119
+ updateTeammateStatus(id, status) {
120
+ const teammate = this.teammates.get(id);
121
+ if (teammate) {
122
+ teammate.status = status;
123
+ }
124
+ }
125
+ /**
126
+ * Add a new teammate to an existing team
127
+ */
128
+ addTeammate(teamName, teammate) {
129
+ const team = this.teams.get(teamName);
130
+ if (!team)
131
+ return false;
132
+ // Add to team
133
+ team.teammates.push(teammate);
134
+ this.teammates.set(teammate.teammateId, teammate);
135
+ // Create inbox directories
136
+ const pendingPath = this.getPendingPath(teamName, teammate.teammateId);
137
+ const processedPath = this.getProcessedPath(teamName, teammate.teammateId);
138
+ if (!existsSync(pendingPath)) {
139
+ mkdirSync(pendingPath, { recursive: true });
140
+ }
141
+ if (!existsSync(processedPath)) {
142
+ mkdirSync(processedPath, { recursive: true });
143
+ }
144
+ // Persist updated team
145
+ this.persistTeam(team).catch((err) => {
146
+ console.error(`Failed to persist team ${teamName}:`, err);
147
+ });
148
+ return true;
149
+ }
150
+ /**
151
+ * Remove a teammate from a team
152
+ */
153
+ removeTeammate(teamName, teammateId) {
154
+ const team = this.teams.get(teamName);
155
+ if (!team)
156
+ return false;
157
+ // Remove from team
158
+ const index = team.teammates.findIndex(t => t.teammateId === teammateId);
159
+ if (index === -1)
160
+ return false;
161
+ team.teammates.splice(index, 1);
162
+ this.teammates.delete(teammateId);
163
+ // Keep inbox directory for history (don't delete)
164
+ // Persist updated team
165
+ this.persistTeam(team).catch((err) => {
166
+ console.error(`Failed to persist team ${teamName}:`, err);
167
+ });
168
+ return true;
169
+ }
170
+ // ============================================
171
+ // SPAWNING
172
+ // ============================================
173
+ async spawnTeammate(teammate, options = {}) {
174
+ const { session, workingDir = process.cwd() } = options;
175
+ // Check if inside tmux
176
+ const insideTmux = !!process.env.TMUX;
177
+ if (!insideTmux) {
178
+ // Spawn in new terminal
179
+ await this.spawnInTerminal(teammate, { session, workingDir });
180
+ }
181
+ else {
182
+ // Spawn in tmux pane
183
+ await this.spawnInTmux(teammate, { session, workingDir });
184
+ }
185
+ this.updateTeammateStatus(teammate.teammateId, "in_progress");
186
+ }
187
+ async spawnInTerminal(teammate, options) {
188
+ // Build claude command
189
+ const args = [
190
+ "bun",
191
+ "run",
192
+ "src/interfaces/ui/terminal/cli/index.ts",
193
+ "--teammate-mode",
194
+ "--agent-id",
195
+ teammate.teammateId,
196
+ "--agent-name",
197
+ teammate.name,
198
+ "--team-name",
199
+ teammate.teamName,
200
+ "--agent-color",
201
+ teammate.color,
202
+ ];
203
+ if (teammate.planModeRequired) {
204
+ args.push("--permission-mode", "plan");
205
+ }
206
+ // Use AppleScript on macOS to open new Terminal
207
+ if (process.platform === "darwin") {
208
+ const script = `
209
+ tell application "Terminal"
210
+ do script "cd ${options.workingDir} && ${args.join(" ")}"
211
+ activate
212
+ end tell
213
+ `;
214
+ spawn("osascript", ["-e", script]);
215
+ }
216
+ else {
217
+ // Linux: use xterm or similar
218
+ spawn("xterm", ["-e", args.join(" ")]);
219
+ }
220
+ }
221
+ async spawnInTmux(teammate, options) {
222
+ const sessionName = options.session || process.env.TMUX?.split(",")[0]?.split(":")[0] || "claude";
223
+ // Create new pane
224
+ await this.tmuxCommand(["split-window", "-t", sessionName, "-c", options.workingDir]);
225
+ // Get pane ID
226
+ const paneId = await this.tmuxCommand(["display-message", "-p", "#{pane_id}"]);
227
+ if (paneId) {
228
+ teammate.paneId = paneId.trim();
229
+ }
230
+ // Send claude command
231
+ const args = [
232
+ "bun",
233
+ "run",
234
+ "src/interfaces/ui/terminal/cli/index.ts",
235
+ "--teammate-mode",
236
+ "--agent-id",
237
+ teammate.teammateId,
238
+ "--agent-name",
239
+ teammate.name,
240
+ "--team-name",
241
+ teammate.teamName,
242
+ ];
243
+ await this.tmuxCommand(["send-keys", "-t", teammate.paneId || "", args.join(" "), "Enter"]);
244
+ }
245
+ async tmuxCommand(args) {
246
+ return new Promise((resolve) => {
247
+ const proc = spawn("tmux", args);
248
+ let output = "";
249
+ proc.stdout?.on("data", (data) => {
250
+ output += data.toString();
251
+ });
252
+ proc.on("close", () => {
253
+ resolve(output);
254
+ });
255
+ });
256
+ }
257
+ // ============================================
258
+ // MESSAGING (FILE-BASED)
259
+ // ============================================
260
+ /**
261
+ * Get the team name for a teammate
262
+ */
263
+ getTeamNameForTeammate(teammateId) {
264
+ const teammate = this.teammates.get(teammateId);
265
+ return teammate?.teamName;
266
+ }
267
+ /**
268
+ * Write a message to a teammate's file-based inbox
269
+ */
270
+ writeMessageToInbox(teamName, toId, msg) {
271
+ const pendingPath = this.getPendingPath(teamName, toId);
272
+ // Ensure inbox exists
273
+ if (!existsSync(pendingPath)) {
274
+ mkdirSync(pendingPath, { recursive: true });
275
+ }
276
+ // Write message as JSON file
277
+ const msgPath = join(pendingPath, `${msg.id}.json`);
278
+ writeFileSync(msgPath, JSON.stringify(msg, null, 2));
279
+ }
280
+ /**
281
+ * Read all pending messages from a teammate's inbox
282
+ */
283
+ readPendingMessages(teamName, teammateId) {
284
+ const pendingPath = this.getPendingPath(teamName, teammateId);
285
+ const messages = [];
286
+ if (!existsSync(pendingPath)) {
287
+ return messages;
288
+ }
289
+ try {
290
+ const files = readdirSync(pendingPath)
291
+ .filter(f => f.endsWith('.json'))
292
+ .sort(); // Oldest first (by filename timestamp)
293
+ for (const file of files) {
294
+ try {
295
+ const msgPath = join(pendingPath, file);
296
+ const content = readFileSync(msgPath, 'utf-8');
297
+ const msg = JSON.parse(content);
298
+ messages.push(msg);
299
+ }
300
+ catch {
301
+ // Skip malformed messages
302
+ }
303
+ }
304
+ }
305
+ catch {
306
+ // Directory read error
307
+ }
308
+ return messages;
309
+ }
310
+ /**
311
+ * Move a message from pending to processed
312
+ */
313
+ markMessageProcessed(teamName, teammateId, msgId) {
314
+ const pendingPath = this.getPendingPath(teamName, teammateId);
315
+ const processedPath = this.getProcessedPath(teamName, teammateId);
316
+ const pendingFile = join(pendingPath, `${msgId}.json`);
317
+ const processedFile = join(processedPath, `${msgId}.json`);
318
+ if (existsSync(pendingFile)) {
319
+ // Ensure processed directory exists
320
+ if (!existsSync(processedPath)) {
321
+ mkdirSync(processedPath, { recursive: true });
322
+ }
323
+ // Update message with readAt timestamp
324
+ try {
325
+ const content = readFileSync(pendingFile, 'utf-8');
326
+ const msg = JSON.parse(content);
327
+ msg.readAt = Date.now();
328
+ writeFileSync(processedFile, JSON.stringify(msg, null, 2));
329
+ rmSync(pendingFile);
330
+ }
331
+ catch {
332
+ // If update fails, just move the file
333
+ try {
334
+ renameSync(pendingFile, processedFile);
335
+ }
336
+ catch {
337
+ // Ignore move errors
338
+ }
339
+ }
340
+ }
341
+ }
342
+ /**
343
+ * Broadcast a message to all teammates in a team
344
+ */
345
+ broadcast(teamName, message, fromId) {
346
+ const team = this.teams.get(teamName);
347
+ if (!team)
348
+ return;
349
+ const baseMsg = {
350
+ type: "broadcast",
351
+ from: fromId || "system",
352
+ content: message,
353
+ timestamp: Date.now(),
354
+ };
355
+ // Write message to each teammate's inbox
356
+ for (const teammate of team.teammates) {
357
+ // Don't send to sender
358
+ if (fromId && teammate.teammateId === fromId)
359
+ continue;
360
+ const msg = {
361
+ ...baseMsg,
362
+ id: this.generateMessageId(),
363
+ teamName,
364
+ createdAt: Date.now(),
365
+ to: teammate.teammateId,
366
+ };
367
+ this.writeMessageToInbox(teamName, teammate.teammateId, msg);
368
+ }
369
+ }
370
+ /**
371
+ * Send a direct message to a specific teammate
372
+ */
373
+ sendDirect(toId, fromId, message) {
374
+ const teamName = this.getTeamNameForTeammate(toId);
375
+ if (!teamName)
376
+ return;
377
+ const msg = {
378
+ id: this.generateMessageId(),
379
+ type: "direct",
380
+ from: fromId,
381
+ to: toId,
382
+ content: message,
383
+ timestamp: Date.now(),
384
+ teamName,
385
+ createdAt: Date.now(),
386
+ };
387
+ this.writeMessageToInbox(teamName, toId, msg);
388
+ }
389
+ /**
390
+ * Inject a message as if it came from the user (for teammate integration)
391
+ * This integrates messages into conversation flow
392
+ */
393
+ injectUserMessageToTeammate(toId, message) {
394
+ const teamName = this.getTeamNameForTeammate(toId);
395
+ if (!teamName)
396
+ return;
397
+ const msg = {
398
+ id: this.generateMessageId(),
399
+ type: "notification", // Use notification type for injected messages
400
+ from: "user",
401
+ to: toId,
402
+ content: message,
403
+ timestamp: Date.now(),
404
+ teamName,
405
+ createdAt: Date.now(),
406
+ };
407
+ this.writeMessageToInbox(teamName, toId, msg);
408
+ }
409
+ /**
410
+ * Retrieve and mark all messages as processed for a teammate
411
+ * Returns messages in chronological order (oldest first)
412
+ */
413
+ getMessages(teammateId) {
414
+ const teamName = this.getTeamNameForTeammate(teammateId);
415
+ if (!teamName)
416
+ return [];
417
+ const storedMsgs = this.readPendingMessages(teamName, teammateId);
418
+ // Mark all as processed
419
+ for (const msg of storedMsgs) {
420
+ this.markMessageProcessed(teamName, teammateId, msg.id);
421
+ }
422
+ // Convert to TeammateMessage format
423
+ return storedMsgs.map(msg => ({
424
+ type: msg.type,
425
+ from: msg.from,
426
+ to: msg.to,
427
+ content: msg.content,
428
+ timestamp: msg.timestamp,
429
+ }));
430
+ }
431
+ /**
432
+ * Check if a teammate has pending messages
433
+ */
434
+ hasMessages(teammateId) {
435
+ const teamName = this.getTeamNameForTeammate(teammateId);
436
+ if (!teamName)
437
+ return false;
438
+ const pendingPath = this.getPendingPath(teamName, teammateId);
439
+ if (!existsSync(pendingPath))
440
+ return false;
441
+ try {
442
+ const files = readdirSync(pendingPath);
443
+ return files.some(f => f.endsWith('.json'));
444
+ }
445
+ catch {
446
+ return false;
447
+ }
448
+ }
449
+ /**
450
+ * Peek at messages without marking them as processed
451
+ */
452
+ peekMessages(teammateId) {
453
+ const teamName = this.getTeamNameForTeammate(teammateId);
454
+ if (!teamName)
455
+ return [];
456
+ const storedMsgs = this.readPendingMessages(teamName, teammateId);
457
+ return storedMsgs.map(msg => ({
458
+ type: msg.type,
459
+ from: msg.from,
460
+ to: msg.to,
461
+ content: msg.content,
462
+ timestamp: msg.timestamp,
463
+ }));
464
+ }
465
+ /**
466
+ * Clear all pending messages for a teammate (move to processed)
467
+ */
468
+ clearMessages(teammateId) {
469
+ const teamName = this.getTeamNameForTeammate(teammateId);
470
+ if (!teamName)
471
+ return;
472
+ const pendingPath = this.getPendingPath(teamName, teammateId);
473
+ if (!existsSync(pendingPath))
474
+ return;
475
+ const storedMsgs = this.readPendingMessages(teamName, teammateId);
476
+ for (const msg of storedMsgs) {
477
+ this.markMessageProcessed(teamName, teammateId, msg.id);
478
+ }
479
+ }
480
+ /**
481
+ * Get count of pending messages for a teammate
482
+ */
483
+ getMessageCount(teammateId) {
484
+ const teamName = this.getTeamNameForTeammate(teammateId);
485
+ if (!teamName)
486
+ return 0;
487
+ const pendingPath = this.getPendingPath(teamName, teammateId);
488
+ if (!existsSync(pendingPath))
489
+ return 0;
490
+ try {
491
+ const files = readdirSync(pendingPath);
492
+ return files.filter(f => f.endsWith('.json')).length;
493
+ }
494
+ catch {
495
+ return 0;
496
+ }
497
+ }
498
+ /**
499
+ * Get processed messages (history) for a teammate
500
+ */
501
+ getProcessedMessages(teammateId, limit = 100) {
502
+ const teamName = this.getTeamNameForTeammate(teammateId);
503
+ if (!teamName)
504
+ return [];
505
+ const processedPath = this.getProcessedPath(teamName, teammateId);
506
+ const messages = [];
507
+ if (!existsSync(processedPath)) {
508
+ return messages;
509
+ }
510
+ try {
511
+ const files = readdirSync(processedPath)
512
+ .filter(f => f.endsWith('.json'))
513
+ .sort()
514
+ .reverse() // Newest first
515
+ .slice(0, limit);
516
+ for (const file of files) {
517
+ try {
518
+ const msgPath = join(processedPath, file);
519
+ const content = readFileSync(msgPath, 'utf-8');
520
+ messages.push(JSON.parse(content));
521
+ }
522
+ catch {
523
+ // Skip malformed
524
+ }
525
+ }
526
+ }
527
+ catch {
528
+ // Directory read error
529
+ }
530
+ return messages;
531
+ }
532
+ /**
533
+ * Clean up old processed messages (older than maxAgeMs)
534
+ */
535
+ cleanupProcessedMessages(teammateId, maxAgeMs = 7 * 24 * 60 * 60 * 1000) {
536
+ const teamName = this.getTeamNameForTeammate(teammateId);
537
+ if (!teamName)
538
+ return 0;
539
+ const processedPath = this.getProcessedPath(teamName, teammateId);
540
+ const cutoff = Date.now() - maxAgeMs;
541
+ let deleted = 0;
542
+ if (!existsSync(processedPath))
543
+ return 0;
544
+ try {
545
+ const files = readdirSync(processedPath).filter(f => f.endsWith('.json'));
546
+ for (const file of files) {
547
+ try {
548
+ const msgPath = join(processedPath, file);
549
+ const content = readFileSync(msgPath, 'utf-8');
550
+ const msg = JSON.parse(content);
551
+ if (msg.readAt && msg.readAt < cutoff) {
552
+ rmSync(msgPath);
553
+ deleted++;
554
+ }
555
+ }
556
+ catch {
557
+ // Skip errors
558
+ }
559
+ }
560
+ }
561
+ catch {
562
+ // Directory read error
563
+ }
564
+ return deleted;
565
+ }
566
+ /**
567
+ * Wait for all teammates in a team to become idle
568
+ * Returns when all teammates have status 'idle', 'completed', or 'failed'
569
+ */
570
+ async waitForTeammatesToBecomeIdle(teamName, options = {}) {
571
+ const { timeout = 60000, pollInterval = 1000 } = options;
572
+ const startTime = Date.now();
573
+ const idleStatuses = ['idle', 'completed', 'failed'];
574
+ while (true) {
575
+ const team = this.teams.get(teamName);
576
+ if (!team) {
577
+ return { success: false, timedOut: false, statuses: {} };
578
+ }
579
+ const statuses = {};
580
+ let allIdle = true;
581
+ for (const teammate of team.teammates) {
582
+ statuses[teammate.teammateId] = teammate.status;
583
+ if (!idleStatuses.includes(teammate.status)) {
584
+ allIdle = false;
585
+ }
586
+ }
587
+ if (allIdle) {
588
+ return { success: true, timedOut: false, statuses };
589
+ }
590
+ // Check timeout
591
+ if (Date.now() - startTime > timeout) {
592
+ return { success: false, timedOut: true, statuses };
593
+ }
594
+ // Wait before polling again
595
+ await new Promise(resolve => setTimeout(resolve, pollInterval));
596
+ }
597
+ }
598
+ /**
599
+ * Get inbox statistics for a teammate
600
+ */
601
+ getInboxStats(teammateId) {
602
+ const teamName = this.getTeamNameForTeammate(teammateId);
603
+ if (!teamName)
604
+ return { pending: 0, processed: 0 };
605
+ const pendingPath = this.getPendingPath(teamName, teammateId);
606
+ const processedPath = this.getProcessedPath(teamName, teammateId);
607
+ let pending = 0;
608
+ let processed = 0;
609
+ let oldestPending;
610
+ let newestPending;
611
+ // Count pending
612
+ if (existsSync(pendingPath)) {
613
+ try {
614
+ const files = readdirSync(pendingPath).filter(f => f.endsWith('.json'));
615
+ pending = files.length;
616
+ for (const file of files) {
617
+ try {
618
+ const msgPath = join(pendingPath, file);
619
+ const content = readFileSync(msgPath, 'utf-8');
620
+ const msg = JSON.parse(content);
621
+ if (!oldestPending || msg.createdAt < oldestPending) {
622
+ oldestPending = msg.createdAt;
623
+ }
624
+ if (!newestPending || msg.createdAt > newestPending) {
625
+ newestPending = msg.createdAt;
626
+ }
627
+ }
628
+ catch {
629
+ // Skip
630
+ }
631
+ }
632
+ }
633
+ catch {
634
+ // Skip
635
+ }
636
+ }
637
+ // Count processed
638
+ if (existsSync(processedPath)) {
639
+ try {
640
+ const files = readdirSync(processedPath).filter(f => f.endsWith('.json'));
641
+ processed = files.length;
642
+ }
643
+ catch {
644
+ // Skip
645
+ }
646
+ }
647
+ return { pending, processed, oldestPending, newestPending };
648
+ }
649
+ // ============================================
650
+ // PERSISTENCE
651
+ // ============================================
652
+ /**
653
+ * Persist a team configuration to disk
654
+ */
655
+ async persistTeam(team) {
656
+ const teamDir = join(this.storagePath, team.name);
657
+ const configPath = join(teamDir, "config.json");
658
+ // Ensure directory exists
659
+ if (!existsSync(teamDir)) {
660
+ mkdirSync(teamDir, { recursive: true });
661
+ }
662
+ // Write .gitkeep to ensure directory is tracked
663
+ await Bun.write(join(teamDir, ".gitkeep"), "");
664
+ // Build config object
665
+ const config = {
666
+ name: team.name,
667
+ description: team.description,
668
+ teammates: team.teammates,
669
+ taskListId: team.taskListId,
670
+ status: team.status,
671
+ coordination: team.coordination,
672
+ updatedAt: Date.now(),
673
+ };
674
+ // Write config as formatted JSON
675
+ await Bun.write(configPath, JSON.stringify(config, null, 2));
676
+ }
677
+ /**
678
+ * Load all teams from disk at startup
679
+ * Uses synchronous operations for constructor compatibility
680
+ */
681
+ loadTeams() {
682
+ // Use Bun's glob to find team configs
683
+ const glob = new Bun.Glob("**/config.json");
684
+ try {
685
+ const files = Array.from(glob.scanSync(this.storagePath));
686
+ for (const file of files) {
687
+ try {
688
+ const filePath = join(this.storagePath, file);
689
+ const content = Bun.file(filePath);
690
+ // Check if file exists and is readable (sync check via size)
691
+ const size = content.size;
692
+ if (size === 0) {
693
+ continue;
694
+ }
695
+ // Read file synchronously using readFileSync
696
+ // Bun.file().text() is async, so we use fs.readFileSync for sync operation
697
+ const text = readFileSync(filePath, "utf-8");
698
+ const config = JSON.parse(text);
699
+ // Validate required fields - skip if missing teammates or name
700
+ if (!config.name || !config.teammates || !Array.isArray(config.teammates)) {
701
+ // Skip configs that don't match our expected structure
702
+ continue;
703
+ }
704
+ const team = {
705
+ name: config.name,
706
+ description: config.description || "",
707
+ teammates: config.teammates,
708
+ taskListId: config.taskListId || "",
709
+ status: config.status || "active",
710
+ coordination: config.coordination || {
711
+ dependencyOrder: [],
712
+ communicationProtocol: "broadcast",
713
+ taskAssignmentStrategy: "manual",
714
+ },
715
+ };
716
+ this.teams.set(team.name, team);
717
+ // Index teammates
718
+ for (const teammate of team.teammates) {
719
+ this.teammates.set(teammate.teammateId, teammate);
720
+ }
721
+ }
722
+ catch (error) {
723
+ // Silently skip malformed configs
724
+ }
725
+ }
726
+ }
727
+ catch (error) {
728
+ // Storage path may not exist yet - that's okay
729
+ if (error.code !== "ENOENT") {
730
+ // Ignore permission errors too
731
+ }
732
+ }
733
+ }
734
+ /**
735
+ * Persist all teams to disk (useful for shutdown)
736
+ */
737
+ async persistAllTeams() {
738
+ const promises = Array.from(this.teams.values()).map((team) => this.persistTeam(team));
739
+ await Promise.all(promises);
740
+ }
741
+ }
742
+ // ============================================
743
+ // TEAMMATE TEMPLATES
744
+ // ============================================
745
+ export const teammateTemplates = {
746
+ /**
747
+ * Architect - Plans and designs
748
+ */
749
+ architect: (teamName) => ({
750
+ name: "architect",
751
+ teamName,
752
+ color: "blue",
753
+ prompt: `You are an architect on the ${teamName} team.
754
+ Your role is to design and plan the technical architecture.
755
+ Focus on:
756
+ - System design and component relationships
757
+ - API contracts and interfaces
758
+ - Data models and schemas
759
+ - Trade-offs and design decisions`,
760
+ planModeRequired: true,
761
+ status: "pending",
762
+ }),
763
+ /**
764
+ * Implementer - Writes code
765
+ */
766
+ implementer: (teamName) => ({
767
+ name: "implementer",
768
+ teamName,
769
+ color: "green",
770
+ prompt: `You are an implementer on the ${teamName} team.
771
+ Your role is to write clean, working code based on the architecture.
772
+ Focus on:
773
+ - Implementing the designed architecture
774
+ - Writing tests
775
+ - Following coding standards
776
+ - Handling edge cases`,
777
+ planModeRequired: false,
778
+ status: "pending",
779
+ }),
780
+ /**
781
+ * Reviewer - Reviews code
782
+ */
783
+ reviewer: (teamName) => ({
784
+ name: "reviewer",
785
+ teamName,
786
+ color: "yellow",
787
+ prompt: `You are a code reviewer on the ${teamName} team.
788
+ Your role is to review code changes and provide feedback.
789
+ Focus on:
790
+ - Code quality and readability
791
+ - Potential bugs and issues
792
+ - Performance considerations
793
+ - Test coverage`,
794
+ planModeRequired: false,
795
+ status: "pending",
796
+ }),
797
+ /**
798
+ * Tester - Tests features
799
+ */
800
+ tester: (teamName) => ({
801
+ name: "tester",
802
+ teamName,
803
+ color: "orange",
804
+ prompt: `You are a tester on the ${teamName} team.
805
+ Your role is to ensure features work correctly.
806
+ Focus on:
807
+ - Writing comprehensive tests
808
+ - Finding edge cases
809
+ - Verifying requirements
810
+ - Reporting bugs`,
811
+ planModeRequired: false,
812
+ status: "pending",
813
+ }),
814
+ };
815
+ // ============================================
816
+ // HELPER FUNCTIONS
817
+ // ============================================
818
+ export function generateTeammateId() {
819
+ return `teammate_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
820
+ }
821
+ export function createTeammate(config) {
822
+ return {
823
+ ...config,
824
+ teammateId: generateTeammateId(),
825
+ status: "pending",
826
+ };
827
+ }