@urateam/core 0.1.0

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 (620) hide show
  1. package/dist/__tests__/assembler.test.d.ts +2 -0
  2. package/dist/__tests__/assembler.test.d.ts.map +1 -0
  3. package/dist/__tests__/assembler.test.js +63 -0
  4. package/dist/__tests__/assembler.test.js.map +1 -0
  5. package/dist/__tests__/auth-check.test.d.ts +2 -0
  6. package/dist/__tests__/auth-check.test.d.ts.map +1 -0
  7. package/dist/__tests__/auth-check.test.js +88 -0
  8. package/dist/__tests__/auth-check.test.js.map +1 -0
  9. package/dist/__tests__/auto-merge.test.d.ts +15 -0
  10. package/dist/__tests__/auto-merge.test.d.ts.map +1 -0
  11. package/dist/__tests__/auto-merge.test.js +428 -0
  12. package/dist/__tests__/auto-merge.test.js.map +1 -0
  13. package/dist/__tests__/bec89-unified-schema.test.d.ts +2 -0
  14. package/dist/__tests__/bec89-unified-schema.test.d.ts.map +1 -0
  15. package/dist/__tests__/bec89-unified-schema.test.js +235 -0
  16. package/dist/__tests__/bec89-unified-schema.test.js.map +1 -0
  17. package/dist/__tests__/conflict-detector.test.d.ts +2 -0
  18. package/dist/__tests__/conflict-detector.test.d.ts.map +1 -0
  19. package/dist/__tests__/conflict-detector.test.js +206 -0
  20. package/dist/__tests__/conflict-detector.test.js.map +1 -0
  21. package/dist/__tests__/coordination.test.d.ts +2 -0
  22. package/dist/__tests__/coordination.test.d.ts.map +1 -0
  23. package/dist/__tests__/coordination.test.js +257 -0
  24. package/dist/__tests__/coordination.test.js.map +1 -0
  25. package/dist/__tests__/db-postgres.test.d.ts +14 -0
  26. package/dist/__tests__/db-postgres.test.d.ts.map +1 -0
  27. package/dist/__tests__/db-postgres.test.js +289 -0
  28. package/dist/__tests__/db-postgres.test.js.map +1 -0
  29. package/dist/__tests__/db.test.d.ts +2 -0
  30. package/dist/__tests__/db.test.d.ts.map +1 -0
  31. package/dist/__tests__/db.test.js +182 -0
  32. package/dist/__tests__/db.test.js.map +1 -0
  33. package/dist/__tests__/deep-review.test.d.ts +2 -0
  34. package/dist/__tests__/deep-review.test.d.ts.map +1 -0
  35. package/dist/__tests__/deep-review.test.js +322 -0
  36. package/dist/__tests__/deep-review.test.js.map +1 -0
  37. package/dist/__tests__/devcontainer.test.d.ts +2 -0
  38. package/dist/__tests__/devcontainer.test.d.ts.map +1 -0
  39. package/dist/__tests__/devcontainer.test.js +89 -0
  40. package/dist/__tests__/devcontainer.test.js.map +1 -0
  41. package/dist/__tests__/distributed-lock.test.d.ts +18 -0
  42. package/dist/__tests__/distributed-lock.test.d.ts.map +1 -0
  43. package/dist/__tests__/distributed-lock.test.js +237 -0
  44. package/dist/__tests__/distributed-lock.test.js.map +1 -0
  45. package/dist/__tests__/e2e-pipeline.test.d.ts +25 -0
  46. package/dist/__tests__/e2e-pipeline.test.d.ts.map +1 -0
  47. package/dist/__tests__/e2e-pipeline.test.js +517 -0
  48. package/dist/__tests__/e2e-pipeline.test.js.map +1 -0
  49. package/dist/__tests__/error-classifier.test.d.ts +2 -0
  50. package/dist/__tests__/error-classifier.test.d.ts.map +1 -0
  51. package/dist/__tests__/error-classifier.test.js +33 -0
  52. package/dist/__tests__/error-classifier.test.js.map +1 -0
  53. package/dist/__tests__/executor-integration.test.d.ts +11 -0
  54. package/dist/__tests__/executor-integration.test.d.ts.map +1 -0
  55. package/dist/__tests__/executor-integration.test.js +246 -0
  56. package/dist/__tests__/executor-integration.test.js.map +1 -0
  57. package/dist/__tests__/executor-issue-id.test.d.ts +13 -0
  58. package/dist/__tests__/executor-issue-id.test.d.ts.map +1 -0
  59. package/dist/__tests__/executor-issue-id.test.js +211 -0
  60. package/dist/__tests__/executor-issue-id.test.js.map +1 -0
  61. package/dist/__tests__/executor.test.d.ts +2 -0
  62. package/dist/__tests__/executor.test.d.ts.map +1 -0
  63. package/dist/__tests__/executor.test.js +164 -0
  64. package/dist/__tests__/executor.test.js.map +1 -0
  65. package/dist/__tests__/extract-handoff.test.d.ts +2 -0
  66. package/dist/__tests__/extract-handoff.test.d.ts.map +1 -0
  67. package/dist/__tests__/extract-handoff.test.js +131 -0
  68. package/dist/__tests__/extract-handoff.test.js.map +1 -0
  69. package/dist/__tests__/fail-on-auto-commit.test.d.ts +2 -0
  70. package/dist/__tests__/fail-on-auto-commit.test.d.ts.map +1 -0
  71. package/dist/__tests__/fail-on-auto-commit.test.js +156 -0
  72. package/dist/__tests__/fail-on-auto-commit.test.js.map +1 -0
  73. package/dist/__tests__/fixtures/webhook-comment.json +5 -0
  74. package/dist/__tests__/fixtures/webhook-state-change.json +15 -0
  75. package/dist/__tests__/force-push-agent-branches.test.d.ts +12 -0
  76. package/dist/__tests__/force-push-agent-branches.test.d.ts.map +1 -0
  77. package/dist/__tests__/force-push-agent-branches.test.js +348 -0
  78. package/dist/__tests__/force-push-agent-branches.test.js.map +1 -0
  79. package/dist/__tests__/github-webhook.test.d.ts +2 -0
  80. package/dist/__tests__/github-webhook.test.d.ts.map +1 -0
  81. package/dist/__tests__/github-webhook.test.js +370 -0
  82. package/dist/__tests__/github-webhook.test.js.map +1 -0
  83. package/dist/__tests__/gitlab.test.d.ts +28 -0
  84. package/dist/__tests__/gitlab.test.d.ts.map +1 -0
  85. package/dist/__tests__/gitlab.test.js +241 -0
  86. package/dist/__tests__/gitlab.test.js.map +1 -0
  87. package/dist/__tests__/integration/auto-commit.test.d.ts +2 -0
  88. package/dist/__tests__/integration/auto-commit.test.d.ts.map +1 -0
  89. package/dist/__tests__/integration/auto-commit.test.js +207 -0
  90. package/dist/__tests__/integration/auto-commit.test.js.map +1 -0
  91. package/dist/__tests__/integration/bec99-cross-worktree-guard.test.d.ts +10 -0
  92. package/dist/__tests__/integration/bec99-cross-worktree-guard.test.d.ts.map +1 -0
  93. package/dist/__tests__/integration/bec99-cross-worktree-guard.test.js +183 -0
  94. package/dist/__tests__/integration/bec99-cross-worktree-guard.test.js.map +1 -0
  95. package/dist/__tests__/integration/reproduce-bec99.test.d.ts +32 -0
  96. package/dist/__tests__/integration/reproduce-bec99.test.d.ts.map +1 -0
  97. package/dist/__tests__/integration/reproduce-bec99.test.js +243 -0
  98. package/dist/__tests__/integration/reproduce-bec99.test.js.map +1 -0
  99. package/dist/__tests__/integration/vitest-changed.test.d.ts +10 -0
  100. package/dist/__tests__/integration/vitest-changed.test.d.ts.map +1 -0
  101. package/dist/__tests__/integration/vitest-changed.test.js +128 -0
  102. package/dist/__tests__/integration/vitest-changed.test.js.map +1 -0
  103. package/dist/__tests__/license.test.d.ts +2 -0
  104. package/dist/__tests__/license.test.d.ts.map +1 -0
  105. package/dist/__tests__/license.test.js +53 -0
  106. package/dist/__tests__/license.test.js.map +1 -0
  107. package/dist/__tests__/mcp-resolver.test.d.ts +2 -0
  108. package/dist/__tests__/mcp-resolver.test.d.ts.map +1 -0
  109. package/dist/__tests__/mcp-resolver.test.js +65 -0
  110. package/dist/__tests__/mcp-resolver.test.js.map +1 -0
  111. package/dist/__tests__/migrator.test.d.ts +2 -0
  112. package/dist/__tests__/migrator.test.d.ts.map +1 -0
  113. package/dist/__tests__/migrator.test.js +300 -0
  114. package/dist/__tests__/migrator.test.js.map +1 -0
  115. package/dist/__tests__/notifier-discord.test.d.ts +2 -0
  116. package/dist/__tests__/notifier-discord.test.d.ts.map +1 -0
  117. package/dist/__tests__/notifier-discord.test.js +166 -0
  118. package/dist/__tests__/notifier-discord.test.js.map +1 -0
  119. package/dist/__tests__/notifier-slack.test.d.ts +2 -0
  120. package/dist/__tests__/notifier-slack.test.d.ts.map +1 -0
  121. package/dist/__tests__/notifier-slack.test.js +157 -0
  122. package/dist/__tests__/notifier-slack.test.js.map +1 -0
  123. package/dist/__tests__/notifier.test.d.ts +2 -0
  124. package/dist/__tests__/notifier.test.d.ts.map +1 -0
  125. package/dist/__tests__/notifier.test.js +207 -0
  126. package/dist/__tests__/notifier.test.js.map +1 -0
  127. package/dist/__tests__/pipeline-config.test.d.ts +2 -0
  128. package/dist/__tests__/pipeline-config.test.d.ts.map +1 -0
  129. package/dist/__tests__/pipeline-config.test.js +143 -0
  130. package/dist/__tests__/pipeline-config.test.js.map +1 -0
  131. package/dist/__tests__/pipeline-runner.test.d.ts +2 -0
  132. package/dist/__tests__/pipeline-runner.test.d.ts.map +1 -0
  133. package/dist/__tests__/pipeline-runner.test.js +359 -0
  134. package/dist/__tests__/pipeline-runner.test.js.map +1 -0
  135. package/dist/__tests__/pm-approvals-n1.repro.test.d.ts +9 -0
  136. package/dist/__tests__/pm-approvals-n1.repro.test.d.ts.map +1 -0
  137. package/dist/__tests__/pm-approvals-n1.repro.test.js +175 -0
  138. package/dist/__tests__/pm-approvals-n1.repro.test.js.map +1 -0
  139. package/dist/__tests__/pm-approvals.test.d.ts +2 -0
  140. package/dist/__tests__/pm-approvals.test.d.ts.map +1 -0
  141. package/dist/__tests__/pm-approvals.test.js +162 -0
  142. package/dist/__tests__/pm-approvals.test.js.map +1 -0
  143. package/dist/__tests__/pm-budget.test.d.ts +2 -0
  144. package/dist/__tests__/pm-budget.test.d.ts.map +1 -0
  145. package/dist/__tests__/pm-budget.test.js +65 -0
  146. package/dist/__tests__/pm-budget.test.js.map +1 -0
  147. package/dist/__tests__/pm-conflict.test.d.ts +2 -0
  148. package/dist/__tests__/pm-conflict.test.d.ts.map +1 -0
  149. package/dist/__tests__/pm-conflict.test.js +87 -0
  150. package/dist/__tests__/pm-conflict.test.js.map +1 -0
  151. package/dist/__tests__/pm-promote.test.d.ts +2 -0
  152. package/dist/__tests__/pm-promote.test.d.ts.map +1 -0
  153. package/dist/__tests__/pm-promote.test.js +82 -0
  154. package/dist/__tests__/pm-promote.test.js.map +1 -0
  155. package/dist/__tests__/pm-recover.test.d.ts +2 -0
  156. package/dist/__tests__/pm-recover.test.d.ts.map +1 -0
  157. package/dist/__tests__/pm-recover.test.js +100 -0
  158. package/dist/__tests__/pm-recover.test.js.map +1 -0
  159. package/dist/__tests__/pm-scheduler.test.d.ts +2 -0
  160. package/dist/__tests__/pm-scheduler.test.d.ts.map +1 -0
  161. package/dist/__tests__/pm-scheduler.test.js +112 -0
  162. package/dist/__tests__/pm-scheduler.test.js.map +1 -0
  163. package/dist/__tests__/pm-slack-interface.test.d.ts +2 -0
  164. package/dist/__tests__/pm-slack-interface.test.d.ts.map +1 -0
  165. package/dist/__tests__/pm-slack-interface.test.js +372 -0
  166. package/dist/__tests__/pm-slack-interface.test.js.map +1 -0
  167. package/dist/__tests__/pm-slack.test.d.ts +2 -0
  168. package/dist/__tests__/pm-slack.test.d.ts.map +1 -0
  169. package/dist/__tests__/pm-slack.test.js +83 -0
  170. package/dist/__tests__/pm-slack.test.js.map +1 -0
  171. package/dist/__tests__/pm-triage.test.d.ts +2 -0
  172. package/dist/__tests__/pm-triage.test.d.ts.map +1 -0
  173. package/dist/__tests__/pm-triage.test.js +198 -0
  174. package/dist/__tests__/pm-triage.test.js.map +1 -0
  175. package/dist/__tests__/pm-types.test.d.ts +2 -0
  176. package/dist/__tests__/pm-types.test.d.ts.map +1 -0
  177. package/dist/__tests__/pm-types.test.js +76 -0
  178. package/dist/__tests__/pm-types.test.js.map +1 -0
  179. package/dist/__tests__/pr-automerge.test.d.ts +18 -0
  180. package/dist/__tests__/pr-automerge.test.d.ts.map +1 -0
  181. package/dist/__tests__/pr-automerge.test.js +645 -0
  182. package/dist/__tests__/pr-automerge.test.js.map +1 -0
  183. package/dist/__tests__/pr-description.test.d.ts +2 -0
  184. package/dist/__tests__/pr-description.test.d.ts.map +1 -0
  185. package/dist/__tests__/pr-description.test.js +728 -0
  186. package/dist/__tests__/pr-description.test.js.map +1 -0
  187. package/dist/__tests__/prompt-injection.test.d.ts +2 -0
  188. package/dist/__tests__/prompt-injection.test.d.ts.map +1 -0
  189. package/dist/__tests__/prompt-injection.test.js +446 -0
  190. package/dist/__tests__/prompt-injection.test.js.map +1 -0
  191. package/dist/__tests__/ralph-gate.test.d.ts +19 -0
  192. package/dist/__tests__/ralph-gate.test.d.ts.map +1 -0
  193. package/dist/__tests__/ralph-gate.test.js +593 -0
  194. package/dist/__tests__/ralph-gate.test.js.map +1 -0
  195. package/dist/__tests__/ralph-review-fix-regression.test.d.ts +18 -0
  196. package/dist/__tests__/ralph-review-fix-regression.test.d.ts.map +1 -0
  197. package/dist/__tests__/ralph-review-fix-regression.test.js +306 -0
  198. package/dist/__tests__/ralph-review-fix-regression.test.js.map +1 -0
  199. package/dist/__tests__/ralph.test.d.ts +2 -0
  200. package/dist/__tests__/ralph.test.d.ts.map +1 -0
  201. package/dist/__tests__/ralph.test.js +96 -0
  202. package/dist/__tests__/ralph.test.js.map +1 -0
  203. package/dist/__tests__/recover-stuck.test.d.ts +8 -0
  204. package/dist/__tests__/recover-stuck.test.d.ts.map +1 -0
  205. package/dist/__tests__/recover-stuck.test.js +399 -0
  206. package/dist/__tests__/recover-stuck.test.js.map +1 -0
  207. package/dist/__tests__/repo.test.d.ts +2 -0
  208. package/dist/__tests__/repo.test.d.ts.map +1 -0
  209. package/dist/__tests__/repo.test.js +295 -0
  210. package/dist/__tests__/repo.test.js.map +1 -0
  211. package/dist/__tests__/repro-bec58-n-plus-one.test.d.ts +2 -0
  212. package/dist/__tests__/repro-bec58-n-plus-one.test.d.ts.map +1 -0
  213. package/dist/__tests__/repro-bec58-n-plus-one.test.js +187 -0
  214. package/dist/__tests__/repro-bec58-n-plus-one.test.js.map +1 -0
  215. package/dist/__tests__/reproduce-bec113-pagination-warning.test.d.ts +16 -0
  216. package/dist/__tests__/reproduce-bec113-pagination-warning.test.d.ts.map +1 -0
  217. package/dist/__tests__/reproduce-bec113-pagination-warning.test.js +226 -0
  218. package/dist/__tests__/reproduce-bec113-pagination-warning.test.js.map +1 -0
  219. package/dist/__tests__/reproduce-bec43-updatedat.test.d.ts +2 -0
  220. package/dist/__tests__/reproduce-bec43-updatedat.test.d.ts.map +1 -0
  221. package/dist/__tests__/reproduce-bec43-updatedat.test.js +76 -0
  222. package/dist/__tests__/reproduce-bec43-updatedat.test.js.map +1 -0
  223. package/dist/__tests__/reproduce-bec48-distributed-race.test.d.ts +18 -0
  224. package/dist/__tests__/reproduce-bec48-distributed-race.test.d.ts.map +1 -0
  225. package/dist/__tests__/reproduce-bec48-distributed-race.test.js +178 -0
  226. package/dist/__tests__/reproduce-bec48-distributed-race.test.js.map +1 -0
  227. package/dist/__tests__/reproduce-bec62.test.d.ts +2 -0
  228. package/dist/__tests__/reproduce-bec62.test.d.ts.map +1 -0
  229. package/dist/__tests__/reproduce-bec62.test.js +86 -0
  230. package/dist/__tests__/reproduce-bec62.test.js.map +1 -0
  231. package/dist/__tests__/reproduce-bec91-stuck-in-progress.test.d.ts +13 -0
  232. package/dist/__tests__/reproduce-bec91-stuck-in-progress.test.d.ts.map +1 -0
  233. package/dist/__tests__/reproduce-bec91-stuck-in-progress.test.js +220 -0
  234. package/dist/__tests__/reproduce-bec91-stuck-in-progress.test.js.map +1 -0
  235. package/dist/__tests__/review-feedback.test.d.ts +2 -0
  236. package/dist/__tests__/review-feedback.test.d.ts.map +1 -0
  237. package/dist/__tests__/review-feedback.test.js +383 -0
  238. package/dist/__tests__/review-feedback.test.js.map +1 -0
  239. package/dist/__tests__/sanitizer.test.d.ts +2 -0
  240. package/dist/__tests__/sanitizer.test.d.ts.map +1 -0
  241. package/dist/__tests__/sanitizer.test.js +162 -0
  242. package/dist/__tests__/sanitizer.test.js.map +1 -0
  243. package/dist/__tests__/security.test.d.ts +2 -0
  244. package/dist/__tests__/security.test.d.ts.map +1 -0
  245. package/dist/__tests__/security.test.js +52 -0
  246. package/dist/__tests__/security.test.js.map +1 -0
  247. package/dist/__tests__/server.test.d.ts +2 -0
  248. package/dist/__tests__/server.test.d.ts.map +1 -0
  249. package/dist/__tests__/server.test.js +61 -0
  250. package/dist/__tests__/server.test.js.map +1 -0
  251. package/dist/__tests__/slack-alerts.test.d.ts +2 -0
  252. package/dist/__tests__/slack-alerts.test.d.ts.map +1 -0
  253. package/dist/__tests__/slack-alerts.test.js +214 -0
  254. package/dist/__tests__/slack-alerts.test.js.map +1 -0
  255. package/dist/__tests__/stage-models.test.d.ts +14 -0
  256. package/dist/__tests__/stage-models.test.d.ts.map +1 -0
  257. package/dist/__tests__/stage-models.test.js +244 -0
  258. package/dist/__tests__/stage-models.test.js.map +1 -0
  259. package/dist/__tests__/start-todo.test.d.ts +2 -0
  260. package/dist/__tests__/start-todo.test.d.ts.map +1 -0
  261. package/dist/__tests__/start-todo.test.js +175 -0
  262. package/dist/__tests__/start-todo.test.js.map +1 -0
  263. package/dist/__tests__/tech-stack.test.d.ts +2 -0
  264. package/dist/__tests__/tech-stack.test.d.ts.map +1 -0
  265. package/dist/__tests__/tech-stack.test.js +75 -0
  266. package/dist/__tests__/tech-stack.test.js.map +1 -0
  267. package/dist/__tests__/templates.test.d.ts +2 -0
  268. package/dist/__tests__/templates.test.d.ts.map +1 -0
  269. package/dist/__tests__/templates.test.js +161 -0
  270. package/dist/__tests__/templates.test.js.map +1 -0
  271. package/dist/__tests__/test-quality.test.d.ts +2 -0
  272. package/dist/__tests__/test-quality.test.d.ts.map +1 -0
  273. package/dist/__tests__/test-quality.test.js +329 -0
  274. package/dist/__tests__/test-quality.test.js.map +1 -0
  275. package/dist/__tests__/token-budget.test.d.ts +2 -0
  276. package/dist/__tests__/token-budget.test.d.ts.map +1 -0
  277. package/dist/__tests__/token-budget.test.js +198 -0
  278. package/dist/__tests__/token-budget.test.js.map +1 -0
  279. package/dist/__tests__/types.test.d.ts +2 -0
  280. package/dist/__tests__/types.test.d.ts.map +1 -0
  281. package/dist/__tests__/types.test.js +156 -0
  282. package/dist/__tests__/types.test.js.map +1 -0
  283. package/dist/__tests__/validate.test.d.ts +2 -0
  284. package/dist/__tests__/validate.test.d.ts.map +1 -0
  285. package/dist/__tests__/validate.test.js +128 -0
  286. package/dist/__tests__/validate.test.js.map +1 -0
  287. package/dist/__tests__/webhook-handler.test.d.ts +2 -0
  288. package/dist/__tests__/webhook-handler.test.d.ts.map +1 -0
  289. package/dist/__tests__/webhook-handler.test.js +286 -0
  290. package/dist/__tests__/webhook-handler.test.js.map +1 -0
  291. package/dist/__tests__/webhook.test.d.ts +2 -0
  292. package/dist/__tests__/webhook.test.d.ts.map +1 -0
  293. package/dist/__tests__/webhook.test.js +58 -0
  294. package/dist/__tests__/webhook.test.js.map +1 -0
  295. package/dist/db/client.d.ts +56 -0
  296. package/dist/db/client.d.ts.map +1 -0
  297. package/dist/db/client.js +201 -0
  298. package/dist/db/client.js.map +1 -0
  299. package/dist/db/index.d.ts +4 -0
  300. package/dist/db/index.d.ts.map +1 -0
  301. package/dist/db/index.js +4 -0
  302. package/dist/db/index.js.map +1 -0
  303. package/dist/db/migrations/postgres/001_initial_schema.sql +78 -0
  304. package/dist/db/migrations/postgres/002_pg_timestamps.sql +78 -0
  305. package/dist/db/migrations/postgres/003_retry_count.sql +10 -0
  306. package/dist/db/migrations/postgres/004_review_feedback.sql +20 -0
  307. package/dist/db/migrations/postgres/005_auto_merge.sql +15 -0
  308. package/dist/db/migrations/sqlite/001_initial_schema.sql +78 -0
  309. package/dist/db/migrations/sqlite/002_retry_count.sql +5 -0
  310. package/dist/db/migrations/sqlite/003_review_feedback.sql +7 -0
  311. package/dist/db/migrations/sqlite/004_auto_merge.sql +6 -0
  312. package/dist/db/migrator.d.ts +51 -0
  313. package/dist/db/migrator.d.ts.map +1 -0
  314. package/dist/db/migrator.js +188 -0
  315. package/dist/db/migrator.js.map +1 -0
  316. package/dist/db/schema.d.ts +1114 -0
  317. package/dist/db/schema.d.ts.map +1 -0
  318. package/dist/db/schema.js +129 -0
  319. package/dist/db/schema.js.map +1 -0
  320. package/dist/entrypoint.d.ts +2 -0
  321. package/dist/entrypoint.d.ts.map +1 -0
  322. package/dist/entrypoint.js +113 -0
  323. package/dist/entrypoint.js.map +1 -0
  324. package/dist/executor/agent-config.d.ts +10 -0
  325. package/dist/executor/agent-config.d.ts.map +1 -0
  326. package/dist/executor/agent-config.js +81 -0
  327. package/dist/executor/agent-config.js.map +1 -0
  328. package/dist/executor/agent-stream.d.ts +65 -0
  329. package/dist/executor/agent-stream.d.ts.map +1 -0
  330. package/dist/executor/agent-stream.js +101 -0
  331. package/dist/executor/agent-stream.js.map +1 -0
  332. package/dist/executor/auth-check.d.ts +10 -0
  333. package/dist/executor/auth-check.d.ts.map +1 -0
  334. package/dist/executor/auth-check.js +52 -0
  335. package/dist/executor/auth-check.js.map +1 -0
  336. package/dist/executor/deep-review.d.ts +61 -0
  337. package/dist/executor/deep-review.d.ts.map +1 -0
  338. package/dist/executor/deep-review.js +308 -0
  339. package/dist/executor/deep-review.js.map +1 -0
  340. package/dist/executor/executor.d.ts +27 -0
  341. package/dist/executor/executor.d.ts.map +1 -0
  342. package/dist/executor/executor.js +168 -0
  343. package/dist/executor/executor.js.map +1 -0
  344. package/dist/executor/extract-handoff.d.ts +14 -0
  345. package/dist/executor/extract-handoff.d.ts.map +1 -0
  346. package/dist/executor/extract-handoff.js +80 -0
  347. package/dist/executor/extract-handoff.js.map +1 -0
  348. package/dist/executor/handoff.d.ts +24 -0
  349. package/dist/executor/handoff.d.ts.map +1 -0
  350. package/dist/executor/handoff.js +63 -0
  351. package/dist/executor/handoff.js.map +1 -0
  352. package/dist/executor/index.d.ts +8 -0
  353. package/dist/executor/index.d.ts.map +1 -0
  354. package/dist/executor/index.js +8 -0
  355. package/dist/executor/index.js.map +1 -0
  356. package/dist/executor/mcp-resolver.d.ts +29 -0
  357. package/dist/executor/mcp-resolver.d.ts.map +1 -0
  358. package/dist/executor/mcp-resolver.js +80 -0
  359. package/dist/executor/mcp-resolver.js.map +1 -0
  360. package/dist/executor/permissions.d.ts +11 -0
  361. package/dist/executor/permissions.d.ts.map +1 -0
  362. package/dist/executor/permissions.js +32 -0
  363. package/dist/executor/permissions.js.map +1 -0
  364. package/dist/executor/profiles.d.ts +5 -0
  365. package/dist/executor/profiles.d.ts.map +1 -0
  366. package/dist/executor/profiles.js +35 -0
  367. package/dist/executor/profiles.js.map +1 -0
  368. package/dist/executor/prompt/assembler.d.ts +10 -0
  369. package/dist/executor/prompt/assembler.d.ts.map +1 -0
  370. package/dist/executor/prompt/assembler.js +28 -0
  371. package/dist/executor/prompt/assembler.js.map +1 -0
  372. package/dist/executor/prompt/index.d.ts +5 -0
  373. package/dist/executor/prompt/index.d.ts.map +1 -0
  374. package/dist/executor/prompt/index.js +5 -0
  375. package/dist/executor/prompt/index.js.map +1 -0
  376. package/dist/executor/prompt/sanitizer.d.ts +25 -0
  377. package/dist/executor/prompt/sanitizer.d.ts.map +1 -0
  378. package/dist/executor/prompt/sanitizer.js +81 -0
  379. package/dist/executor/prompt/sanitizer.js.map +1 -0
  380. package/dist/executor/prompt/schema-mapper.d.ts +7 -0
  381. package/dist/executor/prompt/schema-mapper.d.ts.map +1 -0
  382. package/dist/executor/prompt/schema-mapper.js +59 -0
  383. package/dist/executor/prompt/schema-mapper.js.map +1 -0
  384. package/dist/executor/prompt/templates.d.ts +31 -0
  385. package/dist/executor/prompt/templates.d.ts.map +1 -0
  386. package/dist/executor/prompt/templates.js +283 -0
  387. package/dist/executor/prompt/templates.js.map +1 -0
  388. package/dist/executor/ralph.d.ts +19 -0
  389. package/dist/executor/ralph.d.ts.map +1 -0
  390. package/dist/executor/ralph.js +112 -0
  391. package/dist/executor/ralph.js.map +1 -0
  392. package/dist/executor/test-quality.d.ts +117 -0
  393. package/dist/executor/test-quality.d.ts.map +1 -0
  394. package/dist/executor/test-quality.js +261 -0
  395. package/dist/executor/test-quality.js.map +1 -0
  396. package/dist/executor/validate.d.ts +15 -0
  397. package/dist/executor/validate.d.ts.map +1 -0
  398. package/dist/executor/validate.js +124 -0
  399. package/dist/executor/validate.js.map +1 -0
  400. package/dist/index.d.ts +29 -0
  401. package/dist/index.d.ts.map +1 -0
  402. package/dist/index.js +26 -0
  403. package/dist/index.js.map +1 -0
  404. package/dist/license.d.ts +18 -0
  405. package/dist/license.d.ts.map +1 -0
  406. package/dist/license.js +44 -0
  407. package/dist/license.js.map +1 -0
  408. package/dist/logger.d.ts +43 -0
  409. package/dist/logger.d.ts.map +1 -0
  410. package/dist/logger.js +91 -0
  411. package/dist/logger.js.map +1 -0
  412. package/dist/notifier/composite.d.ts +13 -0
  413. package/dist/notifier/composite.d.ts.map +1 -0
  414. package/dist/notifier/composite.js +28 -0
  415. package/dist/notifier/composite.js.map +1 -0
  416. package/dist/notifier/discord.d.ts +14 -0
  417. package/dist/notifier/discord.d.ts.map +1 -0
  418. package/dist/notifier/discord.js +105 -0
  419. package/dist/notifier/discord.js.map +1 -0
  420. package/dist/notifier/index.d.ts +6 -0
  421. package/dist/notifier/index.d.ts.map +1 -0
  422. package/dist/notifier/index.js +6 -0
  423. package/dist/notifier/index.js.map +1 -0
  424. package/dist/notifier/linear.d.ts +28 -0
  425. package/dist/notifier/linear.d.ts.map +1 -0
  426. package/dist/notifier/linear.js +138 -0
  427. package/dist/notifier/linear.js.map +1 -0
  428. package/dist/notifier/slack-alerts.d.ts +62 -0
  429. package/dist/notifier/slack-alerts.d.ts.map +1 -0
  430. package/dist/notifier/slack-alerts.js +184 -0
  431. package/dist/notifier/slack-alerts.js.map +1 -0
  432. package/dist/notifier/slack.d.ts +14 -0
  433. package/dist/notifier/slack.d.ts.map +1 -0
  434. package/dist/notifier/slack.js +146 -0
  435. package/dist/notifier/slack.js.map +1 -0
  436. package/dist/pipeline/automerge.d.ts +44 -0
  437. package/dist/pipeline/automerge.d.ts.map +1 -0
  438. package/dist/pipeline/automerge.js +135 -0
  439. package/dist/pipeline/automerge.js.map +1 -0
  440. package/dist/pipeline/config.d.ts +5 -0
  441. package/dist/pipeline/config.d.ts.map +1 -0
  442. package/dist/pipeline/config.js +68 -0
  443. package/dist/pipeline/config.js.map +1 -0
  444. package/dist/pipeline/distributed-lock.d.ts +50 -0
  445. package/dist/pipeline/distributed-lock.d.ts.map +1 -0
  446. package/dist/pipeline/distributed-lock.js +114 -0
  447. package/dist/pipeline/distributed-lock.js.map +1 -0
  448. package/dist/pipeline/error-classifier.d.ts +9 -0
  449. package/dist/pipeline/error-classifier.d.ts.map +1 -0
  450. package/dist/pipeline/error-classifier.js +25 -0
  451. package/dist/pipeline/error-classifier.js.map +1 -0
  452. package/dist/pipeline/index.d.ts +9 -0
  453. package/dist/pipeline/index.d.ts.map +1 -0
  454. package/dist/pipeline/index.js +9 -0
  455. package/dist/pipeline/index.js.map +1 -0
  456. package/dist/pipeline/pr-description.d.ts +35 -0
  457. package/dist/pipeline/pr-description.d.ts.map +1 -0
  458. package/dist/pipeline/pr-description.js +52 -0
  459. package/dist/pipeline/pr-description.js.map +1 -0
  460. package/dist/pipeline/queue.d.ts +7 -0
  461. package/dist/pipeline/queue.d.ts.map +1 -0
  462. package/dist/pipeline/queue.js +39 -0
  463. package/dist/pipeline/queue.js.map +1 -0
  464. package/dist/pipeline/router.d.ts +6 -0
  465. package/dist/pipeline/router.d.ts.map +1 -0
  466. package/dist/pipeline/router.js +19 -0
  467. package/dist/pipeline/router.js.map +1 -0
  468. package/dist/pipeline/runner.d.ts +142 -0
  469. package/dist/pipeline/runner.d.ts.map +1 -0
  470. package/dist/pipeline/runner.js +1848 -0
  471. package/dist/pipeline/runner.js.map +1 -0
  472. package/dist/pm/actions/approval-helpers.d.ts +11 -0
  473. package/dist/pm/actions/approval-helpers.d.ts.map +1 -0
  474. package/dist/pm/actions/approval-helpers.js +34 -0
  475. package/dist/pm/actions/approval-helpers.js.map +1 -0
  476. package/dist/pm/actions/cancel.d.ts +11 -0
  477. package/dist/pm/actions/cancel.d.ts.map +1 -0
  478. package/dist/pm/actions/cancel.js +68 -0
  479. package/dist/pm/actions/cancel.js.map +1 -0
  480. package/dist/pm/actions/deprioritize.d.ts +12 -0
  481. package/dist/pm/actions/deprioritize.d.ts.map +1 -0
  482. package/dist/pm/actions/deprioritize.js +55 -0
  483. package/dist/pm/actions/deprioritize.js.map +1 -0
  484. package/dist/pm/actions/promote.d.ts +11 -0
  485. package/dist/pm/actions/promote.d.ts.map +1 -0
  486. package/dist/pm/actions/promote.js +78 -0
  487. package/dist/pm/actions/promote.js.map +1 -0
  488. package/dist/pm/actions/recover-stuck.d.ts +42 -0
  489. package/dist/pm/actions/recover-stuck.d.ts.map +1 -0
  490. package/dist/pm/actions/recover-stuck.js +143 -0
  491. package/dist/pm/actions/recover-stuck.js.map +1 -0
  492. package/dist/pm/actions/recover.d.ts +18 -0
  493. package/dist/pm/actions/recover.d.ts.map +1 -0
  494. package/dist/pm/actions/recover.js +56 -0
  495. package/dist/pm/actions/recover.js.map +1 -0
  496. package/dist/pm/actions/resolve-approvals.d.ts +17 -0
  497. package/dist/pm/actions/resolve-approvals.d.ts.map +1 -0
  498. package/dist/pm/actions/resolve-approvals.js +92 -0
  499. package/dist/pm/actions/resolve-approvals.js.map +1 -0
  500. package/dist/pm/actions/start-todo.d.ts +28 -0
  501. package/dist/pm/actions/start-todo.d.ts.map +1 -0
  502. package/dist/pm/actions/start-todo.js +117 -0
  503. package/dist/pm/actions/start-todo.js.map +1 -0
  504. package/dist/pm/actions/triage.d.ts +13 -0
  505. package/dist/pm/actions/triage.d.ts.map +1 -0
  506. package/dist/pm/actions/triage.js +109 -0
  507. package/dist/pm/actions/triage.js.map +1 -0
  508. package/dist/pm/budget.d.ts +9 -0
  509. package/dist/pm/budget.d.ts.map +1 -0
  510. package/dist/pm/budget.js +62 -0
  511. package/dist/pm/budget.js.map +1 -0
  512. package/dist/pm/call-claude.d.ts +3 -0
  513. package/dist/pm/call-claude.d.ts.map +1 -0
  514. package/dist/pm/call-claude.js +37 -0
  515. package/dist/pm/call-claude.js.map +1 -0
  516. package/dist/pm/conflict-detector.d.ts +42 -0
  517. package/dist/pm/conflict-detector.d.ts.map +1 -0
  518. package/dist/pm/conflict-detector.js +116 -0
  519. package/dist/pm/conflict-detector.js.map +1 -0
  520. package/dist/pm/conflict.d.ts +20 -0
  521. package/dist/pm/conflict.d.ts.map +1 -0
  522. package/dist/pm/conflict.js +63 -0
  523. package/dist/pm/conflict.js.map +1 -0
  524. package/dist/pm/coordination.d.ts +50 -0
  525. package/dist/pm/coordination.d.ts.map +1 -0
  526. package/dist/pm/coordination.js +163 -0
  527. package/dist/pm/coordination.js.map +1 -0
  528. package/dist/pm/linear-helpers.d.ts +2 -0
  529. package/dist/pm/linear-helpers.d.ts.map +1 -0
  530. package/dist/pm/linear-helpers.js +16 -0
  531. package/dist/pm/linear-helpers.js.map +1 -0
  532. package/dist/pm/scheduler.d.ts +47 -0
  533. package/dist/pm/scheduler.d.ts.map +1 -0
  534. package/dist/pm/scheduler.js +346 -0
  535. package/dist/pm/scheduler.js.map +1 -0
  536. package/dist/pm/slack-helpers.d.ts +2 -0
  537. package/dist/pm/slack-helpers.d.ts.map +1 -0
  538. package/dist/pm/slack-helpers.js +24 -0
  539. package/dist/pm/slack-helpers.js.map +1 -0
  540. package/dist/pm/slack-interface.d.ts +133 -0
  541. package/dist/pm/slack-interface.d.ts.map +1 -0
  542. package/dist/pm/slack-interface.js +641 -0
  543. package/dist/pm/slack-interface.js.map +1 -0
  544. package/dist/pm/slack.d.ts +18 -0
  545. package/dist/pm/slack.d.ts.map +1 -0
  546. package/dist/pm/slack.js +144 -0
  547. package/dist/pm/slack.js.map +1 -0
  548. package/dist/pm/types.d.ts +99 -0
  549. package/dist/pm/types.d.ts.map +1 -0
  550. package/dist/pm/types.js +17 -0
  551. package/dist/pm/types.js.map +1 -0
  552. package/dist/repo/config.d.ts +35 -0
  553. package/dist/repo/config.d.ts.map +1 -0
  554. package/dist/repo/config.js +72 -0
  555. package/dist/repo/config.js.map +1 -0
  556. package/dist/repo/devcontainer.d.ts +33 -0
  557. package/dist/repo/devcontainer.d.ts.map +1 -0
  558. package/dist/repo/devcontainer.js +90 -0
  559. package/dist/repo/devcontainer.js.map +1 -0
  560. package/dist/repo/git.d.ts +185 -0
  561. package/dist/repo/git.d.ts.map +1 -0
  562. package/dist/repo/git.js +586 -0
  563. package/dist/repo/git.js.map +1 -0
  564. package/dist/repo/github.d.ts +56 -0
  565. package/dist/repo/github.d.ts.map +1 -0
  566. package/dist/repo/github.js +164 -0
  567. package/dist/repo/github.js.map +1 -0
  568. package/dist/repo/gitlab.d.ts +47 -0
  569. package/dist/repo/gitlab.d.ts.map +1 -0
  570. package/dist/repo/gitlab.js +91 -0
  571. package/dist/repo/gitlab.js.map +1 -0
  572. package/dist/repo/index.d.ts +7 -0
  573. package/dist/repo/index.d.ts.map +1 -0
  574. package/dist/repo/index.js +5 -0
  575. package/dist/repo/index.js.map +1 -0
  576. package/dist/repo/tech-stack.d.ts +13 -0
  577. package/dist/repo/tech-stack.d.ts.map +1 -0
  578. package/dist/repo/tech-stack.js +112 -0
  579. package/dist/repo/tech-stack.js.map +1 -0
  580. package/dist/security/index.d.ts +3 -0
  581. package/dist/security/index.d.ts.map +1 -0
  582. package/dist/security/index.js +3 -0
  583. package/dist/security/index.js.map +1 -0
  584. package/dist/security/review-checklist.d.ts +9 -0
  585. package/dist/security/review-checklist.d.ts.map +1 -0
  586. package/dist/security/review-checklist.js +46 -0
  587. package/dist/security/review-checklist.js.map +1 -0
  588. package/dist/security/sandbox.d.ts +7 -0
  589. package/dist/security/sandbox.d.ts.map +1 -0
  590. package/dist/security/sandbox.js +31 -0
  591. package/dist/security/sandbox.js.map +1 -0
  592. package/dist/server.d.ts +48 -0
  593. package/dist/server.d.ts.map +1 -0
  594. package/dist/server.js +90 -0
  595. package/dist/server.js.map +1 -0
  596. package/dist/types.d.ts +1230 -0
  597. package/dist/types.d.ts.map +1 -0
  598. package/dist/types.js +225 -0
  599. package/dist/types.js.map +1 -0
  600. package/dist/webhook/github-handler.d.ts +39 -0
  601. package/dist/webhook/github-handler.d.ts.map +1 -0
  602. package/dist/webhook/github-handler.js +439 -0
  603. package/dist/webhook/github-handler.js.map +1 -0
  604. package/dist/webhook/handler.d.ts +16 -0
  605. package/dist/webhook/handler.d.ts.map +1 -0
  606. package/dist/webhook/handler.js +171 -0
  607. package/dist/webhook/handler.js.map +1 -0
  608. package/dist/webhook/index.d.ts +5 -0
  609. package/dist/webhook/index.d.ts.map +1 -0
  610. package/dist/webhook/index.js +5 -0
  611. package/dist/webhook/index.js.map +1 -0
  612. package/dist/webhook/parser.d.ts +18 -0
  613. package/dist/webhook/parser.d.ts.map +1 -0
  614. package/dist/webhook/parser.js +30 -0
  615. package/dist/webhook/parser.js.map +1 -0
  616. package/dist/webhook/signature.d.ts +2 -0
  617. package/dist/webhook/signature.d.ts.map +1 -0
  618. package/dist/webhook/signature.js +14 -0
  619. package/dist/webhook/signature.js.map +1 -0
  620. package/package.json +40 -0
@@ -0,0 +1,641 @@
1
+ /**
2
+ * PM Agent Slack Interface — bidirectional human-agent communication.
3
+ *
4
+ * Inbound:
5
+ * POST /slack/commands — slash commands (/pm prioritize, /pm create, …)
6
+ * POST /slack/events — Events API (natural language messages + URL verification)
7
+ *
8
+ * Outbound helpers (call from PM scheduler):
9
+ * notifyAssigned, notifySkipped, askForClarification, postDailySummary
10
+ */
11
+ import { Hono } from "hono";
12
+ import { createLogger } from "../logger.js";
13
+ import { sanitize } from "../executor/prompt/sanitizer.js";
14
+ import { parseJsonObject } from "../executor/agent-stream.js";
15
+ import { makeCallClaude, makeCallClaudeSonnet } from "./call-claude.js";
16
+ import { postSlackMessage } from "./slack-helpers.js";
17
+ const log = createLogger({ component: "PmAgent:slack-interface" });
18
+ // ---------------------------------------------------------------------------
19
+ // Module-level constants
20
+ // ---------------------------------------------------------------------------
21
+ /** Valid PM command type names — kept in sync with the PmCommand union type. */
22
+ const VALID_PM_COMMAND_TYPES = [
23
+ "prioritize",
24
+ "create",
25
+ "bulk_create",
26
+ "status",
27
+ "pause",
28
+ "resume",
29
+ "assign",
30
+ "unknown",
31
+ ];
32
+ /** Linear workflow state name for the Triage column. */
33
+ const LINEAR_STATE_TRIAGE = "Triage";
34
+ /** Linear workflow state name for the Todo column. */
35
+ const LINEAR_STATE_TODO = "Todo";
36
+ /** Linear label name that triggers the auto-implement pipeline. */
37
+ const LINEAR_LABEL_AUTO_IMPLEMENT = "auto-implement";
38
+ /** Valid numeric priority values accepted by Linear (1=Urgent … 4=Low). */
39
+ const VALID_PRIORITIES = [1, 2, 3, 4];
40
+ /** Default priority used when a generated issue omits or has an invalid value. */
41
+ const DEFAULT_PRIORITY = 3;
42
+ /** Lazy singleton for the `crypto` built-in — avoids repeated dynamic import on every Slack request. */
43
+ let _cryptoModule = null;
44
+ async function getCrypto() {
45
+ if (!_cryptoModule) {
46
+ try {
47
+ _cryptoModule = await import("crypto");
48
+ }
49
+ catch {
50
+ log.error("crypto module unavailable — cannot verify Slack signatures");
51
+ return null;
52
+ }
53
+ }
54
+ return _cryptoModule;
55
+ }
56
+ // ---------------------------------------------------------------------------
57
+ // Shared pause state — single-process only; use Redis for multi-process
58
+ // ---------------------------------------------------------------------------
59
+ let paused = false;
60
+ export function isPmPaused() {
61
+ return paused;
62
+ }
63
+ export function setPmPaused(value) {
64
+ paused = value;
65
+ }
66
+ // ---------------------------------------------------------------------------
67
+ // Slack request verification
68
+ // ---------------------------------------------------------------------------
69
+ /**
70
+ * Verifies the Slack signing secret against the X-Slack-Signature header.
71
+ * Returns `true` if valid, `false` otherwise.
72
+ *
73
+ * See https://api.slack.com/authentication/verifying-requests-from-slack
74
+ */
75
+ export async function verifySlackSignature(rawBody, timestamp, signature, signingSecret) {
76
+ // Reject requests older than 5 minutes
77
+ const requestAge = Math.abs(Date.now() / 1000 - Number(timestamp));
78
+ if (requestAge > 300)
79
+ return false;
80
+ const baseString = `v0:${timestamp}:${rawBody}`;
81
+ const crypto = await getCrypto();
82
+ if (!crypto)
83
+ return false;
84
+ const hmac = crypto
85
+ .createHmac("sha256", signingSecret)
86
+ .update(baseString, "utf8")
87
+ .digest("hex");
88
+ const expected = `v0=${hmac}`;
89
+ // Constant-time comparison
90
+ if (expected.length !== signature.length)
91
+ return false;
92
+ let result = 0;
93
+ for (let i = 0; i < expected.length; i++) {
94
+ result |= expected.charCodeAt(i) ^ signature.charCodeAt(i);
95
+ }
96
+ return result === 0;
97
+ }
98
+ // ---------------------------------------------------------------------------
99
+ // Command parser
100
+ // ---------------------------------------------------------------------------
101
+ /**
102
+ * Parses the text following "/pm" into a structured `PmCommand`.
103
+ *
104
+ * Examples:
105
+ * "prioritize BEC-25" → { type: "prioritize", issueId: "BEC-25" }
106
+ * 'create "title" "desc"' → { type: "create", title: "title", description: "desc" }
107
+ * "status" → { type: "status" }
108
+ * "pause" → { type: "pause" }
109
+ * "resume" → { type: "resume" }
110
+ * "assign BEC-13" → { type: "assign", issueId: "BEC-13" }
111
+ */
112
+ const ISSUE_ID_RE = /^[A-Z]+-\d+$/;
113
+ /**
114
+ * Extracts and validates an issue ID from a command like "prioritize BEC-25".
115
+ * Returns the uppercase issue ID string, or `null` if the format is invalid.
116
+ */
117
+ function parseIssueIdCommand(trimmed, keyword) {
118
+ const re = new RegExp(`^${keyword}\\s+`, "i");
119
+ const raw = trimmed.replace(re, "").trim().toUpperCase();
120
+ return ISSUE_ID_RE.test(raw) ? raw : null;
121
+ }
122
+ export function parsePmCommand(text) {
123
+ const trimmed = text.trim();
124
+ if (/^prioritize\s+/i.test(trimmed)) {
125
+ const issueId = parseIssueIdCommand(trimmed, "prioritize");
126
+ if (!issueId)
127
+ return { type: "unknown", original: text };
128
+ return { type: "prioritize", issueId };
129
+ }
130
+ if (/^assign\s+/i.test(trimmed)) {
131
+ const issueId = parseIssueIdCommand(trimmed, "assign");
132
+ if (!issueId)
133
+ return { type: "unknown", original: text };
134
+ return { type: "assign", issueId };
135
+ }
136
+ if (/^create\s+/i.test(trimmed)) {
137
+ const rest = trimmed.replace(/^create\s+/i, "").trim();
138
+ const matches = rest.match(/^"([^"]+)"\s+"([^"]+)"$/);
139
+ if (matches) {
140
+ return { type: "create", title: matches[1], description: matches[2] };
141
+ }
142
+ // Single-quoted titles, no description
143
+ const singleMatch = rest.match(/^"([^"]+)"$/);
144
+ if (singleMatch) {
145
+ return { type: "create", title: singleMatch[1], description: "" };
146
+ }
147
+ return { type: "unknown", original: text };
148
+ }
149
+ if (/^status$/i.test(trimmed))
150
+ return { type: "status" };
151
+ if (/^pause$/i.test(trimmed))
152
+ return { type: "pause" };
153
+ if (/^resume$/i.test(trimmed))
154
+ return { type: "resume" };
155
+ return { type: "unknown", original: text };
156
+ }
157
+ // ---------------------------------------------------------------------------
158
+ // Natural language intent parsing via Claude
159
+ // ---------------------------------------------------------------------------
160
+ /**
161
+ * Interprets a free-text Slack message as a `PmCommand` using Claude.
162
+ * Returns `{ type: "unknown", original }` if no actionable intent is found.
163
+ */
164
+ export async function interpretNaturalLanguage(message, callClaude) {
165
+ const safe = sanitize(message);
166
+ const prompt = `You are a PM Agent assistant. The following Slack message was sent to you:\n\n"${safe}"\n\nClassify it as exactly ONE of these JSON responses (no other text):\n{"type":"prioritize","issueId":"<id>"}\n{"type":"create","title":"<t>","description":"<d>"}\n{"type":"bulk_create","request":"<original request>"}\n{"type":"status"}\n{"type":"pause"}\n{"type":"resume"}\n{"type":"assign","issueId":"<id>"}\n{"type":"unknown","original":"${safe}"}\n\nRules:\n- Issue IDs look like BEC-25, ENG-42, etc.\n- "more urgent" / "higher priority" → prioritize\n- "add", "open a ticket", "create" → create (single issue with clear title)\n- "create issues for", "find gaps and create", "generate issues", "analyze and create multiple", "create tickets for all" → bulk_create (multiple issues from analysis)\n- "what's running", "show queue" → status\n- "stop", "pause" → pause\n- "start again", "unpause", "resume" → resume\n- "move to todo", "assign" → assign\n- Use bulk_create when the request implies analysis or generating multiple issues, not a single specific issue\n\nRespond ONLY with the JSON object.`;
167
+ try {
168
+ const raw = await callClaude(prompt);
169
+ const parsed = parseJsonObject(raw);
170
+ if (!parsed)
171
+ return { type: "unknown", original: message };
172
+ // Validate type field against the canonical list of command types
173
+ if (!VALID_PM_COMMAND_TYPES.includes(parsed.type)) {
174
+ return { type: "unknown", original: message };
175
+ }
176
+ return parsed;
177
+ }
178
+ catch (err) {
179
+ log.warn({ err, message }, "failed to parse NL intent");
180
+ return { type: "unknown", original: message };
181
+ }
182
+ }
183
+ /**
184
+ * Executes a parsed `PmCommand` against Linear and returns a human-readable
185
+ * response string suitable for posting back to Slack.
186
+ */
187
+ export async function executePmCommand(cmd, deps) {
188
+ let _linear = null;
189
+ async function getLinear() {
190
+ if (!_linear && deps.linearApiKey) {
191
+ const { LinearClient } = await import("@linear/sdk");
192
+ _linear = new LinearClient({ apiKey: deps.linearApiKey });
193
+ }
194
+ return _linear;
195
+ }
196
+ /**
197
+ * Searches Linear for an issue by its identifier (e.g. "BEC-25") and returns
198
+ * the first match, or `null` when not found. Shared by prioritize + assign.
199
+ */
200
+ async function findIssueByIdentifier(linear, issueId) {
201
+ const results = await linear.searchIssues(issueId);
202
+ return results.nodes?.[0] ?? null;
203
+ }
204
+ switch (cmd.type) {
205
+ case "status": {
206
+ const state = paused ? "⏸ *Paused*" : "▶️ *Running*";
207
+ return `PM Agent is ${state}.\nUse \`/pm pause\` or \`/pm resume\` to control autonomous assignment.`;
208
+ }
209
+ case "pause": {
210
+ setPmPaused(true);
211
+ log.info("PM Agent paused via Slack");
212
+ return "⏸ PM Agent autonomous assignment has been *paused*. Use `/pm resume` to restart.";
213
+ }
214
+ case "resume": {
215
+ setPmPaused(false);
216
+ log.info("PM Agent resumed via Slack");
217
+ return "▶️ PM Agent autonomous assignment has been *resumed*.";
218
+ }
219
+ case "prioritize": {
220
+ if (!deps.linearApiKey) {
221
+ return `⚠️ No Linear API key configured — cannot prioritize *${cmd.issueId}*.`;
222
+ }
223
+ try {
224
+ const linear = await getLinear();
225
+ if (!linear)
226
+ return `⚠️ No Linear API key configured — cannot prioritize *${cmd.issueId}*.`;
227
+ const issue = await findIssueByIdentifier(linear, cmd.issueId);
228
+ if (!issue)
229
+ return `⚠️ Issue *${cmd.issueId}* not found in Linear.`;
230
+ // updateIssue and createComment are independent — run in parallel
231
+ await Promise.all([
232
+ linear.updateIssue(issue.id, { priority: 1 }),
233
+ linear.createComment({
234
+ issueId: issue.id,
235
+ body: "🤖 **PM Agent** — Bumped to top of queue via Slack command.",
236
+ }),
237
+ ]);
238
+ log.info({ issueId: cmd.issueId }, "prioritized via Slack");
239
+ return `✅ *${cmd.issueId}* has been bumped to top priority (Urgent).`;
240
+ }
241
+ catch (err) {
242
+ log.error({ err, issueId: cmd.issueId }, "prioritize failed");
243
+ return `❌ Failed to prioritize *${cmd.issueId}*: ${err.message}`;
244
+ }
245
+ }
246
+ case "assign": {
247
+ if (!deps.linearApiKey) {
248
+ return `⚠️ No Linear API key configured — cannot assign *${cmd.issueId}*.`;
249
+ }
250
+ try {
251
+ const linear = await getLinear();
252
+ if (!linear)
253
+ return `⚠️ No Linear API key configured — cannot assign *${cmd.issueId}*.`;
254
+ const issue = await findIssueByIdentifier(linear, cmd.issueId);
255
+ if (!issue)
256
+ return `⚠️ Issue *${cmd.issueId}* not found in Linear.`;
257
+ const team = await issue.team;
258
+ const allStates = await linear.workflowStates({
259
+ filter: { team: { id: { eq: team?.id } } },
260
+ first: 50,
261
+ });
262
+ const todoState = allStates.nodes?.find((s) => s.name === LINEAR_STATE_TODO);
263
+ if (!todoState)
264
+ return `⚠️ No "${LINEAR_STATE_TODO}" state found for *${cmd.issueId}*'s team.`;
265
+ await linear.updateIssue(issue.id, { stateId: todoState.id });
266
+ await linear.createComment({
267
+ issueId: issue.id,
268
+ body: "🤖 **PM Agent** — Manually assigned to Todo via Slack command.",
269
+ });
270
+ log.info({ issueId: cmd.issueId }, "manually assigned to Todo via Slack");
271
+ return `✅ *${cmd.issueId}* has been moved to Todo.`;
272
+ }
273
+ catch (err) {
274
+ log.error({ err, issueId: cmd.issueId }, "assign failed");
275
+ return `❌ Failed to assign *${cmd.issueId}*: ${err.message}`;
276
+ }
277
+ }
278
+ case "create": {
279
+ if (!deps.linearApiKey) {
280
+ return `⚠️ No Linear API key configured — cannot create issue.`;
281
+ }
282
+ if (!deps.teamIds || deps.teamIds.length === 0) {
283
+ return `⚠️ No team IDs configured — cannot create issue.`;
284
+ }
285
+ try {
286
+ const linear = await getLinear();
287
+ if (!linear)
288
+ return `⚠️ No Linear API key configured — cannot create issue.`;
289
+ const created = await linear.createIssue({
290
+ teamId: deps.teamIds[0],
291
+ title: cmd.title,
292
+ description: cmd.description || undefined,
293
+ });
294
+ const issue = await created.issue;
295
+ const url = issue?.url ?? "";
296
+ log.info({ title: cmd.title, issueId: issue?.identifier }, "issue created via Slack");
297
+ return `✅ Created <${url}|${issue?.identifier ?? "new issue"}>: *${cmd.title}*`;
298
+ }
299
+ catch (err) {
300
+ log.error({ err, title: cmd.title }, "create issue failed");
301
+ return `❌ Failed to create issue: ${err.message}`;
302
+ }
303
+ }
304
+ case "bulk_create": {
305
+ if (!deps.linearApiKey) {
306
+ return `⚠️ No Linear API key configured — cannot create issues.`;
307
+ }
308
+ if (!deps.teamIds || deps.teamIds.length === 0) {
309
+ return `⚠️ No team IDs configured — cannot create issues.`;
310
+ }
311
+ if (!deps.callClaudeSonnet) {
312
+ return `⚠️ Bulk create requires a Sonnet model caller — not configured.`;
313
+ }
314
+ try {
315
+ const specs = await analyzeBulkCreateRequest(cmd.request, deps.callClaudeSonnet);
316
+ if (specs.length === 0) {
317
+ return `🤔 Could not generate any issues from your request. Try being more specific.`;
318
+ }
319
+ const linear = await getLinear();
320
+ if (!linear)
321
+ return `⚠️ No Linear API key configured — cannot create issues.`;
322
+ // Resolve the Triage state and auto-implement label IDs
323
+ const teamId = deps.teamIds[0];
324
+ const [allStatesRes, allLabelsRes] = await Promise.all([
325
+ linear.workflowStates({ filter: { team: { id: { eq: teamId } } }, first: 50 }),
326
+ linear.issueLabels({ first: 100 }),
327
+ ]);
328
+ const triageState = allStatesRes.nodes?.find((s) => s.name === LINEAR_STATE_TRIAGE);
329
+ const labelMap = new Map();
330
+ for (const label of allLabelsRes.nodes ?? []) {
331
+ labelMap.set(label.name.toLowerCase(), label.id);
332
+ }
333
+ const autoImplementLabelId = labelMap.get(LINEAR_LABEL_AUTO_IMPLEMENT);
334
+ // Build all payloads first, then create all issues in parallel
335
+ const payloads = specs.map((spec) => {
336
+ const descWithCriteria = spec.acceptanceCriteria.length > 0
337
+ ? `${spec.description}\n\n**Acceptance Criteria:**\n${spec.acceptanceCriteria.map((c) => `- [ ] ${c}`).join("\n")}`
338
+ : spec.description;
339
+ const payload = {
340
+ teamId,
341
+ title: spec.title,
342
+ description: descWithCriteria || undefined,
343
+ priority: spec.priority,
344
+ };
345
+ if (triageState)
346
+ payload.stateId = triageState.id;
347
+ if (autoImplementLabelId)
348
+ payload.labelIds = [autoImplementLabelId];
349
+ return payload;
350
+ });
351
+ const results = await Promise.all(payloads.map((p) => linear.createIssue(p)));
352
+ const issueObjects = await Promise.all(results.map((r) => r.issue));
353
+ const created = [];
354
+ for (let i = 0; i < issueObjects.length; i++) {
355
+ const issue = issueObjects[i];
356
+ if (issue) {
357
+ const title = specs[i].title;
358
+ created.push({ identifier: issue.identifier ?? "", url: issue.url ?? "", title });
359
+ log.info({ issueId: issue.identifier, title }, "bulk issue created via Slack");
360
+ }
361
+ }
362
+ if (created.length === 0) {
363
+ return `❌ Failed to create any issues.`;
364
+ }
365
+ const lines = [`✅ Created ${created.length} issue${created.length === 1 ? "" : "s"}:`];
366
+ for (const issue of created) {
367
+ const link = issue.url ? `<${issue.url}|${issue.identifier}>` : `*${issue.identifier}*`;
368
+ lines.push(`• ${link}: *${issue.title}*`);
369
+ }
370
+ return lines.join("\n");
371
+ }
372
+ catch (err) {
373
+ log.error({ err, request: cmd.request }, "bulk create failed");
374
+ return `❌ Failed to create issues: ${err.message}`;
375
+ }
376
+ }
377
+ case "unknown":
378
+ return `🤔 I didn't understand that. Try:\n• \`/pm status\`\n• \`/pm prioritize BEC-25\`\n• \`/pm create "title" "description"\`\n• \`/pm assign BEC-13\`\n• \`/pm pause\` / \`/pm resume\``;
379
+ default:
380
+ return `Unknown command.`;
381
+ }
382
+ }
383
+ // ---------------------------------------------------------------------------
384
+ // Outbound notifications (PM Agent → Slack)
385
+ // ---------------------------------------------------------------------------
386
+ export class SlackInterfaceNotifier {
387
+ botToken;
388
+ channelId;
389
+ constructor(config) {
390
+ this.botToken = config.botToken;
391
+ this.channelId = config.channelId;
392
+ }
393
+ /** Called when PM Agent promotes an issue to Todo. */
394
+ async notifyAssigned(n) {
395
+ const urlPart = n.issueUrl ? `<${n.issueUrl}|${n.issueId}>` : `*${n.issueId}*`;
396
+ const text = `🤖 *PM Agent assigned* ${urlPart}: ${n.issueTitle}\n` +
397
+ `*Reasoning:* ${n.reasoning}`;
398
+ await this.postMessage({ channel: this.channelId, blocks: [{ type: "section", text: { type: "mrkdwn", text } }] });
399
+ }
400
+ /** Called when PM Agent skips/deprioritizes an issue. */
401
+ async notifySkipped(n) {
402
+ const text = `⏭ *PM Agent skipped* *${n.issueId}*: ${n.issueTitle}\n` +
403
+ `*Reason:* ${n.reasoning}`;
404
+ await this.postMessage({ channel: this.channelId, blocks: [{ type: "section", text: { type: "mrkdwn", text } }] });
405
+ }
406
+ /** Ask a human for input when priority is ambiguous. */
407
+ async askForClarification(question) {
408
+ const text = `❓ *PM Agent needs your input:*\n${question}`;
409
+ await this.postMessage({ channel: this.channelId, blocks: [{ type: "section", text: { type: "mrkdwn", text } }] });
410
+ }
411
+ /** Post a daily summary of assigned, completed, and blocked issues. */
412
+ async postDailySummary(entries, date) {
413
+ const label = date ?? new Date().toLocaleDateString("en-US", { weekday: "long", month: "long", day: "numeric" });
414
+ const lines = [`📊 *PM Agent Daily Summary — ${label}*`, ""];
415
+ const assigned = entries.filter((e) => e.status === "assigned");
416
+ const completed = entries.filter((e) => e.status === "completed");
417
+ const blocked = entries.filter((e) => e.status === "blocked");
418
+ if (assigned.length > 0) {
419
+ lines.push(`*Assigned (${assigned.length}):*`);
420
+ for (const e of assigned)
421
+ lines.push(` • *${e.issueId}* — ${e.issueTitle}`);
422
+ }
423
+ if (completed.length > 0) {
424
+ lines.push(`*Completed (${completed.length}):*`);
425
+ for (const e of completed)
426
+ lines.push(` • *${e.issueId}* — ${e.issueTitle}`);
427
+ }
428
+ if (blocked.length > 0) {
429
+ lines.push(`*Blocked (${blocked.length}):*`);
430
+ for (const e of blocked)
431
+ lines.push(` • *${e.issueId}* — ${e.issueTitle}`);
432
+ }
433
+ if (entries.length === 0) {
434
+ lines.push("No activity today.");
435
+ }
436
+ await this.postMessage({
437
+ channel: this.channelId,
438
+ blocks: [{ type: "section", text: { type: "mrkdwn", text: lines.join("\n") } }],
439
+ });
440
+ }
441
+ async postMessage(payload) {
442
+ await postSlackMessage(this.botToken, payload);
443
+ }
444
+ }
445
+ // ---------------------------------------------------------------------------
446
+ // Hono router factory
447
+ // ---------------------------------------------------------------------------
448
+ /**
449
+ * Creates a Hono router that handles Slack slash commands and Events API
450
+ * messages for the PM Agent.
451
+ *
452
+ * Mount it in your app:
453
+ * const { router } = createSlackInterface(config);
454
+ * app.route("/", router);
455
+ *
456
+ * The router registers:
457
+ * POST /slack/commands — Slack slash command handler
458
+ * POST /slack/events — Slack Events API handler
459
+ */
460
+ export function createSlackInterface(config) {
461
+ const router = new Hono();
462
+ const notifier = new SlackInterfaceNotifier(config);
463
+ const callClaude = config.callClaude ?? makeCallClaude();
464
+ const callClaudeSonnet = config.callClaudeSonnet ?? makeCallClaudeSonnet();
465
+ const executorDeps = {
466
+ linearApiKey: config.linearApiKey,
467
+ teamIds: config.teamIds,
468
+ callClaudeSonnet,
469
+ };
470
+ // Helper: verify Slack signature and return 401 on failure
471
+ async function checkSignature(c) {
472
+ const rawBody = await c.req.text();
473
+ const timestamp = c.req.header("X-Slack-Request-Timestamp") ?? "";
474
+ const signature = c.req.header("X-Slack-Signature") ?? "";
475
+ const valid = await verifySlackSignature(rawBody, timestamp, signature, config.signingSecret);
476
+ if (!valid)
477
+ return null;
478
+ return rawBody;
479
+ }
480
+ // ------------------------------------------------------------------
481
+ // POST /slack/commands
482
+ // ------------------------------------------------------------------
483
+ router.post("/slack/commands", async (c) => {
484
+ const rawBody = await checkSignature(c);
485
+ if (rawBody === null) {
486
+ return c.json({ error: "Invalid signature" }, 401);
487
+ }
488
+ // Parse URL-encoded form body
489
+ const params = new URLSearchParams(rawBody);
490
+ const commandText = (params.get("text") ?? "").trim();
491
+ const responseUrl = params.get("response_url") ?? "";
492
+ log.info({ commandText }, "received Slack slash command");
493
+ let cmd = parsePmCommand(commandText);
494
+ // Fall back to NL interpretation if command is unknown
495
+ if (cmd.type === "unknown" && commandText.length > 0) {
496
+ cmd = await interpretNaturalLanguage(commandText, callClaude);
497
+ }
498
+ const replyText = await executePmCommand(cmd, executorDeps);
499
+ // If a response_url is provided, post back asynchronously
500
+ if (responseUrl) {
501
+ postToResponseUrl(responseUrl, replyText).catch((err) => log.error({ err }, "failed to post to Slack response_url"));
502
+ }
503
+ // Immediate acknowledgement (required within 3s)
504
+ return c.json({ response_type: "ephemeral", text: replyText });
505
+ });
506
+ // ------------------------------------------------------------------
507
+ // POST /slack/events
508
+ // ------------------------------------------------------------------
509
+ router.post("/slack/events", async (c) => {
510
+ // Slack sends url_verification during setup — must respond with challenge.
511
+ // We peek at the body first; if it's a challenge, respond immediately.
512
+ // For all other events, verify the signature.
513
+ const rawBody = await c.req.text();
514
+ let body;
515
+ try {
516
+ body = JSON.parse(rawBody);
517
+ }
518
+ catch {
519
+ return c.json({ error: "Invalid JSON" }, 400);
520
+ }
521
+ // URL verification challenge — respond before signature check
522
+ // (Slack sends this once during Event Subscriptions setup)
523
+ if (body.type === "url_verification") {
524
+ return c.json({ challenge: body.challenge });
525
+ }
526
+ // Verify signature for all real events
527
+ const timestamp = c.req.header("X-Slack-Request-Timestamp") ?? "";
528
+ const signature = c.req.header("X-Slack-Signature") ?? "";
529
+ const valid = await verifySlackSignature(rawBody, timestamp, signature, config.signingSecret);
530
+ if (!valid) {
531
+ return c.json({ error: "Invalid signature" }, 401);
532
+ }
533
+ // Handle event callbacks
534
+ if (body.type === "event_callback") {
535
+ const event = body.event ?? {};
536
+ // Only handle direct messages or mentions in the PM channel
537
+ if (event.type === "app_mention" || event.type === "message") {
538
+ // Skip bot messages to avoid loops
539
+ if (event.bot_id || event.subtype === "bot_message") {
540
+ return c.json({ ok: true });
541
+ }
542
+ const messageText = (event.text ?? "").replace(/<@[A-Z0-9]+>/g, "").trim();
543
+ if (!messageText)
544
+ return c.json({ ok: true });
545
+ log.info({ messageText }, "received Slack message event");
546
+ // Process asynchronously — acknowledge immediately
547
+ processMessageAsync(messageText, event.channel ?? config.channelId, config.botToken, callClaude, executorDeps)
548
+ .catch((err) => log.error({ err }, "async message processing failed"));
549
+ }
550
+ }
551
+ return c.json({ ok: true });
552
+ });
553
+ return { router, notifier };
554
+ }
555
+ // ---------------------------------------------------------------------------
556
+ // Internal helpers
557
+ // ---------------------------------------------------------------------------
558
+ /**
559
+ * Uses a capable Claude model (Sonnet) to analyze a bulk create request and
560
+ * produce a structured list of issue specifications.
561
+ */
562
+ export async function analyzeBulkCreateRequest(request, callClaudeSonnet) {
563
+ const safe = sanitize(request);
564
+ const prompt = `You are a software PM Agent. A user asked: "${safe}"\n\n` +
565
+ `Analyze this request and generate a list of concrete, actionable software issues to create.\n` +
566
+ `Each issue must have a clear title, description, priority (1=urgent, 2=high, 3=medium, 4=low), and acceptance criteria.\n\n` +
567
+ `Respond ONLY with a JSON array (no other text), e.g.:\n` +
568
+ `[\n` +
569
+ ` {\n` +
570
+ ` "title": "Issue title",\n` +
571
+ ` "description": "Clear description of what needs to be done",\n` +
572
+ ` "priority": 2,\n` +
573
+ ` "acceptanceCriteria": ["Criterion 1", "Criterion 2"]\n` +
574
+ ` }\n` +
575
+ `]\n\n` +
576
+ `Rules:\n` +
577
+ `- Generate between 1 and 10 issues\n` +
578
+ `- Each issue must be specific and actionable\n` +
579
+ `- Priority must be 1, 2, 3, or 4\n` +
580
+ `- acceptanceCriteria must be a non-empty array of strings\n` +
581
+ `- Respond ONLY with the JSON array, no markdown fences or explanation`;
582
+ try {
583
+ const raw = await callClaudeSonnet(prompt);
584
+ // Parse the array — look for a JSON array in the response
585
+ const arrayMatch = raw.match(/\[[\s\S]*\]/);
586
+ if (!arrayMatch) {
587
+ log.warn({ responsePreview: raw.slice(0, 200) }, "bulk create: no JSON array in Claude response");
588
+ return [];
589
+ }
590
+ let parsed;
591
+ try {
592
+ parsed = JSON.parse(arrayMatch[0]);
593
+ }
594
+ catch {
595
+ log.warn({ responsePreview: raw.slice(0, 200) }, "bulk create: failed to parse JSON array");
596
+ return [];
597
+ }
598
+ if (!Array.isArray(parsed))
599
+ return [];
600
+ const specs = [];
601
+ for (const item of parsed) {
602
+ if (typeof item !== "object" || item === null)
603
+ continue;
604
+ const title = typeof item.title === "string" ? item.title.trim() : "";
605
+ const description = typeof item.description === "string" ? item.description.trim() : "";
606
+ const priority = typeof item.priority === "number" && VALID_PRIORITIES.includes(item.priority)
607
+ ? item.priority
608
+ : DEFAULT_PRIORITY;
609
+ const acceptanceCriteria = Array.isArray(item.acceptanceCriteria)
610
+ ? item.acceptanceCriteria.filter((c) => typeof c === "string" && c.trim().length > 0)
611
+ : [];
612
+ if (!title)
613
+ continue;
614
+ // Cap title/description length to prevent excessively large issues
615
+ specs.push({
616
+ title: title.slice(0, 200),
617
+ description: description.slice(0, 5000),
618
+ priority,
619
+ acceptanceCriteria: acceptanceCriteria.slice(0, 10),
620
+ });
621
+ }
622
+ return specs.slice(0, 10);
623
+ }
624
+ catch (err) {
625
+ log.warn({ err }, "bulk create: failed to analyze request");
626
+ return [];
627
+ }
628
+ }
629
+ async function postToResponseUrl(responseUrl, text) {
630
+ await fetch(responseUrl, {
631
+ method: "POST",
632
+ headers: { "Content-Type": "application/json" },
633
+ body: JSON.stringify({ response_type: "ephemeral", text }),
634
+ });
635
+ }
636
+ async function processMessageAsync(text, channel, botToken, callClaude, deps) {
637
+ const cmd = await interpretNaturalLanguage(text, callClaude);
638
+ const replyText = await executePmCommand(cmd, deps);
639
+ await postSlackMessage(botToken, { channel, text: replyText });
640
+ }
641
+ //# sourceMappingURL=slack-interface.js.map