verbolab 0.1.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (493) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +71 -0
  3. package/dist/bin/verbo.d.ts +3 -0
  4. package/dist/bin/verbo.d.ts.map +1 -0
  5. package/dist/bin/verbo.js +1156 -0
  6. package/dist/bin/verbo.js.map +1 -0
  7. package/dist/relay/index.d.ts +2 -0
  8. package/dist/relay/index.d.ts.map +1 -0
  9. package/dist/relay/index.js +15 -0
  10. package/dist/relay/index.js.map +1 -0
  11. package/dist/src/agent/agent-launcher.d.ts +64 -0
  12. package/dist/src/agent/agent-launcher.d.ts.map +1 -0
  13. package/dist/src/agent/agent-launcher.js +326 -0
  14. package/dist/src/agent/agent-launcher.js.map +1 -0
  15. package/dist/src/agent/agent-monitor.d.ts +16 -0
  16. package/dist/src/agent/agent-monitor.d.ts.map +1 -0
  17. package/dist/src/agent/agent-monitor.js +41 -0
  18. package/dist/src/agent/agent-monitor.js.map +1 -0
  19. package/dist/src/agent/fun-names.d.ts +9 -0
  20. package/dist/src/agent/fun-names.d.ts.map +1 -0
  21. package/dist/src/agent/fun-names.js +118 -0
  22. package/dist/src/agent/fun-names.js.map +1 -0
  23. package/dist/src/agent/mcp-shim.d.ts +45 -0
  24. package/dist/src/agent/mcp-shim.d.ts.map +1 -0
  25. package/dist/src/agent/mcp-shim.js +192 -0
  26. package/dist/src/agent/mcp-shim.js.map +1 -0
  27. package/dist/src/agent/personas.d.ts +47 -0
  28. package/dist/src/agent/personas.d.ts.map +1 -0
  29. package/dist/src/agent/personas.js +86 -0
  30. package/dist/src/agent/personas.js.map +1 -0
  31. package/dist/src/agent/provider-detection.d.ts +21 -0
  32. package/dist/src/agent/provider-detection.d.ts.map +1 -0
  33. package/dist/src/agent/provider-detection.js +47 -0
  34. package/dist/src/agent/provider-detection.js.map +1 -0
  35. package/dist/src/agent/providers/claude-provider.d.ts +3 -0
  36. package/dist/src/agent/providers/claude-provider.d.ts.map +1 -0
  37. package/dist/src/agent/providers/claude-provider.js +119 -0
  38. package/dist/src/agent/providers/claude-provider.js.map +1 -0
  39. package/dist/src/agent/providers/gemini-provider.d.ts +13 -0
  40. package/dist/src/agent/providers/gemini-provider.d.ts.map +1 -0
  41. package/dist/src/agent/providers/gemini-provider.js +143 -0
  42. package/dist/src/agent/providers/gemini-provider.js.map +1 -0
  43. package/dist/src/agent/providers/openai-provider.d.ts +3 -0
  44. package/dist/src/agent/providers/openai-provider.d.ts.map +1 -0
  45. package/dist/src/agent/providers/openai-provider.js +127 -0
  46. package/dist/src/agent/providers/openai-provider.js.map +1 -0
  47. package/dist/src/agent/providers/registry.d.ts +19 -0
  48. package/dist/src/agent/providers/registry.d.ts.map +1 -0
  49. package/dist/src/agent/providers/registry.js +30 -0
  50. package/dist/src/agent/providers/registry.js.map +1 -0
  51. package/dist/src/agent/providers/types.d.ts +118 -0
  52. package/dist/src/agent/providers/types.d.ts.map +1 -0
  53. package/dist/src/agent/providers/types.js +2 -0
  54. package/dist/src/agent/providers/types.js.map +1 -0
  55. package/dist/src/approval/approval-server.d.ts +17 -0
  56. package/dist/src/approval/approval-server.d.ts.map +1 -0
  57. package/dist/src/approval/approval-server.js +90 -0
  58. package/dist/src/approval/approval-server.js.map +1 -0
  59. package/dist/src/approval/approval-store.d.ts +29 -0
  60. package/dist/src/approval/approval-store.d.ts.map +1 -0
  61. package/dist/src/approval/approval-store.js +94 -0
  62. package/dist/src/approval/approval-store.js.map +1 -0
  63. package/dist/src/auth/auth-store.d.ts +18 -0
  64. package/dist/src/auth/auth-store.d.ts.map +1 -0
  65. package/dist/src/auth/auth-store.js +34 -0
  66. package/dist/src/auth/auth-store.js.map +1 -0
  67. package/dist/src/auth/device-code-client.d.ts +32 -0
  68. package/dist/src/auth/device-code-client.d.ts.map +1 -0
  69. package/dist/src/auth/device-code-client.js +41 -0
  70. package/dist/src/auth/device-code-client.js.map +1 -0
  71. package/dist/src/auth/plan-enforcer.d.ts +8 -0
  72. package/dist/src/auth/plan-enforcer.d.ts.map +1 -0
  73. package/dist/src/auth/plan-enforcer.js +14 -0
  74. package/dist/src/auth/plan-enforcer.js.map +1 -0
  75. package/dist/src/commands/audit.d.ts +7 -0
  76. package/dist/src/commands/audit.d.ts.map +1 -0
  77. package/dist/src/commands/audit.js +92 -0
  78. package/dist/src/commands/audit.js.map +1 -0
  79. package/dist/src/commands/team.d.ts +48 -0
  80. package/dist/src/commands/team.d.ts.map +1 -0
  81. package/dist/src/commands/team.js +175 -0
  82. package/dist/src/commands/team.js.map +1 -0
  83. package/dist/src/config/verbo-config.d.ts +43 -0
  84. package/dist/src/config/verbo-config.d.ts.map +1 -0
  85. package/dist/src/config/verbo-config.js +111 -0
  86. package/dist/src/config/verbo-config.js.map +1 -0
  87. package/dist/src/core/agent-session-store.d.ts +69 -0
  88. package/dist/src/core/agent-session-store.d.ts.map +1 -0
  89. package/dist/src/core/agent-session-store.js +168 -0
  90. package/dist/src/core/agent-session-store.js.map +1 -0
  91. package/dist/src/core/audit-log-store.d.ts +33 -0
  92. package/dist/src/core/audit-log-store.d.ts.map +1 -0
  93. package/dist/src/core/audit-log-store.js +104 -0
  94. package/dist/src/core/audit-log-store.js.map +1 -0
  95. package/dist/src/core/compliance.d.ts +50 -0
  96. package/dist/src/core/compliance.d.ts.map +1 -0
  97. package/dist/src/core/compliance.js +59 -0
  98. package/dist/src/core/compliance.js.map +1 -0
  99. package/dist/src/core/conflict-detector.d.ts +19 -0
  100. package/dist/src/core/conflict-detector.d.ts.map +1 -0
  101. package/dist/src/core/conflict-detector.js +87 -0
  102. package/dist/src/core/conflict-detector.js.map +1 -0
  103. package/dist/src/core/conflict-enforcer.d.ts +37 -0
  104. package/dist/src/core/conflict-enforcer.d.ts.map +1 -0
  105. package/dist/src/core/conflict-enforcer.js +139 -0
  106. package/dist/src/core/conflict-enforcer.js.map +1 -0
  107. package/dist/src/core/cost-store.d.ts +55 -0
  108. package/dist/src/core/cost-store.d.ts.map +1 -0
  109. package/dist/src/core/cost-store.js +140 -0
  110. package/dist/src/core/cost-store.js.map +1 -0
  111. package/dist/src/core/hot-files.d.ts +19 -0
  112. package/dist/src/core/hot-files.d.ts.map +1 -0
  113. package/dist/src/core/hot-files.js +64 -0
  114. package/dist/src/core/hot-files.js.map +1 -0
  115. package/dist/src/core/human-action-store.d.ts +33 -0
  116. package/dist/src/core/human-action-store.d.ts.map +1 -0
  117. package/dist/src/core/human-action-store.js +92 -0
  118. package/dist/src/core/human-action-store.js.map +1 -0
  119. package/dist/src/core/learning-store.d.ts +32 -0
  120. package/dist/src/core/learning-store.d.ts.map +1 -0
  121. package/dist/src/core/learning-store.js +95 -0
  122. package/dist/src/core/learning-store.js.map +1 -0
  123. package/dist/src/core/merge-queue.d.ts +28 -0
  124. package/dist/src/core/merge-queue.d.ts.map +1 -0
  125. package/dist/src/core/merge-queue.js +92 -0
  126. package/dist/src/core/merge-queue.js.map +1 -0
  127. package/dist/src/core/notification-service.d.ts +13 -0
  128. package/dist/src/core/notification-service.d.ts.map +1 -0
  129. package/dist/src/core/notification-service.js +126 -0
  130. package/dist/src/core/notification-service.js.map +1 -0
  131. package/dist/src/core/notifications.d.ts +10 -0
  132. package/dist/src/core/notifications.d.ts.map +1 -0
  133. package/dist/src/core/notifications.js +33 -0
  134. package/dist/src/core/notifications.js.map +1 -0
  135. package/dist/src/core/orchestrator-store.d.ts +44 -0
  136. package/dist/src/core/orchestrator-store.d.ts.map +1 -0
  137. package/dist/src/core/orchestrator-store.js +69 -0
  138. package/dist/src/core/orchestrator-store.js.map +1 -0
  139. package/dist/src/core/parallelizer.d.ts +47 -0
  140. package/dist/src/core/parallelizer.d.ts.map +1 -0
  141. package/dist/src/core/parallelizer.js +224 -0
  142. package/dist/src/core/parallelizer.js.map +1 -0
  143. package/dist/src/core/pipeline-rollback.d.ts +29 -0
  144. package/dist/src/core/pipeline-rollback.d.ts.map +1 -0
  145. package/dist/src/core/pipeline-rollback.js +84 -0
  146. package/dist/src/core/pipeline-rollback.js.map +1 -0
  147. package/dist/src/core/pipeline-runner.d.ts +73 -0
  148. package/dist/src/core/pipeline-runner.d.ts.map +1 -0
  149. package/dist/src/core/pipeline-runner.js +165 -0
  150. package/dist/src/core/pipeline-runner.js.map +1 -0
  151. package/dist/src/core/pr-creator.d.ts +22 -0
  152. package/dist/src/core/pr-creator.d.ts.map +1 -0
  153. package/dist/src/core/pr-creator.js +55 -0
  154. package/dist/src/core/pr-creator.js.map +1 -0
  155. package/dist/src/core/rbac.d.ts +27 -0
  156. package/dist/src/core/rbac.d.ts.map +1 -0
  157. package/dist/src/core/rbac.js +76 -0
  158. package/dist/src/core/rbac.js.map +1 -0
  159. package/dist/src/core/startup-cleanup.d.ts +47 -0
  160. package/dist/src/core/startup-cleanup.d.ts.map +1 -0
  161. package/dist/src/core/startup-cleanup.js +150 -0
  162. package/dist/src/core/startup-cleanup.js.map +1 -0
  163. package/dist/src/core/task-store.d.ts +96 -0
  164. package/dist/src/core/task-store.d.ts.map +1 -0
  165. package/dist/src/core/task-store.js +309 -0
  166. package/dist/src/core/task-store.js.map +1 -0
  167. package/dist/src/core/verbo-config-editor.d.ts +44 -0
  168. package/dist/src/core/verbo-config-editor.d.ts.map +1 -0
  169. package/dist/src/core/verbo-config-editor.js +204 -0
  170. package/dist/src/core/verbo-config-editor.js.map +1 -0
  171. package/dist/src/core/verbo-config.d.ts +35 -0
  172. package/dist/src/core/verbo-config.d.ts.map +1 -0
  173. package/dist/src/core/verbo-config.js +55 -0
  174. package/dist/src/core/verbo-config.js.map +1 -0
  175. package/dist/src/core/verbo-md.d.ts +96 -0
  176. package/dist/src/core/verbo-md.d.ts.map +1 -0
  177. package/dist/src/core/verbo-md.js +410 -0
  178. package/dist/src/core/verbo-md.js.map +1 -0
  179. package/dist/src/db/database.d.ts +9 -0
  180. package/dist/src/db/database.d.ts.map +1 -0
  181. package/dist/src/db/database.js +37 -0
  182. package/dist/src/db/database.js.map +1 -0
  183. package/dist/src/db/migrations/001-personas-subtasks.d.ts +10 -0
  184. package/dist/src/db/migrations/001-personas-subtasks.d.ts.map +1 -0
  185. package/dist/src/db/migrations/001-personas-subtasks.js +32 -0
  186. package/dist/src/db/migrations/001-personas-subtasks.js.map +1 -0
  187. package/dist/src/db/migrations/002-rbac.d.ts +9 -0
  188. package/dist/src/db/migrations/002-rbac.d.ts.map +1 -0
  189. package/dist/src/db/migrations/002-rbac.js +31 -0
  190. package/dist/src/db/migrations/002-rbac.js.map +1 -0
  191. package/dist/src/db/migrations/003-provider-column.d.ts +8 -0
  192. package/dist/src/db/migrations/003-provider-column.d.ts.map +1 -0
  193. package/dist/src/db/migrations/003-provider-column.js +12 -0
  194. package/dist/src/db/migrations/003-provider-column.js.map +1 -0
  195. package/dist/src/db/migrations/004-pipeline-cost.d.ts +8 -0
  196. package/dist/src/db/migrations/004-pipeline-cost.d.ts.map +1 -0
  197. package/dist/src/db/migrations/004-pipeline-cost.js +23 -0
  198. package/dist/src/db/migrations/004-pipeline-cost.js.map +1 -0
  199. package/dist/src/db/migrations/005-audit-log-timestamp.d.ts +10 -0
  200. package/dist/src/db/migrations/005-audit-log-timestamp.d.ts.map +1 -0
  201. package/dist/src/db/migrations/005-audit-log-timestamp.js +39 -0
  202. package/dist/src/db/migrations/005-audit-log-timestamp.js.map +1 -0
  203. package/dist/src/db/migrations/006-human-action-type.d.ts +9 -0
  204. package/dist/src/db/migrations/006-human-action-type.d.ts.map +1 -0
  205. package/dist/src/db/migrations/006-human-action-type.js +16 -0
  206. package/dist/src/db/migrations/006-human-action-type.js.map +1 -0
  207. package/dist/src/db/schema.d.ts +6 -0
  208. package/dist/src/db/schema.d.ts.map +1 -0
  209. package/dist/src/db/schema.js +255 -0
  210. package/dist/src/db/schema.js.map +1 -0
  211. package/dist/src/deps/dependabot-generator.d.ts +22 -0
  212. package/dist/src/deps/dependabot-generator.d.ts.map +1 -0
  213. package/dist/src/deps/dependabot-generator.js +83 -0
  214. package/dist/src/deps/dependabot-generator.js.map +1 -0
  215. package/dist/src/deps/dependabot-monitor.d.ts +22 -0
  216. package/dist/src/deps/dependabot-monitor.d.ts.map +1 -0
  217. package/dist/src/deps/dependabot-monitor.js +28 -0
  218. package/dist/src/deps/dependabot-monitor.js.map +1 -0
  219. package/dist/src/deps/package-auditor.d.ts +24 -0
  220. package/dist/src/deps/package-auditor.d.ts.map +1 -0
  221. package/dist/src/deps/package-auditor.js +118 -0
  222. package/dist/src/deps/package-auditor.js.map +1 -0
  223. package/dist/src/init/ensure-init.d.ts +6 -0
  224. package/dist/src/init/ensure-init.d.ts.map +1 -0
  225. package/dist/src/init/ensure-init.js +27 -0
  226. package/dist/src/init/ensure-init.js.map +1 -0
  227. package/dist/src/init/project-detector.d.ts +11 -0
  228. package/dist/src/init/project-detector.d.ts.map +1 -0
  229. package/dist/src/init/project-detector.js +117 -0
  230. package/dist/src/init/project-detector.js.map +1 -0
  231. package/dist/src/init/questionnaire.d.ts +5 -0
  232. package/dist/src/init/questionnaire.d.ts.map +1 -0
  233. package/dist/src/init/questionnaire.js +112 -0
  234. package/dist/src/init/questionnaire.js.map +1 -0
  235. package/dist/src/init/template.d.ts +17 -0
  236. package/dist/src/init/template.d.ts.map +1 -0
  237. package/dist/src/init/template.js +46 -0
  238. package/dist/src/init/template.js.map +1 -0
  239. package/dist/src/intelligence/claude-client.d.ts +3 -0
  240. package/dist/src/intelligence/claude-client.d.ts.map +1 -0
  241. package/dist/src/intelligence/claude-client.js +12 -0
  242. package/dist/src/intelligence/claude-client.js.map +1 -0
  243. package/dist/src/intelligence/conflict-mediator.d.ts +17 -0
  244. package/dist/src/intelligence/conflict-mediator.d.ts.map +1 -0
  245. package/dist/src/intelligence/conflict-mediator.js +83 -0
  246. package/dist/src/intelligence/conflict-mediator.js.map +1 -0
  247. package/dist/src/intelligence/github-orchestrator.d.ts +30 -0
  248. package/dist/src/intelligence/github-orchestrator.d.ts.map +1 -0
  249. package/dist/src/intelligence/github-orchestrator.js +270 -0
  250. package/dist/src/intelligence/github-orchestrator.js.map +1 -0
  251. package/dist/src/intelligence/kill-switch.d.ts +10 -0
  252. package/dist/src/intelligence/kill-switch.d.ts.map +1 -0
  253. package/dist/src/intelligence/kill-switch.js +12 -0
  254. package/dist/src/intelligence/kill-switch.js.map +1 -0
  255. package/dist/src/intelligence/learnings-extractor.d.ts +13 -0
  256. package/dist/src/intelligence/learnings-extractor.d.ts.map +1 -0
  257. package/dist/src/intelligence/learnings-extractor.js +74 -0
  258. package/dist/src/intelligence/learnings-extractor.js.map +1 -0
  259. package/dist/src/intelligence/project-scanner.d.ts +2 -0
  260. package/dist/src/intelligence/project-scanner.d.ts.map +1 -0
  261. package/dist/src/intelligence/project-scanner.js +28 -0
  262. package/dist/src/intelligence/project-scanner.js.map +1 -0
  263. package/dist/src/intelligence/task-decomposer.d.ts +14 -0
  264. package/dist/src/intelligence/task-decomposer.d.ts.map +1 -0
  265. package/dist/src/intelligence/task-decomposer.js +97 -0
  266. package/dist/src/intelligence/task-decomposer.js.map +1 -0
  267. package/dist/src/intelligence/types.d.ts +14 -0
  268. package/dist/src/intelligence/types.d.ts.map +1 -0
  269. package/dist/src/intelligence/types.js +2 -0
  270. package/dist/src/intelligence/types.js.map +1 -0
  271. package/dist/src/mcp/server.d.ts +63 -0
  272. package/dist/src/mcp/server.d.ts.map +1 -0
  273. package/dist/src/mcp/server.js +537 -0
  274. package/dist/src/mcp/server.js.map +1 -0
  275. package/dist/src/mcp/stdio-entry.d.ts +2 -0
  276. package/dist/src/mcp/stdio-entry.d.ts.map +1 -0
  277. package/dist/src/mcp/stdio-entry.js +124 -0
  278. package/dist/src/mcp/stdio-entry.js.map +1 -0
  279. package/dist/src/mcp/subtask-handlers.d.ts +7 -0
  280. package/dist/src/mcp/subtask-handlers.d.ts.map +1 -0
  281. package/dist/src/mcp/subtask-handlers.js +50 -0
  282. package/dist/src/mcp/subtask-handlers.js.map +1 -0
  283. package/dist/src/security/network-proxy.d.ts +20 -0
  284. package/dist/src/security/network-proxy.d.ts.map +1 -0
  285. package/dist/src/security/network-proxy.js +125 -0
  286. package/dist/src/security/network-proxy.js.map +1 -0
  287. package/dist/src/security/network-sandbox.d.ts +19 -0
  288. package/dist/src/security/network-sandbox.d.ts.map +1 -0
  289. package/dist/src/security/network-sandbox.js +100 -0
  290. package/dist/src/security/network-sandbox.js.map +1 -0
  291. package/dist/src/security/sanitize.d.ts +13 -0
  292. package/dist/src/security/sanitize.d.ts.map +1 -0
  293. package/dist/src/security/sanitize.js +19 -0
  294. package/dist/src/security/sanitize.js.map +1 -0
  295. package/dist/src/security/secrets-patterns.d.ts +29 -0
  296. package/dist/src/security/secrets-patterns.d.ts.map +1 -0
  297. package/dist/src/security/secrets-patterns.js +430 -0
  298. package/dist/src/security/secrets-patterns.js.map +1 -0
  299. package/dist/src/security/secrets-scanner.d.ts +26 -0
  300. package/dist/src/security/secrets-scanner.d.ts.map +1 -0
  301. package/dist/src/security/secrets-scanner.js +62 -0
  302. package/dist/src/security/secrets-scanner.js.map +1 -0
  303. package/dist/src/skills/classifier.d.ts +9 -0
  304. package/dist/src/skills/classifier.d.ts.map +1 -0
  305. package/dist/src/skills/classifier.js +41 -0
  306. package/dist/src/skills/classifier.js.map +1 -0
  307. package/dist/src/skills/registry.d.ts +16 -0
  308. package/dist/src/skills/registry.d.ts.map +1 -0
  309. package/dist/src/skills/registry.js +61 -0
  310. package/dist/src/skills/registry.js.map +1 -0
  311. package/dist/src/sync/events.d.ts +9 -0
  312. package/dist/src/sync/events.d.ts.map +1 -0
  313. package/dist/src/sync/events.js +2 -0
  314. package/dist/src/sync/events.js.map +1 -0
  315. package/dist/src/sync/relay-server.d.ts +18 -0
  316. package/dist/src/sync/relay-server.d.ts.map +1 -0
  317. package/dist/src/sync/relay-server.js +131 -0
  318. package/dist/src/sync/relay-server.js.map +1 -0
  319. package/dist/src/sync/sync-client.d.ts +31 -0
  320. package/dist/src/sync/sync-client.d.ts.map +1 -0
  321. package/dist/src/sync/sync-client.js +314 -0
  322. package/dist/src/sync/sync-client.js.map +1 -0
  323. package/dist/src/tui/app.d.ts +35 -0
  324. package/dist/src/tui/app.d.ts.map +1 -0
  325. package/dist/src/tui/app.js +676 -0
  326. package/dist/src/tui/app.js.map +1 -0
  327. package/dist/src/tui/components/activity-feed.d.ts +12 -0
  328. package/dist/src/tui/components/activity-feed.d.ts.map +1 -0
  329. package/dist/src/tui/components/activity-feed.js +82 -0
  330. package/dist/src/tui/components/activity-feed.js.map +1 -0
  331. package/dist/src/tui/components/agent-list.d.ts +19 -0
  332. package/dist/src/tui/components/agent-list.d.ts.map +1 -0
  333. package/dist/src/tui/components/agent-list.js +33 -0
  334. package/dist/src/tui/components/agent-list.js.map +1 -0
  335. package/dist/src/tui/components/agent-row.d.ts +12 -0
  336. package/dist/src/tui/components/agent-row.d.ts.map +1 -0
  337. package/dist/src/tui/components/agent-row.js +37 -0
  338. package/dist/src/tui/components/agent-row.js.map +1 -0
  339. package/dist/src/tui/components/approval-terminal.d.ts +13 -0
  340. package/dist/src/tui/components/approval-terminal.d.ts.map +1 -0
  341. package/dist/src/tui/components/approval-terminal.js +34 -0
  342. package/dist/src/tui/components/approval-terminal.js.map +1 -0
  343. package/dist/src/tui/components/audit-viewer.d.ts +16 -0
  344. package/dist/src/tui/components/audit-viewer.d.ts.map +1 -0
  345. package/dist/src/tui/components/audit-viewer.js +46 -0
  346. package/dist/src/tui/components/audit-viewer.js.map +1 -0
  347. package/dist/src/tui/components/auth-gate.d.ts +9 -0
  348. package/dist/src/tui/components/auth-gate.d.ts.map +1 -0
  349. package/dist/src/tui/components/auth-gate.js +112 -0
  350. package/dist/src/tui/components/auth-gate.js.map +1 -0
  351. package/dist/src/tui/components/command-palette.d.ts +12 -0
  352. package/dist/src/tui/components/command-palette.d.ts.map +1 -0
  353. package/dist/src/tui/components/command-palette.js +51 -0
  354. package/dist/src/tui/components/command-palette.js.map +1 -0
  355. package/dist/src/tui/components/compliance-badge.d.ts +11 -0
  356. package/dist/src/tui/components/compliance-badge.d.ts.map +1 -0
  357. package/dist/src/tui/components/compliance-badge.js +12 -0
  358. package/dist/src/tui/components/compliance-badge.js.map +1 -0
  359. package/dist/src/tui/components/decomposition-review.d.ts +10 -0
  360. package/dist/src/tui/components/decomposition-review.d.ts.map +1 -0
  361. package/dist/src/tui/components/decomposition-review.js +19 -0
  362. package/dist/src/tui/components/decomposition-review.js.map +1 -0
  363. package/dist/src/tui/components/dependency-graph.d.ts +13 -0
  364. package/dist/src/tui/components/dependency-graph.d.ts.map +1 -0
  365. package/dist/src/tui/components/dependency-graph.js +143 -0
  366. package/dist/src/tui/components/dependency-graph.js.map +1 -0
  367. package/dist/src/tui/components/diff-viewer.d.ts +11 -0
  368. package/dist/src/tui/components/diff-viewer.d.ts.map +1 -0
  369. package/dist/src/tui/components/diff-viewer.js +82 -0
  370. package/dist/src/tui/components/diff-viewer.js.map +1 -0
  371. package/dist/src/tui/components/edit-task-input.d.ts +10 -0
  372. package/dist/src/tui/components/edit-task-input.d.ts.map +1 -0
  373. package/dist/src/tui/components/edit-task-input.js +20 -0
  374. package/dist/src/tui/components/edit-task-input.js.map +1 -0
  375. package/dist/src/tui/components/footer.d.ts +12 -0
  376. package/dist/src/tui/components/footer.d.ts.map +1 -0
  377. package/dist/src/tui/components/footer.js +41 -0
  378. package/dist/src/tui/components/footer.js.map +1 -0
  379. package/dist/src/tui/components/header.d.ts +8 -0
  380. package/dist/src/tui/components/header.d.ts.map +1 -0
  381. package/dist/src/tui/components/header.js +20 -0
  382. package/dist/src/tui/components/header.js.map +1 -0
  383. package/dist/src/tui/components/human-actions.d.ts +14 -0
  384. package/dist/src/tui/components/human-actions.d.ts.map +1 -0
  385. package/dist/src/tui/components/human-actions.js +43 -0
  386. package/dist/src/tui/components/human-actions.js.map +1 -0
  387. package/dist/src/tui/components/log-panel.d.ts +10 -0
  388. package/dist/src/tui/components/log-panel.d.ts.map +1 -0
  389. package/dist/src/tui/components/log-panel.js +38 -0
  390. package/dist/src/tui/components/log-panel.js.map +1 -0
  391. package/dist/src/tui/components/memory-viewer.d.ts +10 -0
  392. package/dist/src/tui/components/memory-viewer.d.ts.map +1 -0
  393. package/dist/src/tui/components/memory-viewer.js +44 -0
  394. package/dist/src/tui/components/memory-viewer.js.map +1 -0
  395. package/dist/src/tui/components/new-task-input.d.ts +9 -0
  396. package/dist/src/tui/components/new-task-input.d.ts.map +1 -0
  397. package/dist/src/tui/components/new-task-input.js +21 -0
  398. package/dist/src/tui/components/new-task-input.js.map +1 -0
  399. package/dist/src/tui/components/orchestrator-status.d.ts +9 -0
  400. package/dist/src/tui/components/orchestrator-status.d.ts.map +1 -0
  401. package/dist/src/tui/components/orchestrator-status.js +15 -0
  402. package/dist/src/tui/components/orchestrator-status.js.map +1 -0
  403. package/dist/src/tui/components/parallelize-banner.d.ts +8 -0
  404. package/dist/src/tui/components/parallelize-banner.d.ts.map +1 -0
  405. package/dist/src/tui/components/parallelize-banner.js +9 -0
  406. package/dist/src/tui/components/parallelize-banner.js.map +1 -0
  407. package/dist/src/tui/components/progress-bar.d.ts +9 -0
  408. package/dist/src/tui/components/progress-bar.d.ts.map +1 -0
  409. package/dist/src/tui/components/progress-bar.js +15 -0
  410. package/dist/src/tui/components/progress-bar.js.map +1 -0
  411. package/dist/src/tui/components/review-queue.d.ts +13 -0
  412. package/dist/src/tui/components/review-queue.d.ts.map +1 -0
  413. package/dist/src/tui/components/review-queue.js +78 -0
  414. package/dist/src/tui/components/review-queue.js.map +1 -0
  415. package/dist/src/tui/components/rich-header.d.ts +11 -0
  416. package/dist/src/tui/components/rich-header.d.ts.map +1 -0
  417. package/dist/src/tui/components/rich-header.js +25 -0
  418. package/dist/src/tui/components/rich-header.js.map +1 -0
  419. package/dist/src/tui/components/spinner.d.ts +7 -0
  420. package/dist/src/tui/components/spinner.d.ts.map +1 -0
  421. package/dist/src/tui/components/spinner.js +8 -0
  422. package/dist/src/tui/components/spinner.js.map +1 -0
  423. package/dist/src/tui/components/status-bar.d.ts +23 -0
  424. package/dist/src/tui/components/status-bar.d.ts.map +1 -0
  425. package/dist/src/tui/components/status-bar.js +28 -0
  426. package/dist/src/tui/components/status-bar.js.map +1 -0
  427. package/dist/src/tui/components/task-queue.d.ts +11 -0
  428. package/dist/src/tui/components/task-queue.d.ts.map +1 -0
  429. package/dist/src/tui/components/task-queue.js +30 -0
  430. package/dist/src/tui/components/task-queue.js.map +1 -0
  431. package/dist/src/tui/components/team-view.d.ts +13 -0
  432. package/dist/src/tui/components/team-view.d.ts.map +1 -0
  433. package/dist/src/tui/components/team-view.js +12 -0
  434. package/dist/src/tui/components/team-view.js.map +1 -0
  435. package/dist/src/tui/graph-renderer.d.ts +11 -0
  436. package/dist/src/tui/graph-renderer.d.ts.map +1 -0
  437. package/dist/src/tui/graph-renderer.js +296 -0
  438. package/dist/src/tui/graph-renderer.js.map +1 -0
  439. package/dist/src/tui/hooks/use-bell.d.ts +21 -0
  440. package/dist/src/tui/hooks/use-bell.d.ts.map +1 -0
  441. package/dist/src/tui/hooks/use-bell.js +38 -0
  442. package/dist/src/tui/hooks/use-bell.js.map +1 -0
  443. package/dist/src/tui/hooks/use-ci-status.d.ts +16 -0
  444. package/dist/src/tui/hooks/use-ci-status.d.ts.map +1 -0
  445. package/dist/src/tui/hooks/use-ci-status.js +97 -0
  446. package/dist/src/tui/hooks/use-ci-status.js.map +1 -0
  447. package/dist/src/tui/hooks/use-command-palette.d.ts +37 -0
  448. package/dist/src/tui/hooks/use-command-palette.d.ts.map +1 -0
  449. package/dist/src/tui/hooks/use-command-palette.js +108 -0
  450. package/dist/src/tui/hooks/use-command-palette.js.map +1 -0
  451. package/dist/src/tui/hooks/use-diff-view.d.ts +16 -0
  452. package/dist/src/tui/hooks/use-diff-view.d.ts.map +1 -0
  453. package/dist/src/tui/hooks/use-diff-view.js +75 -0
  454. package/dist/src/tui/hooks/use-diff-view.js.map +1 -0
  455. package/dist/src/tui/hooks/use-keyboard.d.ts +3 -0
  456. package/dist/src/tui/hooks/use-keyboard.d.ts.map +1 -0
  457. package/dist/src/tui/hooks/use-keyboard.js +70 -0
  458. package/dist/src/tui/hooks/use-keyboard.js.map +1 -0
  459. package/dist/src/tui/hooks/use-log-stream.d.ts +25 -0
  460. package/dist/src/tui/hooks/use-log-stream.d.ts.map +1 -0
  461. package/dist/src/tui/hooks/use-log-stream.js +83 -0
  462. package/dist/src/tui/hooks/use-log-stream.js.map +1 -0
  463. package/dist/src/tui/hooks/use-spinner.d.ts +3 -0
  464. package/dist/src/tui/hooks/use-spinner.d.ts.map +1 -0
  465. package/dist/src/tui/hooks/use-spinner.js +13 -0
  466. package/dist/src/tui/hooks/use-spinner.js.map +1 -0
  467. package/dist/src/tui/hooks/use-store.d.ts +33 -0
  468. package/dist/src/tui/hooks/use-store.d.ts.map +1 -0
  469. package/dist/src/tui/hooks/use-store.js +21 -0
  470. package/dist/src/tui/hooks/use-store.js.map +1 -0
  471. package/dist/src/tui/lib/diff-parser.d.ts +24 -0
  472. package/dist/src/tui/lib/diff-parser.d.ts.map +1 -0
  473. package/dist/src/tui/lib/diff-parser.js +115 -0
  474. package/dist/src/tui/lib/diff-parser.js.map +1 -0
  475. package/dist/src/tui/lib/palette-commands.d.ts +14 -0
  476. package/dist/src/tui/lib/palette-commands.d.ts.map +1 -0
  477. package/dist/src/tui/lib/palette-commands.js +101 -0
  478. package/dist/src/tui/lib/palette-commands.js.map +1 -0
  479. package/dist/src/tui/tui.d.ts +8 -0
  480. package/dist/src/tui/tui.d.ts.map +1 -0
  481. package/dist/src/tui/tui.js +8 -0
  482. package/dist/src/tui/tui.js.map +1 -0
  483. package/package.json +66 -0
  484. package/skills/api-design.md +84 -0
  485. package/skills/backend-typescript.md +76 -0
  486. package/skills/data-modeling.md +73 -0
  487. package/skills/devops-ci.md +82 -0
  488. package/skills/frontend-design.md +69 -0
  489. package/skills/observability.md +73 -0
  490. package/skills/react-nextjs.md +76 -0
  491. package/skills/refactoring.md +77 -0
  492. package/skills/security.md +75 -0
  493. package/skills/testing.md +69 -0
@@ -0,0 +1,1156 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import { execSync } from 'child_process';
4
+ import fs from 'fs';
5
+ import path from 'path';
6
+ import { fileURLToPath } from 'url';
7
+ import { createDatabase } from '../src/db/database.js';
8
+ import { createTaskStore } from '../src/core/task-store.js';
9
+ import { createAgentSessionStore } from '../src/core/agent-session-store.js';
10
+ import { createConflictDetector } from '../src/core/conflict-detector.js';
11
+ import { createConflictEnforcer } from '../src/core/conflict-enforcer.js';
12
+ import { createParallelizer, hasFileOverlap } from '../src/core/parallelizer.js';
13
+ import { createAgentLauncher } from '../src/agent/agent-launcher.js';
14
+ import { formatFunIdentity } from '../src/agent/fun-names.js';
15
+ import { createApprovalStore } from '../src/approval/approval-store.js';
16
+ import { createApprovalServer } from '../src/approval/approval-server.js';
17
+ import { createHumanActionStore } from '../src/core/human-action-store.js';
18
+ import { createLearningStore } from '../src/core/learning-store.js';
19
+ import { createOrchestratorStore } from '../src/core/orchestrator-store.js';
20
+ import { createGitHubOrchestrator } from '../src/intelligence/github-orchestrator.js';
21
+ import { readBaseBranch, readHotFiles } from '../src/core/verbo-md.js';
22
+ import { createMergeQueue } from '../src/core/merge-queue.js';
23
+ import { createHotFiles } from '../src/core/hot-files.js';
24
+ import { setVerboMdField, getVerboMdFields, validateFieldValue, requiresConfirmation, FIELD_REGISTRY, } from '../src/core/verbo-config-editor.js';
25
+ import { cleanStaleState, pruneAuditLog } from '../src/core/startup-cleanup.js';
26
+ import { registerTeamCommand, bootstrapTeamFromVerboMd } from '../src/commands/team.js';
27
+ import { registerAuditCommand } from '../src/commands/audit.js';
28
+ import { createRbacStore } from '../src/core/rbac.js';
29
+ import { createAuditLogStore } from '../src/core/audit-log-store.js';
30
+ import { createCostStore } from '../src/core/cost-store.js';
31
+ import { createPipelineRunner } from '../src/core/pipeline-runner.js';
32
+ import { createNotifications } from '../src/core/notifications.js';
33
+ import { readCostConfig, readPipelineConfigs, readNotificationConfig } from '../src/core/verbo-md.js';
34
+ import { readSession, clearSession } from '../src/auth/auth-store.js';
35
+ import { checkLimit } from '../src/auth/plan-enforcer.js';
36
+ import { AuthGate } from '../src/tui/components/auth-gate.js';
37
+ import { startTui } from '../src/tui/tui.js';
38
+ import { detectProject } from '../src/init/project-detector.js';
39
+ import { ensureInit } from '../src/init/ensure-init.js';
40
+ import { buildDefaults, runQuestionnaire } from '../src/init/questionnaire.js';
41
+ import { renderVerboMd } from '../src/init/template.js';
42
+ import { createTaskDecomposer } from '../src/intelligence/task-decomposer.js';
43
+ import { isIntelligenceEnabled } from '../src/intelligence/kill-switch.js';
44
+ import { render } from 'ink';
45
+ import React from 'react';
46
+ import { DecompositionReview } from '../src/tui/components/decomposition-review.js';
47
+ // ---- Helpers ----
48
+ const __filename = fileURLToPath(import.meta.url);
49
+ const __dirname = path.dirname(__filename);
50
+ // When installed via npm, points to dist/src/mcp/stdio-entry.js inside the package
51
+ const MCP_SERVER_COMMAND = `node "${path.join(__dirname, '..', 'src', 'mcp', 'stdio-entry.js')}"`;
52
+ async function ensureAuth() {
53
+ const session = readSession();
54
+ if (session)
55
+ return; // cached (may be stale — refresh is background-only for now)
56
+ await new Promise((resolve) => {
57
+ const { unmount } = render(React.createElement(AuthGate, {
58
+ onSuccess: () => {
59
+ unmount();
60
+ resolve();
61
+ },
62
+ }));
63
+ });
64
+ }
65
+ function resolveProjectDir() {
66
+ const opts = program.opts();
67
+ if (opts.project) {
68
+ return path.resolve(opts.project);
69
+ }
70
+ return process.cwd();
71
+ }
72
+ let _allCache = null;
73
+ function _initAll() {
74
+ const projDir = resolveProjectDir();
75
+ const verboDir = path.join(projDir, '.verbo');
76
+ if (!fs.existsSync(verboDir))
77
+ fs.mkdirSync(verboDir, { recursive: true });
78
+ const dbFile = path.join(verboDir, 'verbo.db');
79
+ const db = createDatabase(dbFile);
80
+ const tasks = createTaskStore(db);
81
+ const sessions = createAgentSessionStore(db);
82
+ const detector = createConflictDetector(tasks);
83
+ const hotFileConfig = readHotFiles(projDir);
84
+ const hotFiles = createHotFiles({
85
+ projectDir: projDir,
86
+ configOverrides: hotFileConfig,
87
+ });
88
+ const parallelizer = createParallelizer(tasks, { maxAgents: 5 }, hotFiles);
89
+ const approvals = createApprovalStore(db);
90
+ const humanActions = createHumanActionStore(db);
91
+ const learnings = createLearningStore(db);
92
+ const orchestratorStore = createOrchestratorStore();
93
+ // Initialize cost store and pipeline runner
94
+ const costStore = createCostStore(db);
95
+ const pipelineRunner = createPipelineRunner(tasks);
96
+ // Read budget from VERBO.md cost section (seed pricing on startup)
97
+ const costConfig = readCostConfig(projDir);
98
+ const budgetPerTaskUsd = costConfig.budgetPerTaskUsd;
99
+ const launcher = createAgentLauncher({
100
+ projectDir: projDir,
101
+ mcpServerCommand: MCP_SERVER_COMMAND,
102
+ approvalPort: 5050,
103
+ budgetPerTaskUsd,
104
+ learningStore: learnings,
105
+ });
106
+ return {
107
+ projectDir: projDir, db, tasks, sessions, detector, parallelizer, hotFiles,
108
+ approvals, humanActions, learnings, orchestratorStore, launcher,
109
+ costStore, pipelineRunner, budgetPerTaskUsd,
110
+ };
111
+ }
112
+ function initAll() {
113
+ if (!_allCache)
114
+ _allCache = _initAll();
115
+ return _allCache;
116
+ }
117
+ function taskIcon(status) {
118
+ switch (status) {
119
+ case 'done': return '✓';
120
+ case 'in_progress': return '▸';
121
+ case 'blocked': return '✗';
122
+ default: return '○';
123
+ }
124
+ }
125
+ async function launchAgentForTask(taskId, tasks, sessions, launcher, approvals, projDir, trustLevel = 'medium', enforcer, orchestrator, extras) {
126
+ const task = tasks.get(taskId);
127
+ if (!task) {
128
+ console.error(`Task not found: ${taskId}`);
129
+ return;
130
+ }
131
+ // Guard: don't launch if already in progress — mark immediately to prevent race
132
+ if (task.status === 'in_progress' || task.status === 'done') {
133
+ return;
134
+ }
135
+ tasks.update(taskId, { status: 'in_progress' });
136
+ // Create a session record
137
+ const session = sessions.create({
138
+ taskId: task.id,
139
+ humanId: 'local',
140
+ });
141
+ // Set up log file for capturing agent output
142
+ const logDir = path.join(projDir, '.verbo', 'logs');
143
+ if (!fs.existsSync(logDir))
144
+ fs.mkdirSync(logDir, { recursive: true });
145
+ const logPath = path.join(logDir, `${task.id}.log`);
146
+ const logStream = fs.createWriteStream(logPath, { flags: 'a' });
147
+ logStream.write(`--- Agent launched at ${new Date().toISOString()} ---\n`);
148
+ try {
149
+ const launched = await launcher.launch({
150
+ taskId: task.id,
151
+ title: task.title,
152
+ description: task.description,
153
+ filePaths: task.filePaths,
154
+ trustLevel,
155
+ }, {
156
+ onOutput: (data) => {
157
+ logStream.write(data);
158
+ sessions.heartbeat(session.id);
159
+ },
160
+ onError: (data) => {
161
+ logStream.write(`[stderr] ${data}`);
162
+ },
163
+ onExit: (code) => {
164
+ logStream.write(`\n--- Agent exited with code ${code} at ${new Date().toISOString()} ---\n`);
165
+ logStream.end();
166
+ approvals.deleteBySession(session.id);
167
+ if (code === 0) {
168
+ const completedSession = sessions.get(session.id);
169
+ sessions.complete(session.id, 'Agent exited successfully');
170
+ tasks.update(task.id, { status: 'done' });
171
+ // Notify on task completion
172
+ extras?.notifications?.send('task_complete', task.title).catch(() => { });
173
+ // Advance any active pipeline runs that have this task as their current step
174
+ if (extras?.pipelineRunner && extras.pipelineRunIds) {
175
+ for (const runId of extras.pipelineRunIds) {
176
+ try {
177
+ extras.pipelineRunner.advance(runId);
178
+ }
179
+ catch {
180
+ // Non-fatal: pipeline advance failures shouldn't block task completion
181
+ }
182
+ }
183
+ }
184
+ // Review diff, push branch, and open PR via the GitHub orchestrator
185
+ if (orchestrator) {
186
+ const baseBranch = readBaseBranch(projDir);
187
+ const worktreeBranch = completedSession?.worktreeBranch ?? `verbo/${task.id}`;
188
+ const worktreePath = completedSession?.worktreePath ?? launcher.getWorktreePath(task.id);
189
+ orchestrator
190
+ .reviewAndPush({
191
+ taskId: task.id,
192
+ taskTitle: task.title,
193
+ summary: completedSession?.completionSummary ?? 'Task completed by Verbo agent',
194
+ branch: worktreeBranch,
195
+ baseBranch,
196
+ worktreePath,
197
+ })
198
+ .then((result) => {
199
+ if (result.prUrl) {
200
+ tasks.update(task.id, { prUrl: result.prUrl });
201
+ }
202
+ })
203
+ .catch(() => {
204
+ // Failures surface via human_actions (blocking review) or are non-critical
205
+ });
206
+ }
207
+ // Cleanup worktree after successful completion
208
+ launcher.cleanupWorktree(task.id).catch(() => { });
209
+ // Auto-relaunch tasks that were paused due to conflict with this task
210
+ if (enforcer) {
211
+ const toRelaunch = enforcer.checkRelaunch(task.id);
212
+ for (const relaunchTaskId of toRelaunch) {
213
+ launchAgentForTask(relaunchTaskId, tasks, sessions, launcher, approvals, projDir, trustLevel, enforcer, orchestrator, extras).catch((err) => {
214
+ console.error(`Failed to auto-relaunch task ${relaunchTaskId}:`, err.message);
215
+ });
216
+ }
217
+ }
218
+ }
219
+ else {
220
+ sessions.error(session.id);
221
+ tasks.unclaim(task.id);
222
+ // Cleanup worktree on failure too
223
+ launcher.cleanupWorktree(task.id).catch(() => { });
224
+ // Advance pipeline runs on failure too (step will be marked failed, on_failure applied)
225
+ if (extras?.pipelineRunner && extras.pipelineRunIds) {
226
+ for (const runId of extras.pipelineRunIds) {
227
+ try {
228
+ extras.pipelineRunner.advance(runId);
229
+ }
230
+ catch {
231
+ // Non-fatal
232
+ }
233
+ }
234
+ }
235
+ }
236
+ // Emit bell / notifications — notifications.send() includes the bell
237
+ if (!extras?.notifications) {
238
+ process.stderr.write('\x07');
239
+ }
240
+ },
241
+ });
242
+ // Store pid, worktree info, and fun name on the session
243
+ sessions.update(session.id, {
244
+ pid: launched.pid,
245
+ worktreePath: launched.worktreePath,
246
+ worktreeBranch: launched.worktreeBranch,
247
+ status: 'active',
248
+ funName: formatFunIdentity(launched.funIdentity),
249
+ });
250
+ // Set agentSessionId on the task so MCP claim_task can reuse it
251
+ tasks.update(task.id, {
252
+ agentSessionId: session.id,
253
+ });
254
+ }
255
+ catch (err) {
256
+ sessions.error(session.id);
257
+ throw err;
258
+ }
259
+ }
260
+ // ---- Program ----
261
+ const program = new Command();
262
+ program
263
+ .name('verbo')
264
+ .description('Orchestrate multiple Claude Code agents across your team')
265
+ .version('0.1.0')
266
+ .option('--project <path>', 'Target project directory (defaults to cwd)');
267
+ // ---- Auth gate: enforce authentication on all commands except login/logout/init ----
268
+ const AUTH_EXEMPT_COMMANDS = new Set(['login', 'logout', 'init']);
269
+ program.hook('preAction', async (_thisCommand, actionCommand) => {
270
+ if (!AUTH_EXEMPT_COMMANDS.has(actionCommand.name())) {
271
+ await ensureAuth();
272
+ }
273
+ });
274
+ // ---- verbo add <title> ----
275
+ program
276
+ .command('add <title>')
277
+ .description('Add a new task')
278
+ .option('-p, --priority <level>', 'Task priority (p0, p1, p2, p3)', 'p2')
279
+ .option('-d, --description <text>', 'Task description')
280
+ .option('-f, --files <paths...>', 'Relevant file paths')
281
+ .action(async (title, opts) => {
282
+ const { tasks } = initAll();
283
+ const task = tasks.create({
284
+ title,
285
+ priority: opts.priority,
286
+ description: opts.description,
287
+ filePaths: opts.files ?? [],
288
+ });
289
+ console.log(`Created task ${task.id}: ${task.title} [${task.priority}]`);
290
+ // Offer decomposition if description has >= 50 words
291
+ const descriptionText = opts.description ?? '';
292
+ const wordCount = descriptionText.trim().split(/\s+/).filter(Boolean).length;
293
+ if (wordCount >= 50) {
294
+ const decomposer = createTaskDecomposer(tasks);
295
+ console.log('Long description detected — generating decomposition…');
296
+ const subtasks = await decomposer.decompose(descriptionText);
297
+ if (subtasks && subtasks.length > 0) {
298
+ await runDecomposeReview(subtasks, decomposer, task.id);
299
+ }
300
+ }
301
+ });
302
+ // ---- Decompose review helper (used by CLI commands) ----
303
+ async function runDecomposeReview(subtasks, decomposer, parentTaskId) {
304
+ return new Promise((resolve) => {
305
+ const { unmount } = render(React.createElement(DecompositionReview, {
306
+ subtasks,
307
+ onConfirm: async () => {
308
+ unmount();
309
+ const created = await decomposer.confirm(subtasks, parentTaskId);
310
+ console.log(`\nCreated ${created.length} subtask${created.length !== 1 ? 's' : ''}:`);
311
+ for (const t of created) {
312
+ console.log(` ○ [${t.priority}] ${t.title} (${t.id.slice(0, 8)})`);
313
+ }
314
+ resolve();
315
+ },
316
+ onCancel: () => {
317
+ unmount();
318
+ console.log('Decomposition cancelled.');
319
+ resolve();
320
+ },
321
+ }));
322
+ });
323
+ }
324
+ // ---- verbo decompose <taskId> ----
325
+ program
326
+ .command('decompose <taskId>')
327
+ .description('Decompose a task into subtasks using AI')
328
+ .action(async (taskId) => {
329
+ const { tasks } = initAll();
330
+ const task = tasks.get(taskId);
331
+ if (!task) {
332
+ console.error(`Task not found: ${taskId}`);
333
+ process.exit(1);
334
+ }
335
+ const input = [task.title, task.description].filter(Boolean).join('\n\n');
336
+ const decomposer = createTaskDecomposer(tasks);
337
+ console.log(`Decomposing task: ${task.title}`);
338
+ const subtasks = await decomposer.decompose(input);
339
+ if (!subtasks || subtasks.length === 0) {
340
+ const wordCount = input.trim().split(/\s+/).filter(Boolean).length;
341
+ if (wordCount < 50) {
342
+ console.log('Task description too short for decomposition (need ≥50 words).');
343
+ }
344
+ else if (!process.env.ANTHROPIC_API_KEY) {
345
+ console.log('No ANTHROPIC_API_KEY set — cannot decompose.');
346
+ }
347
+ else {
348
+ console.log('Could not decompose task.');
349
+ }
350
+ return;
351
+ }
352
+ await runDecomposeReview(subtasks, decomposer, task.id);
353
+ });
354
+ // ---- verbo list ----
355
+ program
356
+ .command('list')
357
+ .description('List tasks')
358
+ .option('-s, --status <status>', 'Filter by status (todo, in_progress, done, blocked)')
359
+ .action((opts) => {
360
+ const { tasks } = initAll();
361
+ const filter = opts.status
362
+ ? { status: opts.status }
363
+ : undefined;
364
+ const list = tasks.list(filter);
365
+ if (list.length === 0) {
366
+ console.log('No tasks found.');
367
+ return;
368
+ }
369
+ for (const task of list) {
370
+ const icon = taskIcon(task.status);
371
+ const shortId = task.id.slice(0, 8);
372
+ console.log(`${icon} [${task.priority}] ${task.title} (${shortId})`);
373
+ }
374
+ });
375
+ // ---- verbo launch <taskId> ----
376
+ program
377
+ .command('launch <taskId>')
378
+ .description('Launch agent on a specific task')
379
+ .option('--trust <level>', 'Trust level: low, medium, high (default: medium)', 'medium')
380
+ .action(async (taskId, opts) => {
381
+ const trust = opts.trust;
382
+ if (!['low', 'medium', 'high'].includes(trust)) {
383
+ console.error(`Invalid trust level: ${opts.trust}. Use low, medium, or high.`);
384
+ process.exit(1);
385
+ }
386
+ const { tasks, sessions, launcher, approvals, projectDir } = initAll();
387
+ try {
388
+ await launchAgentForTask(taskId, tasks, sessions, launcher, approvals, projectDir, trust);
389
+ }
390
+ catch (err) {
391
+ console.error('Failed to launch agent:', err.message);
392
+ process.exit(1);
393
+ }
394
+ });
395
+ // ---- verbo parallel ----
396
+ program
397
+ .command('parallel')
398
+ .description('Show and launch safe parallel set of tasks')
399
+ .action(async () => {
400
+ const { tasks, sessions, parallelizer, launcher, approvals, projectDir } = initAll();
401
+ const batch = parallelizer.findSafeBatch();
402
+ if (batch.length === 0) {
403
+ console.log('No parallelizable tasks found.');
404
+ return;
405
+ }
406
+ console.log(`Found ${batch.length} tasks to run in parallel:`);
407
+ for (const task of batch) {
408
+ console.log(` ${taskIcon(task.status)} [${task.priority}] ${task.title} (${task.id.slice(0, 8)})`);
409
+ }
410
+ console.log('');
411
+ for (const task of batch) {
412
+ try {
413
+ await launchAgentForTask(task.id, tasks, sessions, launcher, approvals, projectDir);
414
+ }
415
+ catch (err) {
416
+ console.error(`Failed to launch agent for task ${task.id}:`, err.message);
417
+ }
418
+ }
419
+ });
420
+ // ---- verbo status ----
421
+ program
422
+ .command('status')
423
+ .description('One-line summary of current state')
424
+ .action(() => {
425
+ const { tasks, sessions } = initAll();
426
+ const activeSessions = sessions.listActive();
427
+ const allTasks = tasks.list();
428
+ const readyTasks = allTasks.filter((t) => t.status === 'todo');
429
+ console.log(`${activeSessions.length} agents running, ${readyTasks.length} tasks ready, ${allTasks.length} total`);
430
+ });
431
+ // ---- verbo team (list, invite, role, log) ----
432
+ registerTeamCommand(program, () => {
433
+ const { db } = initAll();
434
+ const raw = db.raw();
435
+ const rbacStore = createRbacStore(raw);
436
+ const auditLog = createAuditLogStore(db);
437
+ return { db: raw, rbacStore, auditLog };
438
+ });
439
+ // ---- verbo audit (list, export) ----
440
+ registerAuditCommand(program, () => {
441
+ const { db } = initAll();
442
+ const auditLog = createAuditLogStore(db);
443
+ return { auditLog };
444
+ });
445
+ // ---- verbo kill <agentNumber> ----
446
+ program
447
+ .command('kill <agentNumber>')
448
+ .description('Kill agent by number (1-indexed)')
449
+ .action((agentNumberStr) => {
450
+ const agentNumber = parseInt(agentNumberStr, 10);
451
+ if (isNaN(agentNumber) || agentNumber < 1) {
452
+ console.error('Agent number must be a positive integer.');
453
+ process.exit(1);
454
+ }
455
+ const { sessions, launcher, approvals } = initAll();
456
+ const activeSessions = sessions.listActive();
457
+ if (activeSessions.length === 0) {
458
+ console.log('No active sessions.');
459
+ return;
460
+ }
461
+ const session = activeSessions[agentNumber - 1];
462
+ if (!session) {
463
+ console.error(`No agent #${agentNumber}. There are ${activeSessions.length} active agents.`);
464
+ process.exit(1);
465
+ }
466
+ if (session.pid !== null) {
467
+ launcher.kill(session.pid);
468
+ console.log(`Killed agent #${agentNumber} (PID ${session.pid})`);
469
+ }
470
+ else {
471
+ console.log(`Agent #${agentNumber} has no PID recorded — marking as errored.`);
472
+ }
473
+ approvals.deleteBySession(session.id);
474
+ sessions.error(session.id);
475
+ });
476
+ // ---- verbo sync ----
477
+ program
478
+ .command('sync')
479
+ .description('Force re-sync with relay server')
480
+ .action(() => {
481
+ console.log('Sync requested. (Relay integration pending team setup)');
482
+ });
483
+ // ---- verbo stop ----
484
+ program
485
+ .command('stop')
486
+ .description('Stop the daemon')
487
+ .action(() => {
488
+ const { projectDir } = initAll();
489
+ const pidFile = path.join(projectDir, '.verbo', 'daemon.pid');
490
+ if (!fs.existsSync(pidFile)) {
491
+ console.log('No daemon running (no PID file found).');
492
+ return;
493
+ }
494
+ const pid = parseInt(fs.readFileSync(pidFile, 'utf-8').trim(), 10);
495
+ if (isNaN(pid)) {
496
+ console.error('Invalid PID in daemon.pid file.');
497
+ fs.unlinkSync(pidFile);
498
+ return;
499
+ }
500
+ try {
501
+ process.kill(pid);
502
+ console.log(`Stopped daemon (PID ${pid}).`);
503
+ }
504
+ catch {
505
+ console.log(`Daemon (PID ${pid}) was not running.`);
506
+ }
507
+ fs.unlinkSync(pidFile);
508
+ });
509
+ // ---- verbo yolo ----
510
+ program
511
+ .command('yolo')
512
+ .description('Toggle YOLO mode — auto-approve all agent permissions')
513
+ .action(() => {
514
+ console.log('YOLO mode toggled. Use the TUI (!) to toggle in real-time.');
515
+ });
516
+ // ---- verbo memory ----
517
+ const memoryCmd = program
518
+ .command('memory')
519
+ .description('View or manage project memory (learnings from agent tasks)');
520
+ memoryCmd
521
+ .action(() => {
522
+ const { learnings, tasks } = initAll();
523
+ const all = learnings.list();
524
+ if (all.length === 0) {
525
+ console.log('No learnings stored yet.');
526
+ return;
527
+ }
528
+ // Group by category
529
+ const groups = new Map();
530
+ for (const l of all) {
531
+ if (!groups.has(l.category))
532
+ groups.set(l.category, []);
533
+ groups.get(l.category).push(l);
534
+ }
535
+ for (const [cat, items] of groups) {
536
+ console.log(`\n${cat.toUpperCase()}S (${items.length})`);
537
+ for (const l of items) {
538
+ const taskTitle = l.taskId ? tasks.get(l.taskId)?.title ?? l.taskId.slice(0, 8) : null;
539
+ const taskSuffix = taskTitle ? ` (${taskTitle})` : '';
540
+ const sourceSuffix = l.source ? ` [${l.source}]` : '';
541
+ console.log(` · ${l.content}${sourceSuffix}${taskSuffix}`);
542
+ }
543
+ }
544
+ console.log(`\nTotal: ${all.length} learnings`);
545
+ });
546
+ memoryCmd
547
+ .command('clear')
548
+ .description('Clear all stored project memory')
549
+ .action(async () => {
550
+ const { learnings } = initAll();
551
+ const count = learnings.list().length;
552
+ if (count === 0) {
553
+ console.log('No learnings to clear.');
554
+ return;
555
+ }
556
+ const readline = await import('readline');
557
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
558
+ await new Promise((resolve) => {
559
+ rl.question(`Clear all ${count} learnings? (y/N) `, (answer) => {
560
+ rl.close();
561
+ if (answer.trim().toLowerCase() !== 'y') {
562
+ console.log('Aborted.');
563
+ process.exit(0);
564
+ }
565
+ resolve();
566
+ });
567
+ });
568
+ learnings.clear();
569
+ console.log(`Cleared ${count} learnings.`);
570
+ });
571
+ // ---- verbo config ----
572
+ const configCmd = program
573
+ .command('config')
574
+ .description('Read or write VERBO.md configuration fields');
575
+ configCmd
576
+ .command('set <field> <value>')
577
+ .description('Set a field in VERBO.md (e.g. verbo config set merge_mode auto)')
578
+ .action(async (field, value) => {
579
+ const projDir = resolveProjectDir();
580
+ const verboMdPath = path.join(projDir, 'VERBO.md');
581
+ const validationErr = validateFieldValue(field, value);
582
+ if (validationErr) {
583
+ console.error(validationErr);
584
+ process.exit(1);
585
+ }
586
+ const warning = requiresConfirmation(field, value);
587
+ if (warning) {
588
+ console.log(warning);
589
+ const readline = await import('readline');
590
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
591
+ await new Promise((resolve) => {
592
+ rl.question('Confirm? (y/N) ', (answer) => {
593
+ rl.close();
594
+ if (answer.trim().toLowerCase() !== 'y') {
595
+ console.log('Aborted.');
596
+ process.exit(0);
597
+ }
598
+ resolve();
599
+ });
600
+ });
601
+ }
602
+ setVerboMdField(verboMdPath, field, value);
603
+ console.log(`✓ VERBO.md updated: ${field} → ${value}`);
604
+ });
605
+ configCmd
606
+ .command('get [field]')
607
+ .description('Show current VERBO.md configuration (or a specific field)')
608
+ .action((field) => {
609
+ const projDir = resolveProjectDir();
610
+ const verboMdPath = path.join(projDir, 'VERBO.md');
611
+ if (field) {
612
+ if (!FIELD_REGISTRY[field]) {
613
+ const known = Object.keys(FIELD_REGISTRY).join(', ');
614
+ console.error(`Unknown field "${field}". Known fields: ${known}`);
615
+ process.exit(1);
616
+ }
617
+ const fields = getVerboMdFields(verboMdPath);
618
+ const val = fields[field];
619
+ if (val === undefined) {
620
+ console.log(`${field}: (not set)`);
621
+ }
622
+ else {
623
+ console.log(`${field}: ${val}`);
624
+ }
625
+ return;
626
+ }
627
+ const fields = getVerboMdFields(verboMdPath);
628
+ if (Object.keys(fields).length === 0) {
629
+ console.log('No configuration set. Run `verbo init` to create VERBO.md.');
630
+ return;
631
+ }
632
+ for (const [k, v] of Object.entries(fields)) {
633
+ console.log(`${k}: ${v}`);
634
+ }
635
+ });
636
+ // ---- verbo init ----
637
+ program
638
+ .command('init')
639
+ .description('Initialize VERBO.md for your project')
640
+ .action(async () => {
641
+ const projDir = resolveProjectDir();
642
+ const verboMdPath = path.join(projDir, 'VERBO.md');
643
+ if (fs.existsSync(verboMdPath)) {
644
+ console.log('VERBO.md already exists. Delete it first to re-initialize.');
645
+ return;
646
+ }
647
+ console.log('Verbo Init — Setting up your project\n');
648
+ // Detect project
649
+ const info = detectProject(projDir);
650
+ const projectName = path.basename(projDir);
651
+ const defaults = buildDefaults(projectName, info);
652
+ // Check for gh CLI
653
+ try {
654
+ execSync('gh --version', { stdio: 'ignore' });
655
+ }
656
+ catch {
657
+ console.log(' Warning: gh CLI not found. Auto-PR creation requires it.');
658
+ console.log(' Install: https://cli.github.com/\n');
659
+ }
660
+ // Run questionnaire
661
+ const answers = await runQuestionnaire(defaults);
662
+ // Render and write
663
+ const md = renderVerboMd(answers);
664
+ fs.writeFileSync(verboMdPath, md, 'utf-8');
665
+ console.log(`\n VERBO.md created at ${verboMdPath}`);
666
+ console.log(' Agents will follow these rules when launched with verbo start.\n');
667
+ });
668
+ // ---- verbo login ----
669
+ program
670
+ .command('login')
671
+ .description('Log in to Verbo (opens browser)')
672
+ .action(async () => {
673
+ clearSession();
674
+ await ensureAuth();
675
+ const session = readSession();
676
+ if (session) {
677
+ console.log(`Logged in as ${session.email} (${session.plan} plan)`);
678
+ }
679
+ });
680
+ // ---- verbo logout ----
681
+ program
682
+ .command('logout')
683
+ .description('Log out and clear local credentials')
684
+ .action(() => {
685
+ clearSession();
686
+ console.log('Logged out. Run verbo login to authenticate again.');
687
+ });
688
+ // ---- verbo cost ----
689
+ function fmtUsd(n) {
690
+ return '$' + n.toFixed(4);
691
+ }
692
+ function fmtTokens(n) {
693
+ if (n >= 1_000_000)
694
+ return (n / 1_000_000).toFixed(2) + 'M';
695
+ if (n >= 1_000)
696
+ return (n / 1_000).toFixed(1) + 'k';
697
+ return String(n);
698
+ }
699
+ const costCmd = program
700
+ .command('cost')
701
+ .description('Show cost tracking summary and breakdowns');
702
+ costCmd
703
+ .command('summary')
704
+ .description('Overall cost summary')
705
+ .action(() => {
706
+ const { costStore } = initAll();
707
+ const s = costStore.getSummary();
708
+ const today = costStore.getCostToday();
709
+ console.log('=== Cost Summary ===');
710
+ console.log(`Total spent: ${fmtUsd(s.totalCostUsd)}`);
711
+ console.log(`Spent today: ${fmtUsd(today)}`);
712
+ console.log(`Entries: ${s.entryCount}`);
713
+ console.log(`Input tokens: ${fmtTokens(s.totalInputTokens)}`);
714
+ console.log(`Output tokens: ${fmtTokens(s.totalOutputTokens)}`);
715
+ console.log(`Cache read: ${fmtTokens(s.totalCacheReadTokens)}`);
716
+ console.log(`Cache write: ${fmtTokens(s.totalCacheWriteTokens)}`);
717
+ });
718
+ costCmd
719
+ .command('by-task')
720
+ .description('Cost breakdown by task')
721
+ .action(() => {
722
+ const { costStore, tasks } = initAll();
723
+ const groups = costStore.getCostByTask();
724
+ if (groups.length === 0) {
725
+ console.log('No cost data recorded yet.');
726
+ return;
727
+ }
728
+ console.log('=== Cost by Task ===');
729
+ for (const g of groups) {
730
+ const task = g.group !== '(no task)' ? tasks.get(g.group) : null;
731
+ const label = task ? `${g.group.slice(0, 8)}… ${task.title}` : g.group;
732
+ console.log(` ${fmtUsd(g.costUsd).padStart(10)} ${String(g.entryCount).padStart(4)} entries ${label}`);
733
+ }
734
+ });
735
+ costCmd
736
+ .command('by-day')
737
+ .description('Cost breakdown by day')
738
+ .action(() => {
739
+ const { costStore } = initAll();
740
+ const groups = costStore.getCostByDay();
741
+ if (groups.length === 0) {
742
+ console.log('No cost data recorded yet.');
743
+ return;
744
+ }
745
+ console.log('=== Cost by Day ===');
746
+ for (const g of groups) {
747
+ console.log(` ${g.group} ${fmtUsd(g.costUsd).padStart(10)} ${String(g.entryCount).padStart(4)} entries`);
748
+ }
749
+ });
750
+ costCmd
751
+ .command('by-model')
752
+ .description('Cost breakdown by model (requires cost_events data)')
753
+ .action(() => {
754
+ const { db } = initAll();
755
+ const raw = db.raw();
756
+ const rows = raw.prepare(`SELECT model, SUM(cost_usd) AS cost_usd, COUNT(*) AS entry_count
757
+ FROM cost_events GROUP BY model ORDER BY cost_usd DESC`).all();
758
+ if (rows.length === 0) {
759
+ console.log('No model-level cost data recorded yet.');
760
+ console.log('(Model tracking uses the cost_events table, populated by providers that report model info.)');
761
+ return;
762
+ }
763
+ console.log('=== Cost by Model ===');
764
+ for (const r of rows) {
765
+ console.log(` ${fmtUsd(r.cost_usd).padStart(10)} ${String(r.entry_count).padStart(4)} entries ${r.model}`);
766
+ }
767
+ });
768
+ costCmd
769
+ .command('by-pipeline')
770
+ .description('Cost breakdown by pipeline run')
771
+ .action(() => {
772
+ const { costStore } = initAll();
773
+ const groups = costStore.getCostByPipeline();
774
+ if (groups.length === 0) {
775
+ console.log('No cost data recorded yet.');
776
+ return;
777
+ }
778
+ console.log('=== Cost by Pipeline Run ===');
779
+ for (const g of groups) {
780
+ console.log(` ${fmtUsd(g.costUsd).padStart(10)} ${String(g.entryCount).padStart(4)} entries ${g.group}`);
781
+ }
782
+ });
783
+ costCmd
784
+ .command('update-prices <model>')
785
+ .description('Set or update pricing for a model (costs per 1M tokens)')
786
+ .option('--input <cost>', 'Input cost per 1M tokens', parseFloat)
787
+ .option('--output <cost>', 'Output cost per 1M tokens', parseFloat)
788
+ .option('--cache-read <cost>', 'Cache read cost per 1M tokens', parseFloat)
789
+ .option('--cache-write <cost>', 'Cache write cost per 1M tokens', parseFloat)
790
+ .action((model, opts) => {
791
+ if (opts.input == null || opts.output == null) {
792
+ console.error('--input and --output are required.');
793
+ process.exit(1);
794
+ }
795
+ const { costStore } = initAll();
796
+ costStore.updateModelPricing({
797
+ model,
798
+ inputCostPer1mTokens: opts.input,
799
+ outputCostPer1mTokens: opts.output,
800
+ cacheReadCostPer1mTokens: opts.cacheRead ?? null,
801
+ cacheWriteCostPer1mTokens: opts.cacheWrite ?? null,
802
+ });
803
+ console.log(`Pricing updated for model: ${model}`);
804
+ console.log(` Input: $${opts.input}/1M tokens`);
805
+ console.log(` Output: $${opts.output}/1M tokens`);
806
+ if (opts.cacheRead != null)
807
+ console.log(` Cache read: $${opts.cacheRead}/1M tokens`);
808
+ if (opts.cacheWrite != null)
809
+ console.log(` Cache write: $${opts.cacheWrite}/1M tokens`);
810
+ });
811
+ costCmd
812
+ .command('prices')
813
+ .description('List all configured model prices')
814
+ .action(() => {
815
+ const { costStore } = initAll();
816
+ const prices = costStore.listModelPricing();
817
+ if (prices.length === 0) {
818
+ console.log('No custom model pricing configured.');
819
+ console.log('Using defaults: $3/1M input, $15/1M output, $0.30/1M cache-read, $3.75/1M cache-write');
820
+ return;
821
+ }
822
+ console.log('=== Model Pricing ===');
823
+ for (const p of prices) {
824
+ console.log(` ${p.model}`);
825
+ console.log(` Input: $${p.inputCostPer1mTokens}/1M Output: $${p.outputCostPer1mTokens}/1M`);
826
+ if (p.cacheReadCostPer1mTokens != null)
827
+ console.log(` Cache read: $${p.cacheReadCostPer1mTokens}/1M Cache write: $${p.cacheWriteCostPer1mTokens}/1M`);
828
+ }
829
+ });
830
+ // Default: show summary when just `verbo cost` is run
831
+ costCmd.action(() => {
832
+ const { costStore } = initAll();
833
+ const s = costStore.getSummary();
834
+ const today = costStore.getCostToday();
835
+ console.log('=== Cost Summary ===');
836
+ console.log(`Total spent: ${fmtUsd(s.totalCostUsd)}`);
837
+ console.log(`Spent today: ${fmtUsd(today)}`);
838
+ console.log(`Entries: ${s.entryCount}`);
839
+ console.log(`Input tokens: ${fmtTokens(s.totalInputTokens)}`);
840
+ console.log(`Output tokens: ${fmtTokens(s.totalOutputTokens)}`);
841
+ console.log(`Cache read: ${fmtTokens(s.totalCacheReadTokens)}`);
842
+ console.log(`Cache write: ${fmtTokens(s.totalCacheWriteTokens)}`);
843
+ console.log('');
844
+ console.log('Subcommands: summary, by-task, by-day, by-model, by-pipeline, update-prices, prices');
845
+ });
846
+ // ---- verbo whoami ----
847
+ program
848
+ .command('whoami')
849
+ .description('Show current authenticated user and plan')
850
+ .action(() => {
851
+ const session = readSession();
852
+ if (!session) {
853
+ console.log('Not logged in. Run verbo login.');
854
+ return;
855
+ }
856
+ console.log(`Email: ${session.email}`);
857
+ console.log(`Plan: ${session.plan}`);
858
+ console.log(`Agents: ${session.limits.maxAgents === -1 ? 'unlimited' : session.limits.maxAgents}`);
859
+ console.log(`Tasks: ${session.limits.maxTasks === -1 ? 'unlimited' : session.limits.maxTasks}`);
860
+ });
861
+ // ---- Default action: TUI ----
862
+ program
863
+ .action(async () => {
864
+ // ensureAuth() is handled by the preAction hook
865
+ await ensureInit(resolveProjectDir());
866
+ const session = readSession();
867
+ let flashMessage = null;
868
+ const all = initAll();
869
+ const { projectDir, tasks, sessions, detector, parallelizer, hotFiles, approvals, humanActions, orchestratorStore, pipelineRunner, budgetPerTaskUsd, } = all;
870
+ const auditLogForTui = createAuditLogStore(all.db);
871
+ const pidFile = path.join(projectDir, '.verbo', 'daemon.pid');
872
+ fs.writeFileSync(pidFile, String(process.pid), 'utf-8');
873
+ const approvalServer = await createApprovalServer({
874
+ port: 5050,
875
+ approvals,
876
+ sessions,
877
+ pollIntervalMs: 500,
878
+ timeoutMs: 300000,
879
+ });
880
+ console.log(`Approval server running on http://localhost:${approvalServer.port()}`);
881
+ // Re-create launcher with the actual approval server port (and budget)
882
+ const launcher = createAgentLauncher({
883
+ projectDir,
884
+ mcpServerCommand: MCP_SERVER_COMMAND,
885
+ approvalPort: approvalServer.port(),
886
+ budgetPerTaskUsd,
887
+ learningStore: all.learnings,
888
+ });
889
+ // Initialize notifications from VERBO.md
890
+ const notificationConfig = readNotificationConfig(projectDir);
891
+ const notifications = createNotifications(notificationConfig);
892
+ // Sync pipelines from VERBO.md [pipelines] section: create runs for configured pipelines
893
+ const pipelineRunIds = new Set();
894
+ const pipelineConfigs = readPipelineConfigs(projectDir);
895
+ for (const pipelineConfig of pipelineConfigs) {
896
+ if (pipelineConfig.steps.length === 0)
897
+ continue;
898
+ // Map each step title to a matching task (first task whose title matches)
899
+ const allTasks = tasks.list();
900
+ const resolvedSteps = pipelineConfig.steps.map((step, i) => {
901
+ const match = allTasks.find((t) => t.title.toLowerCase() === step.title.toLowerCase());
902
+ return match ? {
903
+ id: `${pipelineConfig.name}-step-${i}`,
904
+ name: step.title,
905
+ taskId: match.id,
906
+ on_failure: (step.onFailure === 'notify' ? 'stop' : step.onFailure),
907
+ requires_approval: step.requiresApproval,
908
+ } : null;
909
+ });
910
+ // Only start a run if all steps have matching tasks
911
+ if (resolvedSteps.some((s) => s === null))
912
+ continue;
913
+ const pipeline = {
914
+ id: pipelineConfig.name,
915
+ name: pipelineConfig.title,
916
+ steps: resolvedSteps,
917
+ };
918
+ try {
919
+ const run = pipelineRunner.start(pipeline);
920
+ pipelineRunIds.add(run.id);
921
+ }
922
+ catch {
923
+ // Non-fatal: pipeline start failure doesn't block the TUI
924
+ }
925
+ }
926
+ // Clean up stale state from previous runs (orphaned worktrees, sessions, approvals)
927
+ const cleanupResult = await cleanStaleState({
928
+ tasks, sessions, approvals, launcher, projectDir,
929
+ pipelineRunner, pipelineRunIds,
930
+ });
931
+ if (cleanupResult.worktreesCleaned > 0) {
932
+ console.log(`Cleaned up ${cleanupResult.worktreesCleaned} orphaned worktree(s) from previous run`);
933
+ }
934
+ // Prune old audit log entries (retain 90 days by default)
935
+ const auditPruned = pruneAuditLog(all.db.raw(), 90);
936
+ if (auditPruned > 0) {
937
+ console.log(`Pruned ${auditPruned} audit log entries older than 90 days`);
938
+ }
939
+ // Bootstrap team members from VERBO.md [team] section
940
+ const verboMdPath = path.join(projectDir, 'VERBO.md');
941
+ if (fs.existsSync(verboMdPath)) {
942
+ const verboMdContent = fs.readFileSync(verboMdPath, 'utf-8');
943
+ const teamSeeded = bootstrapTeamFromVerboMd(all.db.raw(), verboMdContent);
944
+ if (teamSeeded > 0) {
945
+ console.log(`Bootstrapped ${teamSeeded} team member(s) from VERBO.md`);
946
+ }
947
+ }
948
+ // Create merge queue for sequential PR processing
949
+ const mergeQueue = createMergeQueue({
950
+ baseBranch: readBaseBranch(projectDir),
951
+ humanActions,
952
+ onMerged: () => {
953
+ hotFiles.refresh();
954
+ },
955
+ });
956
+ // Create orchestrator for review-and-push workflow
957
+ const orchestrator = createGitHubOrchestrator({
958
+ projectDir,
959
+ humanActions,
960
+ store: orchestratorStore,
961
+ mergeQueue,
962
+ });
963
+ // Kill session helper: kill PID, clean up approvals, mark errored
964
+ function killSessionById(sessionId) {
965
+ const session = sessions.get(sessionId);
966
+ if (session?.pid !== null && session?.pid !== undefined) {
967
+ launcher.kill(session.pid);
968
+ }
969
+ approvals.deleteBySession(sessionId);
970
+ sessions.error(sessionId);
971
+ }
972
+ // Create conflict enforcer for automatic conflict resolution
973
+ const enforcer = createConflictEnforcer({
974
+ tasks,
975
+ sessions,
976
+ detector,
977
+ killSession: killSessionById,
978
+ });
979
+ // Periodic conflict enforcement — check every 2 seconds
980
+ const enforcementInterval = setInterval(() => {
981
+ enforcer.enforce().then((actions) => {
982
+ for (const action of actions) {
983
+ // Terminal bell: conflict enforcement happened
984
+ process.stderr.write('\x07');
985
+ }
986
+ }).catch(() => { });
987
+ }, 2000);
988
+ // Factory mode — automatic task dispatch pipeline
989
+ const FACTORY_MAX_AGENTS = 4;
990
+ let factoryMode = false;
991
+ const factoryInterval = setInterval(() => {
992
+ const activeSessions = sessions.listActive();
993
+ if (activeSessions.length >= FACTORY_MAX_AGENTS)
994
+ return;
995
+ const allTasks = tasks.list();
996
+ const todoTasks = allTasks.filter((t) => t.status === 'todo' && !t.title.startsWith('HUMANO:'));
997
+ if (todoTasks.length === 0)
998
+ return;
999
+ const activeFiles = allTasks
1000
+ .filter((t) => t.status === 'in_progress')
1001
+ .flatMap((t) => t.filePaths);
1002
+ // Find the first non-conflicting task to launch.
1003
+ // Subtasks (parentTaskId set) are always launched regardless of factoryMode.
1004
+ // Regular top-level tasks are only launched when factoryMode is on.
1005
+ for (const candidate of todoTasks) {
1006
+ const isSubtask = !!candidate.parentTaskId;
1007
+ if (!isSubtask && !factoryMode)
1008
+ continue;
1009
+ if (activeFiles.length > 0 && candidate.filePaths.length > 0) {
1010
+ if (hasFileOverlap(candidate.filePaths, activeFiles))
1011
+ continue;
1012
+ }
1013
+ launchAgentForTask(candidate.id, tasks, sessions, launcher, approvals, projectDir, 'medium', enforcer, orchestrator, { notifications, pipelineRunner, pipelineRunIds }).catch((err) => {
1014
+ console.error(`Factory: failed to launch ${candidate.id}:`, err.message);
1015
+ });
1016
+ break;
1017
+ }
1018
+ }, 3000);
1019
+ function getState() {
1020
+ const allTasks = tasks.list();
1021
+ const activeSessions = sessions.listActive();
1022
+ const conflicts = detector.findOverlaps();
1023
+ const parallelBatch = parallelizer.findSafeBatch();
1024
+ // Group active sessions by humanId for teamMembers
1025
+ const byHuman = new Map();
1026
+ for (const session of activeSessions) {
1027
+ if (!byHuman.has(session.humanId)) {
1028
+ byHuman.set(session.humanId, []);
1029
+ }
1030
+ byHuman.get(session.humanId).push(session);
1031
+ }
1032
+ const teamMembers = Array.from(byHuman.entries()).map(([humanId, sArr]) => ({
1033
+ humanId,
1034
+ sessions: sArr,
1035
+ }));
1036
+ return {
1037
+ tasks: allTasks,
1038
+ activeSessions,
1039
+ conflicts,
1040
+ parallelBatch,
1041
+ teamMembers,
1042
+ syncStatus: 'disconnected',
1043
+ pendingApprovals: approvals.listPending(),
1044
+ resolvedApprovals: approvals.listResolved(),
1045
+ humanActions: humanActions.listPending(),
1046
+ orchestratorStates: orchestratorStore.list(),
1047
+ yoloMode: approvalServer.isYoloMode(),
1048
+ factoryMode,
1049
+ flashMessage,
1050
+ intelligenceEnabled: isIntelligenceEnabled(),
1051
+ isCompliance: false,
1052
+ sandboxEnabled: false,
1053
+ mergeQueueItems: mergeQueue.getQueue(),
1054
+ mergeQueueProcessing: mergeQueue.isProcessing(),
1055
+ };
1056
+ }
1057
+ const tui = startTui({
1058
+ getState,
1059
+ teamName: 'local',
1060
+ onCreateTask: (title) => {
1061
+ const allTasks = tasks.list();
1062
+ const check = checkLimit('maxTasks', allTasks.length, session.limits);
1063
+ if (!check.allowed) {
1064
+ flashMessage = check.message;
1065
+ setTimeout(() => { flashMessage = null; }, 4000);
1066
+ return;
1067
+ }
1068
+ tasks.create({ title });
1069
+ },
1070
+ onDeleteTask: (taskId) => {
1071
+ tasks.delete(taskId);
1072
+ },
1073
+ onLaunchAgent: (taskId, trustLevel) => {
1074
+ const activeSessions = sessions.listActive();
1075
+ const check = checkLimit('maxAgents', activeSessions.length, session.limits);
1076
+ if (!check.allowed) {
1077
+ flashMessage = check.message;
1078
+ setTimeout(() => { flashMessage = null; }, 4000);
1079
+ return;
1080
+ }
1081
+ launchAgentForTask(taskId, tasks, sessions, launcher, approvals, projectDir, trustLevel ?? 'medium', enforcer, orchestrator, { notifications, pipelineRunner, pipelineRunIds }).catch((err) => {
1082
+ const e = err;
1083
+ const debugLine = `[${new Date().toISOString()}] LAUNCH FAILED: ${e.message}\n${e.stack}\n`;
1084
+ fs.appendFileSync(path.join(projectDir, '.verbo', 'launch-debug.log'), debugLine);
1085
+ });
1086
+ },
1087
+ onLaunchBatch: (taskIds, trustLevel) => {
1088
+ const activeSessions = sessions.listActive();
1089
+ const check = checkLimit('maxAgents', activeSessions.length, session.limits);
1090
+ if (!check.allowed) {
1091
+ flashMessage = check.message;
1092
+ setTimeout(() => { flashMessage = null; }, 4000);
1093
+ return;
1094
+ }
1095
+ for (const taskId of taskIds) {
1096
+ launchAgentForTask(taskId, tasks, sessions, launcher, approvals, projectDir, trustLevel ?? 'medium', enforcer, orchestrator, { notifications, pipelineRunner, pipelineRunIds }).catch((err) => {
1097
+ console.error(`Failed to launch agent for ${taskId}:`, err.message);
1098
+ });
1099
+ }
1100
+ },
1101
+ onKillAgent: (sessionId) => {
1102
+ killSessionById(sessionId);
1103
+ },
1104
+ onDismiss: () => {
1105
+ clearInterval(enforcementInterval);
1106
+ clearInterval(factoryInterval);
1107
+ approvalServer.stop();
1108
+ tui.unmount();
1109
+ console.log('TUI dismissed. Daemon still running.');
1110
+ },
1111
+ onApproveRequest: (id) => {
1112
+ approvals.approve(id);
1113
+ },
1114
+ onDenyRequest: (id) => {
1115
+ approvals.deny(id);
1116
+ },
1117
+ onToggleYolo: () => {
1118
+ approvalServer.setYoloMode(!approvalServer.isYoloMode());
1119
+ },
1120
+ onToggleFactory: () => {
1121
+ factoryMode = !factoryMode;
1122
+ },
1123
+ onResolveHumanAction: (id) => {
1124
+ humanActions.resolve(id);
1125
+ },
1126
+ onDecomposeTask: async (taskId) => {
1127
+ const task = tasks.get(taskId);
1128
+ if (!task)
1129
+ return null;
1130
+ const input = [task.title, task.description].filter(Boolean).join('\n\n');
1131
+ const decomposer = createTaskDecomposer(tasks);
1132
+ return decomposer.decompose(input);
1133
+ },
1134
+ onConfirmDecompose: (subtasks, parentTaskId) => {
1135
+ const decomposer = createTaskDecomposer(tasks);
1136
+ decomposer.confirm(subtasks, parentTaskId).catch((err) => {
1137
+ console.error('Failed to create subtasks:', err.message);
1138
+ });
1139
+ },
1140
+ onForcePush: (taskId) => {
1141
+ orchestrator.forcePush(taskId).then((result) => {
1142
+ if (result.prUrl) {
1143
+ tasks.update(taskId, { prUrl: result.prUrl });
1144
+ }
1145
+ }).catch((err) => {
1146
+ console.error(`Force push failed for task ${taskId}:`, err.message);
1147
+ });
1148
+ },
1149
+ getLearnings: () => all.learnings.list(),
1150
+ getAuditEntries: () => auditLogForTui.query(),
1151
+ getTaskTitleById: (taskId) => tasks.get(taskId)?.title ?? null,
1152
+ });
1153
+ await tui.waitUntilExit();
1154
+ });
1155
+ program.parse();
1156
+ //# sourceMappingURL=verbo.js.map