edsger 0.49.0 → 0.51.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 (329) hide show
  1. package/README.md +25 -25
  2. package/dist/api/chat.d.ts +7 -7
  3. package/dist/api/chat.js +13 -13
  4. package/dist/api/cross-product.d.ts +10 -10
  5. package/dist/api/cross-product.js +30 -30
  6. package/dist/api/github.d.ts +5 -5
  7. package/dist/api/github.js +10 -10
  8. package/dist/api/intelligence.d.ts +3 -3
  9. package/dist/api/issues/approval-checker.d.ts +20 -0
  10. package/dist/api/issues/approval-checker.js +152 -0
  11. package/dist/api/issues/batch-operations.d.ts +17 -0
  12. package/dist/api/issues/batch-operations.js +100 -0
  13. package/dist/api/issues/get-issue.d.ts +5 -0
  14. package/dist/api/issues/get-issue.js +21 -0
  15. package/dist/api/issues/index.d.ts +8 -0
  16. package/dist/api/issues/index.js +10 -0
  17. package/dist/api/issues/issue-utils.d.ts +23 -0
  18. package/dist/api/issues/issue-utils.js +80 -0
  19. package/dist/api/issues/status-updater.d.ts +41 -0
  20. package/dist/api/issues/status-updater.js +122 -0
  21. package/dist/api/issues/test-cases.d.ts +29 -0
  22. package/dist/api/issues/test-cases.js +110 -0
  23. package/dist/api/issues/update-issue.d.ts +20 -0
  24. package/dist/api/issues/update-issue.js +83 -0
  25. package/dist/api/issues/user-stories.d.ts +21 -0
  26. package/dist/api/issues/user-stories.js +88 -0
  27. package/dist/api/products.d.ts +1 -1
  28. package/dist/api/tasks.d.ts +1 -1
  29. package/dist/api/test-reports.d.ts +2 -2
  30. package/dist/api/test-reports.js +4 -4
  31. package/dist/auth/login.js +1 -1
  32. package/dist/commands/agent-workflow/chat-worker.d.ts +7 -7
  33. package/dist/commands/agent-workflow/chat-worker.js +50 -50
  34. package/dist/commands/agent-workflow/index.d.ts +2 -2
  35. package/dist/commands/agent-workflow/index.js +3 -3
  36. package/dist/commands/agent-workflow/issue-worker.d.ts +14 -0
  37. package/dist/commands/agent-workflow/issue-worker.js +65 -0
  38. package/dist/commands/agent-workflow/processor.d.ts +9 -9
  39. package/dist/commands/agent-workflow/processor.js +90 -90
  40. package/dist/commands/build/index.js +2 -2
  41. package/dist/commands/find-bugs/index.d.ts +11 -0
  42. package/dist/commands/find-bugs/index.js +39 -0
  43. package/dist/commands/find-features/index.d.ts +14 -0
  44. package/dist/commands/find-features/index.js +42 -0
  45. package/dist/commands/init/prompts.js +1 -1
  46. package/dist/commands/init/templates.d.ts +1 -1
  47. package/dist/commands/init/templates.js +4 -4
  48. package/dist/commands/workflow/config/phase-configs.js +17 -17
  49. package/dist/commands/workflow/core/index.d.ts +1 -1
  50. package/dist/commands/workflow/core/index.js +2 -2
  51. package/dist/commands/workflow/core/issue-filter.d.ts +16 -0
  52. package/dist/commands/workflow/core/issue-filter.js +47 -0
  53. package/dist/commands/workflow/core/state-manager.d.ts +10 -10
  54. package/dist/commands/workflow/core/state-manager.js +10 -10
  55. package/dist/commands/workflow/core/workflow-logger.d.ts +9 -9
  56. package/dist/commands/workflow/core/workflow-logger.js +21 -21
  57. package/dist/commands/workflow/executors/phase-executor.d.ts +2 -2
  58. package/dist/commands/workflow/executors/phase-executor.js +32 -32
  59. package/dist/commands/workflow/issue-coordinator.d.ts +18 -0
  60. package/dist/commands/workflow/issue-coordinator.js +161 -0
  61. package/dist/commands/workflow/phase-orchestrator.d.ts +2 -2
  62. package/dist/commands/workflow/phase-orchestrator.js +82 -82
  63. package/dist/commands/workflow/processor.d.ts +7 -7
  64. package/dist/commands/workflow/processor.js +44 -44
  65. package/dist/config/issue-status.d.ts +56 -0
  66. package/dist/config/issue-status.js +130 -0
  67. package/dist/errors/index.d.ts +6 -6
  68. package/dist/errors/index.js +11 -11
  69. package/dist/index.js +61 -1
  70. package/dist/phases/app-store-generation/context.js +6 -6
  71. package/dist/phases/app-store-generation/index.js +2 -2
  72. package/dist/phases/app-store-generation/prompts.js +2 -2
  73. package/dist/phases/autonomous/index.d.ts +3 -3
  74. package/dist/phases/autonomous/index.js +37 -37
  75. package/dist/phases/autonomous/prompts.d.ts +2 -2
  76. package/dist/phases/autonomous/prompts.js +4 -4
  77. package/dist/phases/branch-planning/context.d.ts +3 -3
  78. package/dist/phases/branch-planning/context.js +12 -12
  79. package/dist/phases/branch-planning/index.d.ts +3 -3
  80. package/dist/phases/branch-planning/index.js +32 -32
  81. package/dist/phases/branch-planning/outcome.d.ts +5 -5
  82. package/dist/phases/branch-planning/outcome.js +12 -12
  83. package/dist/phases/branch-planning/prompts.d.ts +3 -3
  84. package/dist/phases/branch-planning/prompts.js +13 -13
  85. package/dist/phases/bug-fixing/analyzer.d.ts +2 -2
  86. package/dist/phases/bug-fixing/analyzer.js +13 -13
  87. package/dist/phases/bug-fixing/context-fetcher.d.ts +3 -3
  88. package/dist/phases/bug-fixing/context-fetcher.js +18 -18
  89. package/dist/phases/bug-fixing/mcp-server.js +17 -18
  90. package/dist/phases/chat-processor/context.d.ts +5 -5
  91. package/dist/phases/chat-processor/context.js +17 -17
  92. package/dist/phases/chat-processor/index.d.ts +4 -4
  93. package/dist/phases/chat-processor/index.js +17 -17
  94. package/dist/phases/chat-processor/product-context.d.ts +3 -3
  95. package/dist/phases/chat-processor/product-context.js +16 -16
  96. package/dist/phases/chat-processor/product-prompts.d.ts +1 -1
  97. package/dist/phases/chat-processor/product-prompts.js +10 -10
  98. package/dist/phases/chat-processor/product-tools.d.ts +2 -2
  99. package/dist/phases/chat-processor/product-tools.js +33 -33
  100. package/dist/phases/chat-processor/prompts.d.ts +3 -3
  101. package/dist/phases/chat-processor/prompts.js +22 -22
  102. package/dist/phases/chat-processor/tools.js +46 -46
  103. package/dist/phases/code-implementation/branch-pr-creator.d.ts +3 -3
  104. package/dist/phases/code-implementation/branch-pr-creator.js +5 -5
  105. package/dist/phases/code-implementation/context.d.ts +3 -3
  106. package/dist/phases/code-implementation/context.js +18 -18
  107. package/dist/phases/code-implementation/index.d.ts +4 -4
  108. package/dist/phases/code-implementation/index.js +88 -88
  109. package/dist/phases/code-implementation/outcome.d.ts +3 -3
  110. package/dist/phases/code-implementation/outcome.js +6 -6
  111. package/dist/phases/code-implementation/prompts.d.ts +1 -1
  112. package/dist/phases/code-implementation/prompts.js +6 -6
  113. package/dist/phases/code-implementation-verification/agent.d.ts +3 -3
  114. package/dist/phases/code-implementation-verification/agent.js +5 -5
  115. package/dist/phases/code-implementation-verification/index.d.ts +3 -3
  116. package/dist/phases/code-implementation-verification/index.js +11 -11
  117. package/dist/phases/code-implementation-verification/prompts.d.ts +3 -3
  118. package/dist/phases/code-implementation-verification/prompts.js +7 -7
  119. package/dist/phases/code-refine/context.d.ts +8 -8
  120. package/dist/phases/code-refine/context.js +29 -29
  121. package/dist/phases/code-refine/index.d.ts +2 -2
  122. package/dist/phases/code-refine/index.js +20 -20
  123. package/dist/phases/code-refine/prompts.d.ts +1 -1
  124. package/dist/phases/code-refine/prompts.js +3 -3
  125. package/dist/phases/code-refine/refine-iteration.d.ts +1 -1
  126. package/dist/phases/code-refine/refine-iteration.js +4 -4
  127. package/dist/phases/code-refine/retry-handler.js +2 -2
  128. package/dist/phases/code-refine-verification/github.d.ts +16 -0
  129. package/dist/phases/code-refine-verification/github.js +118 -32
  130. package/dist/phases/code-refine-verification/index.js +10 -10
  131. package/dist/phases/code-refine-verification/types.d.ts +17 -12
  132. package/dist/phases/code-review/context.d.ts +8 -8
  133. package/dist/phases/code-review/context.js +25 -25
  134. package/dist/phases/code-review/diff-utils.d.ts +1 -1
  135. package/dist/phases/code-review/diff-utils.js +1 -1
  136. package/dist/phases/code-review/index.d.ts +2 -2
  137. package/dist/phases/code-review/index.js +26 -26
  138. package/dist/phases/code-testing/analyzer.d.ts +2 -2
  139. package/dist/phases/code-testing/analyzer.js +18 -18
  140. package/dist/phases/code-testing/context-fetcher.d.ts +3 -3
  141. package/dist/phases/code-testing/context-fetcher.js +16 -16
  142. package/dist/phases/code-testing/prompts.d.ts +1 -1
  143. package/dist/phases/code-testing/prompts.js +5 -5
  144. package/dist/phases/find-bugs/index.d.ts +30 -0
  145. package/dist/phases/find-bugs/index.js +301 -0
  146. package/dist/phases/find-bugs/prompts.d.ts +22 -0
  147. package/dist/phases/find-bugs/prompts.js +101 -0
  148. package/dist/phases/find-bugs/state.d.ts +44 -0
  149. package/dist/phases/find-bugs/state.js +121 -0
  150. package/dist/phases/find-bugs/types.d.ts +21 -0
  151. package/dist/phases/find-bugs/types.js +16 -0
  152. package/dist/phases/find-features/index.d.ts +40 -0
  153. package/dist/phases/find-features/index.js +346 -0
  154. package/dist/phases/find-features/prompts.d.ts +37 -0
  155. package/dist/phases/find-features/prompts.js +118 -0
  156. package/dist/phases/find-features/state.d.ts +29 -0
  157. package/dist/phases/find-features/state.js +94 -0
  158. package/dist/phases/find-features/types.d.ts +27 -0
  159. package/dist/phases/find-features/types.js +16 -0
  160. package/dist/phases/functional-testing/analyzer.d.ts +2 -2
  161. package/dist/phases/functional-testing/analyzer.js +40 -40
  162. package/dist/phases/functional-testing/context-fetcher.d.ts +3 -3
  163. package/dist/phases/functional-testing/context-fetcher.js +16 -16
  164. package/dist/phases/functional-testing/http-fallback.d.ts +2 -2
  165. package/dist/phases/functional-testing/http-fallback.js +9 -9
  166. package/dist/phases/functional-testing/mcp-server.js +23 -24
  167. package/dist/phases/functional-testing/prompts.d.ts +1 -1
  168. package/dist/phases/functional-testing/prompts.js +4 -4
  169. package/dist/phases/functional-testing/test-report-creator.d.ts +2 -2
  170. package/dist/phases/functional-testing/test-report-creator.js +10 -10
  171. package/dist/phases/functional-testing/test-retry-handler.js +3 -3
  172. package/dist/phases/growth-analysis/context.js +6 -6
  173. package/dist/phases/growth-analysis/index.js +2 -2
  174. package/dist/phases/growth-analysis/prompts.js +2 -2
  175. package/dist/phases/intelligence-analysis/context.js +7 -7
  176. package/dist/phases/intelligence-analysis/index.js +3 -3
  177. package/dist/phases/issue-analysis/agent.d.ts +13 -0
  178. package/dist/phases/issue-analysis/agent.js +112 -0
  179. package/dist/phases/issue-analysis/context.d.ts +24 -0
  180. package/dist/phases/issue-analysis/context.js +138 -0
  181. package/dist/phases/issue-analysis/index.d.ts +8 -0
  182. package/dist/phases/issue-analysis/index.js +199 -0
  183. package/dist/phases/issue-analysis/outcome.d.ts +40 -0
  184. package/dist/phases/issue-analysis/outcome.js +280 -0
  185. package/dist/phases/issue-analysis/prompts.d.ts +10 -0
  186. package/dist/phases/issue-analysis/prompts.js +212 -0
  187. package/dist/phases/issue-analysis-verification/agent.d.ts +33 -0
  188. package/dist/phases/issue-analysis-verification/agent.js +124 -0
  189. package/dist/phases/issue-analysis-verification/index.d.ts +25 -0
  190. package/dist/phases/issue-analysis-verification/index.js +92 -0
  191. package/dist/phases/issue-analysis-verification/prompts.d.ts +10 -0
  192. package/dist/phases/issue-analysis-verification/prompts.js +100 -0
  193. package/dist/phases/output-contracts.js +37 -37
  194. package/dist/phases/pr-execution/context.d.ts +3 -3
  195. package/dist/phases/pr-execution/context.js +14 -14
  196. package/dist/phases/pr-execution/index.d.ts +2 -2
  197. package/dist/phases/pr-execution/index.js +22 -22
  198. package/dist/phases/pr-execution/outcome.d.ts +4 -4
  199. package/dist/phases/pr-execution/outcome.js +6 -6
  200. package/dist/phases/pr-execution/prompts.d.ts +4 -4
  201. package/dist/phases/pr-execution/prompts.js +6 -6
  202. package/dist/phases/pr-resolve/checklist-learner.js +2 -2
  203. package/dist/phases/pr-review/index.d.ts +1 -1
  204. package/dist/phases/pr-review/index.js +1 -1
  205. package/dist/phases/pr-review/prompts.d.ts +1 -1
  206. package/dist/phases/pr-review/prompts.js +1 -1
  207. package/dist/phases/pr-shared/context.d.ts +3 -3
  208. package/dist/phases/pr-shared/context.js +3 -3
  209. package/dist/phases/pr-splitting/context.d.ts +3 -3
  210. package/dist/phases/pr-splitting/context.js +16 -16
  211. package/dist/phases/pr-splitting/index.d.ts +4 -4
  212. package/dist/phases/pr-splitting/index.js +29 -29
  213. package/dist/phases/pr-splitting/outcome.d.ts +3 -3
  214. package/dist/phases/pr-splitting/outcome.js +7 -7
  215. package/dist/phases/pr-splitting/prompts.d.ts +3 -3
  216. package/dist/phases/pr-splitting/prompts.js +11 -11
  217. package/dist/phases/pull-request/creator.d.ts +4 -4
  218. package/dist/phases/pull-request/creator.js +25 -25
  219. package/dist/phases/pull-request/handler.d.ts +3 -3
  220. package/dist/phases/pull-request/handler.js +16 -16
  221. package/dist/phases/release-sync/index.js +2 -2
  222. package/dist/phases/run-sheet/agent.js +1 -2
  223. package/dist/phases/run-sheet/index.js +3 -3
  224. package/dist/phases/smoke-test/index.js +2 -2
  225. package/dist/phases/technical-design/context.d.ts +3 -3
  226. package/dist/phases/technical-design/context.js +11 -11
  227. package/dist/phases/technical-design/index.d.ts +2 -2
  228. package/dist/phases/technical-design/index.js +27 -27
  229. package/dist/phases/technical-design/outcome.d.ts +4 -4
  230. package/dist/phases/technical-design/outcome.js +6 -6
  231. package/dist/phases/technical-design/prompts.d.ts +2 -2
  232. package/dist/phases/technical-design/prompts.js +10 -10
  233. package/dist/phases/technical-design-verification/agent.d.ts +3 -3
  234. package/dist/phases/technical-design-verification/agent.js +4 -4
  235. package/dist/phases/technical-design-verification/index.d.ts +4 -4
  236. package/dist/phases/technical-design-verification/index.js +12 -12
  237. package/dist/phases/technical-design-verification/prompts.d.ts +3 -3
  238. package/dist/phases/technical-design-verification/prompts.js +6 -6
  239. package/dist/phases/test-cases-analysis/context.d.ts +5 -5
  240. package/dist/phases/test-cases-analysis/context.js +18 -18
  241. package/dist/phases/test-cases-analysis/formatters.js +7 -7
  242. package/dist/phases/test-cases-analysis/index.d.ts +1 -1
  243. package/dist/phases/test-cases-analysis/index.js +21 -21
  244. package/dist/phases/test-cases-analysis/outcome.d.ts +7 -7
  245. package/dist/phases/test-cases-analysis/outcome.js +13 -13
  246. package/dist/phases/test-cases-analysis/prompts.d.ts +3 -3
  247. package/dist/phases/test-cases-analysis/prompts.js +6 -6
  248. package/dist/phases/user-stories-analysis/context.d.ts +5 -5
  249. package/dist/phases/user-stories-analysis/context.js +18 -18
  250. package/dist/phases/user-stories-analysis/formatters.js +7 -7
  251. package/dist/phases/user-stories-analysis/index.d.ts +1 -1
  252. package/dist/phases/user-stories-analysis/index.js +21 -21
  253. package/dist/phases/user-stories-analysis/outcome.d.ts +7 -7
  254. package/dist/phases/user-stories-analysis/outcome.js +13 -13
  255. package/dist/phases/user-stories-analysis/prompts.d.ts +3 -3
  256. package/dist/phases/user-stories-analysis/prompts.js +10 -10
  257. package/dist/services/audit-logs.d.ts +10 -10
  258. package/dist/services/audit-logs.js +12 -12
  259. package/dist/services/branches.d.ts +6 -6
  260. package/dist/services/branches.js +16 -16
  261. package/dist/services/checklist.d.ts +3 -3
  262. package/dist/services/checklist.js +11 -11
  263. package/dist/services/coaching/coaching-agent.js +2 -2
  264. package/dist/services/coaching/coaching-loop.d.ts +1 -1
  265. package/dist/services/coaching/coaching-loop.js +2 -2
  266. package/dist/services/coaching/phase-coaching.d.ts +2 -2
  267. package/dist/services/coaching/phase-coaching.js +3 -3
  268. package/dist/services/coaching/self-rating.js +1 -1
  269. package/dist/services/feedbacks.d.ts +4 -4
  270. package/dist/services/feedbacks.js +8 -8
  271. package/dist/services/phase-hooks/bindings-fetcher.d.ts +4 -4
  272. package/dist/services/phase-hooks/bindings-fetcher.js +8 -8
  273. package/dist/services/phase-hooks/hook-executor.js +1 -1
  274. package/dist/services/phase-hooks/hook-logging.d.ts +2 -2
  275. package/dist/services/phase-hooks/hook-logging.js +4 -4
  276. package/dist/services/phase-hooks/hook-runner.d.ts +1 -1
  277. package/dist/services/phase-hooks/hook-runner.js +4 -4
  278. package/dist/services/phase-hooks/types.d.ts +3 -3
  279. package/dist/services/phase-ratings.d.ts +7 -7
  280. package/dist/services/phase-ratings.js +8 -8
  281. package/dist/services/pull-requests.d.ts +4 -4
  282. package/dist/services/pull-requests.js +11 -11
  283. package/dist/services/skill-resolver.d.ts +1 -1
  284. package/dist/services/skill-resolver.js +1 -1
  285. package/dist/skills/phase/app-store-generation/SKILL.md +9 -9
  286. package/dist/skills/phase/autonomous/SKILL.md +2 -2
  287. package/dist/skills/phase/branch-planning/SKILL.md +12 -12
  288. package/dist/skills/phase/bug-fixing/SKILL.md +1 -1
  289. package/dist/skills/phase/code-implementation/SKILL.md +6 -6
  290. package/dist/skills/phase/code-implementation-verification/SKILL.md +3 -3
  291. package/dist/skills/phase/code-testing/SKILL.md +5 -5
  292. package/dist/skills/phase/functional-testing/SKILL.md +3 -3
  293. package/dist/skills/phase/growth-analysis/SKILL.md +8 -8
  294. package/dist/skills/phase/incremental-sync/SKILL.md +6 -6
  295. package/dist/skills/phase/intelligence-analysis/SKILL.md +7 -7
  296. package/dist/skills/phase/{feature-analysis → issue-analysis}/SKILL.md +8 -8
  297. package/dist/skills/phase/pr-execution/SKILL.md +7 -7
  298. package/dist/skills/phase/pr-splitting/SKILL.md +14 -14
  299. package/dist/skills/phase/smoke-test/SKILL.md +1 -1
  300. package/dist/skills/phase/technical-design/SKILL.md +5 -5
  301. package/dist/skills/phase/test-cases-analysis/SKILL.md +4 -4
  302. package/dist/skills/phase/user-stories-analysis/SKILL.md +13 -13
  303. package/dist/system/session-manager.d.ts +3 -3
  304. package/dist/system/session-manager.js +3 -3
  305. package/dist/system/sleep-notification.js +2 -2
  306. package/dist/system/sleep-prevention.js +1 -1
  307. package/dist/types/index.d.ts +21 -21
  308. package/dist/types/issues.d.ts +35 -0
  309. package/dist/types/issues.js +1 -0
  310. package/dist/types/pipeline.d.ts +4 -4
  311. package/dist/updater/auto-updater.d.ts +2 -2
  312. package/dist/updater/auto-updater.js +3 -3
  313. package/dist/utils/conflict-resolver.d.ts +1 -1
  314. package/dist/utils/conflict-resolver.js +5 -5
  315. package/dist/utils/formatters.d.ts +4 -4
  316. package/dist/utils/formatters.js +29 -29
  317. package/dist/utils/git-branch-manager-async.d.ts +6 -6
  318. package/dist/utils/git-branch-manager-async.js +41 -41
  319. package/dist/utils/git-branch-manager.d.ts +11 -11
  320. package/dist/utils/git-branch-manager.js +42 -42
  321. package/dist/utils/image-downloader.d.ts +4 -4
  322. package/dist/utils/image-downloader.js +17 -17
  323. package/dist/utils/pipeline-logger.d.ts +1 -1
  324. package/dist/utils/pipeline-logger.js +5 -5
  325. package/dist/workspace/workspace-manager.d.ts +17 -17
  326. package/dist/workspace/workspace-manager.js +21 -21
  327. package/package.json +1 -1
  328. package/vitest.config.ts +10 -4
  329. /package/dist/skills/phase/{feature-analysis-verification → issue-analysis-verification}/SKILL.md +0 -0
@@ -0,0 +1,152 @@
1
+ /**
2
+ * Approval workflow integration for issue phases
3
+ * Checks if current issue status has been approved before executing next phase
4
+ */
5
+ import { logError, logInfo, logWarning } from '../../utils/logger.js';
6
+ import { callMcpEndpoint } from '../mcp-client.js';
7
+ import { getIssue } from './get-issue.js';
8
+ /**
9
+ * Check if current issue status has been approved before executing next phase
10
+ * This should be called BEFORE executing a phase, not after
11
+ *
12
+ * @param issueId - Issue ID
13
+ * @param verbose - Verbose logging
14
+ * @returns Promise<ApprovalCheckResult> - Whether the phase can proceed
15
+ */
16
+ export async function checkApprovalBeforePhaseExecution(issueId, verbose = false) {
17
+ try {
18
+ // 1. Get current issue to check its status and product_id
19
+ const issue = await getIssue(issueId, verbose);
20
+ const currentStatus = issue.status;
21
+ const productId = issue.product_id;
22
+ if (verbose) {
23
+ logInfo(`🔍 Checking approval for current status: ${currentStatus}`);
24
+ logInfo(`📦 Product ID: ${productId}`);
25
+ }
26
+ // 2. Check if current status requires approval
27
+ const requiresApprovalResult = (await callMcpEndpoint('approvals/requires_approval', {
28
+ product_id: productId,
29
+ issue_status: currentStatus,
30
+ }));
31
+ if (verbose) {
32
+ logInfo(`📋 MCP requires_approval response: ${JSON.stringify(requiresApprovalResult)}`);
33
+ }
34
+ const requiresApproval = requiresApprovalResult?.requires_approval === true;
35
+ if (!requiresApproval) {
36
+ if (verbose) {
37
+ logInfo(`✅ Current status ${currentStatus} does not require approval. Proceeding.`);
38
+ }
39
+ return {
40
+ canProceed: true,
41
+ requiresApproval: false,
42
+ };
43
+ }
44
+ // 3. Status requires approval - check if already approved
45
+ if (verbose) {
46
+ logInfo(`🔒 Current status ${currentStatus} requires approval`);
47
+ }
48
+ const existingApprovals = (await callMcpEndpoint('approvals/issue_approvals', {
49
+ issue_id: issueId,
50
+ }));
51
+ // Check if there's an approved approval for the current status
52
+ const approvedApproval = existingApprovals?.approvals?.find((approval) => approval.requested_status === currentStatus &&
53
+ approval.approval_status === 'approved');
54
+ if (approvedApproval) {
55
+ if (verbose) {
56
+ logInfo(`✅ Found approved approval for ${currentStatus}. Proceeding.`);
57
+ }
58
+ return {
59
+ canProceed: true,
60
+ requiresApproval: true,
61
+ approvalId: approvedApproval.id,
62
+ };
63
+ }
64
+ // Check if there's already a pending approval for current status
65
+ const pendingApproval = existingApprovals?.approvals?.find((approval) => approval.requested_status === currentStatus &&
66
+ approval.approval_status === 'pending');
67
+ if (pendingApproval) {
68
+ if (verbose) {
69
+ logWarning(`⏳ Approval already pending for ${currentStatus}. Waiting for review.`);
70
+ }
71
+ return {
72
+ canProceed: false,
73
+ requiresApproval: true,
74
+ approvalId: pendingApproval.id,
75
+ message: `Waiting for approval of current status: ${currentStatus}`,
76
+ };
77
+ }
78
+ // No pending or approved approval - need to create one
79
+ if (verbose) {
80
+ logInfo(`🔔 No approval exists for ${currentStatus}. Creating approval request...`);
81
+ }
82
+ // Create approval request
83
+ const approvalId = await createApprovalRequestWithEmail(issueId, productId, currentStatus, verbose);
84
+ if (approvalId) {
85
+ return {
86
+ canProceed: false,
87
+ requiresApproval: true,
88
+ approvalId,
89
+ message: `Approval request created for status: ${currentStatus}`,
90
+ };
91
+ }
92
+ logError('Failed to create approval request');
93
+ return {
94
+ canProceed: false,
95
+ requiresApproval: true,
96
+ message: `Failed to create approval request for status: ${currentStatus}`,
97
+ };
98
+ }
99
+ catch (error) {
100
+ const errorMessage = error instanceof Error ? error.message : String(error);
101
+ logError(`Error checking approval before phase execution: ${errorMessage}`);
102
+ // On error, block execution to be safe
103
+ return {
104
+ canProceed: false,
105
+ requiresApproval: true,
106
+ message: `Error checking approval: ${errorMessage}`,
107
+ };
108
+ }
109
+ }
110
+ /**
111
+ * Create an approval request (emails are sent automatically by the MCP handler)
112
+ * This is for the CURRENT status, not the next status
113
+ */
114
+ async function createApprovalRequestWithEmail(issueId, productId, currentStatus, verbose = false) {
115
+ try {
116
+ if (verbose) {
117
+ logInfo(`Creating approval request for current status: ${currentStatus}`);
118
+ }
119
+ // Create approval request via MCP endpoint
120
+ // Note: We're requesting approval for the current status
121
+ // The approval is asking: "Can we proceed from this status?"
122
+ // Email notifications are sent automatically by the MCP handler
123
+ const result = (await callMcpEndpoint('approvals/create', {
124
+ issue_id: issueId,
125
+ requested_status: currentStatus,
126
+ previous_status: null, // We're approving current status, not transitioning
127
+ }));
128
+ const approvalId = result?.approval_id;
129
+ if (!approvalId) {
130
+ logError('Failed to create approval request: No approval_id returned');
131
+ return null;
132
+ }
133
+ if (verbose) {
134
+ logInfo(`✅ Approval request created: ${approvalId}`);
135
+ // Log email results if available
136
+ if (result?.emails_sent) {
137
+ const sentCount = result.emails_sent.filter((e) => e.status === 'sent').length;
138
+ const failedCount = result.emails_sent.filter((e) => e.status !== 'sent').length;
139
+ logInfo(`📧 Sent approval emails to ${sentCount} assignee(s)`);
140
+ if (failedCount > 0) {
141
+ logWarning(`⚠️ Failed to send ${failedCount} email(s)`);
142
+ }
143
+ }
144
+ }
145
+ return approvalId;
146
+ }
147
+ catch (error) {
148
+ const errorMessage = error instanceof Error ? error.message : String(error);
149
+ logError(`Failed to create approval request: ${errorMessage}`);
150
+ return null;
151
+ }
152
+ }
@@ -0,0 +1,17 @@
1
+ import { type TestCaseStatus, type UserStoryStatus } from '../../types/index.js';
2
+ /**
3
+ * Batch update user story statuses
4
+ */
5
+ export declare function batchUpdateUserStoryStatus(userStoryIds: string[], status: UserStoryStatus, verbose?: boolean): Promise<boolean>;
6
+ /**
7
+ * Batch update test case statuses
8
+ */
9
+ export declare function batchUpdateTestCaseStatus(testCaseIds: string[], status: TestCaseStatus, verbose?: boolean): Promise<boolean>;
10
+ /**
11
+ * Batch delete user stories
12
+ */
13
+ export declare function batchDeleteUserStories(userStoryIds: string[], verbose?: boolean): Promise<boolean>;
14
+ /**
15
+ * Batch delete test cases
16
+ */
17
+ export declare function batchDeleteTestCases(testCaseIds: string[], verbose?: boolean): Promise<boolean>;
@@ -0,0 +1,100 @@
1
+ import { logError, logInfo } from '../../utils/logger.js';
2
+ import { callMcpEndpoint } from '../mcp-client.js';
3
+ /**
4
+ * Batch update user story statuses
5
+ */
6
+ export async function batchUpdateUserStoryStatus(userStoryIds, status, verbose) {
7
+ try {
8
+ if (verbose) {
9
+ logInfo(`Batch updating ${userStoryIds.length} user stories to status: ${status}`);
10
+ }
11
+ for (const id of userStoryIds) {
12
+ await callMcpEndpoint('user_stories/update_status', {
13
+ user_story_id: id,
14
+ status,
15
+ });
16
+ }
17
+ if (verbose) {
18
+ logInfo('✅ Batch user story status update completed');
19
+ }
20
+ return true;
21
+ }
22
+ catch (error) {
23
+ const errorMessage = error instanceof Error ? error.message : String(error);
24
+ logError(`Failed to batch update user story statuses: ${errorMessage}`);
25
+ return false;
26
+ }
27
+ }
28
+ /**
29
+ * Batch update test case statuses
30
+ */
31
+ export async function batchUpdateTestCaseStatus(testCaseIds, status, verbose) {
32
+ try {
33
+ if (verbose) {
34
+ logInfo(`Batch updating ${testCaseIds.length} test cases to status: ${status}`);
35
+ }
36
+ for (const id of testCaseIds) {
37
+ await callMcpEndpoint('test_cases/update_status', {
38
+ test_case_id: id,
39
+ status,
40
+ });
41
+ }
42
+ if (verbose) {
43
+ logInfo('✅ Batch test case status update completed');
44
+ }
45
+ return true;
46
+ }
47
+ catch (error) {
48
+ const errorMessage = error instanceof Error ? error.message : String(error);
49
+ logError(`Failed to batch update test case statuses: ${errorMessage}`);
50
+ return false;
51
+ }
52
+ }
53
+ /**
54
+ * Batch delete user stories
55
+ */
56
+ export async function batchDeleteUserStories(userStoryIds, verbose) {
57
+ try {
58
+ if (verbose) {
59
+ logInfo(`Batch deleting ${userStoryIds.length} user stories`);
60
+ }
61
+ for (const id of userStoryIds) {
62
+ await callMcpEndpoint('user_stories/delete', {
63
+ user_story_id: id,
64
+ });
65
+ }
66
+ if (verbose) {
67
+ logInfo('✅ Batch user story deletion completed');
68
+ }
69
+ return true;
70
+ }
71
+ catch (error) {
72
+ const errorMessage = error instanceof Error ? error.message : String(error);
73
+ logError(`Failed to batch delete user stories: ${errorMessage}`);
74
+ return false;
75
+ }
76
+ }
77
+ /**
78
+ * Batch delete test cases
79
+ */
80
+ export async function batchDeleteTestCases(testCaseIds, verbose) {
81
+ try {
82
+ if (verbose) {
83
+ logInfo(`Batch deleting ${testCaseIds.length} test cases`);
84
+ }
85
+ for (const id of testCaseIds) {
86
+ await callMcpEndpoint('test_cases/delete', {
87
+ test_case_id: id,
88
+ });
89
+ }
90
+ if (verbose) {
91
+ logInfo('✅ Batch test case deletion completed');
92
+ }
93
+ return true;
94
+ }
95
+ catch (error) {
96
+ const errorMessage = error instanceof Error ? error.message : String(error);
97
+ logError(`Failed to batch delete test cases: ${errorMessage}`);
98
+ return false;
99
+ }
100
+ }
@@ -0,0 +1,5 @@
1
+ import { type IssueInfo } from '../../types/issues.js';
2
+ /**
3
+ * Get issue details by ID
4
+ */
5
+ export declare function getIssue(issueId: string, verbose?: boolean): Promise<IssueInfo>;
@@ -0,0 +1,21 @@
1
+ import { logInfo } from '../../utils/logger.js';
2
+ import { callMcpEndpoint } from '../mcp-client.js';
3
+ /**
4
+ * Get issue details by ID
5
+ */
6
+ export async function getIssue(issueId, verbose) {
7
+ if (verbose) {
8
+ logInfo(`Fetching issue details for: ${issueId}`);
9
+ }
10
+ const result = (await callMcpEndpoint('issues/get', {
11
+ issue_id: issueId,
12
+ }));
13
+ if (!result.issues || result.issues.length === 0) {
14
+ throw new Error(`Issue not found: ${issueId}`);
15
+ }
16
+ const issue = result.issues[0];
17
+ if (!issue || typeof issue !== 'object') {
18
+ throw new Error(`Invalid issue data returned for: ${issueId}`);
19
+ }
20
+ return issue;
21
+ }
@@ -0,0 +1,8 @@
1
+ export * from './batch-operations.js';
2
+ export * from './get-issue.js';
3
+ export * from './issue-utils.js';
4
+ export * from './status-updater.js';
5
+ export * from './test-cases.js';
6
+ export * from './update-issue.js';
7
+ export * from './user-stories.js';
8
+ export * from '../../types/issues.js';
@@ -0,0 +1,10 @@
1
+ // Re-export all issue-related functions
2
+ export * from './batch-operations.js';
3
+ export * from './get-issue.js';
4
+ export * from './issue-utils.js';
5
+ export * from './status-updater.js';
6
+ export * from './test-cases.js';
7
+ export * from './update-issue.js';
8
+ export * from './user-stories.js';
9
+ // Re-export types
10
+ export * from '../../types/issues.js';
@@ -0,0 +1,23 @@
1
+ import { type IssueInfo } from '../../types/issues.js';
2
+ /**
3
+ * Claim the next available ready_for_ai issue for processing.
4
+ * Uses database-level locking (FOR UPDATE SKIP LOCKED) to prevent
5
+ * race conditions between multiple workers.
6
+ *
7
+ * @param productId - The product ID to claim an issue from
8
+ * @param verbose - Whether to log verbose output
9
+ * @returns The claimed issue or null if no issues available
10
+ */
11
+ export declare function claimNextIssue(productId: string, verbose?: boolean): Promise<IssueInfo | null>;
12
+ /**
13
+ * Filter issues by status
14
+ */
15
+ export declare function filterIssuesByStatus(issues: IssueInfo[], status: string): IssueInfo[];
16
+ /**
17
+ * Sort issues by updated_at (oldest first for processing)
18
+ */
19
+ export declare function sortIssuesByUpdatedAt(issues: IssueInfo[]): IssueInfo[];
20
+ /**
21
+ * Get issues with ready_for_ai status for a product
22
+ */
23
+ export declare function getReadyForAIIssues(productId: string, verbose?: boolean): Promise<IssueInfo[]>;
@@ -0,0 +1,80 @@
1
+ import { logError, logInfo } from '../../utils/logger.js';
2
+ import { callMcpEndpoint } from '../mcp-client.js';
3
+ /**
4
+ * Claim the next available ready_for_ai issue for processing.
5
+ * Uses database-level locking (FOR UPDATE SKIP LOCKED) to prevent
6
+ * race conditions between multiple workers.
7
+ *
8
+ * @param productId - The product ID to claim an issue from
9
+ * @param verbose - Whether to log verbose output
10
+ * @returns The claimed issue or null if no issues available
11
+ */
12
+ export async function claimNextIssue(productId, verbose) {
13
+ if (verbose) {
14
+ logInfo(`Attempting to claim next ready_for_ai issue for product: ${productId}`);
15
+ }
16
+ try {
17
+ const result = (await callMcpEndpoint('issues/claim', {
18
+ product_id: productId,
19
+ }));
20
+ if (result.issue) {
21
+ if (verbose) {
22
+ logInfo(`✅ Claimed issue: ${result.issue.name} (${result.issue.id})`);
23
+ }
24
+ return result.issue;
25
+ }
26
+ if (verbose) {
27
+ logInfo('No issues available for processing');
28
+ }
29
+ return null;
30
+ }
31
+ catch (error) {
32
+ const errorMessage = error instanceof Error ? error.message : String(error);
33
+ logError(`Failed to claim issue: ${errorMessage}`);
34
+ throw error;
35
+ }
36
+ }
37
+ /**
38
+ * Filter issues by status
39
+ */
40
+ export function filterIssuesByStatus(issues, status) {
41
+ return issues.filter((issue) => issue.status === status);
42
+ }
43
+ /**
44
+ * Sort issues by updated_at (oldest first for processing)
45
+ */
46
+ export function sortIssuesByUpdatedAt(issues) {
47
+ return [...issues].sort((a, b) => {
48
+ const dateA = new Date(a.updated_at || 0).getTime();
49
+ const dateB = new Date(b.updated_at || 0).getTime();
50
+ return dateA - dateB;
51
+ });
52
+ }
53
+ /**
54
+ * Get issues with ready_for_ai status for a product
55
+ */
56
+ export async function getReadyForAIIssues(productId, verbose) {
57
+ if (verbose) {
58
+ logInfo(`Fetching ready_for_ai issues for product: ${productId}`);
59
+ }
60
+ try {
61
+ const result = (await callMcpEndpoint('issues/list', {
62
+ product_id: productId,
63
+ status: 'ready_for_ai',
64
+ }));
65
+ const issues = result.issues || [];
66
+ const sortedIssues = sortIssuesByUpdatedAt(issues);
67
+ if (verbose) {
68
+ logInfo(`✅ Found ${sortedIssues.length} ready_for_ai issues (oldest first)`);
69
+ sortedIssues.forEach((issue, index) => {
70
+ logInfo(` ${index + 1}. ${issue.name} (updated: ${issue.updated_at})`);
71
+ });
72
+ }
73
+ return sortedIssues;
74
+ }
75
+ catch (error) {
76
+ const errorMessage = error instanceof Error ? error.message : String(error);
77
+ logError(`Failed to fetch ready_for_ai issues: ${errorMessage}`);
78
+ throw error;
79
+ }
80
+ }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Issue status updater for workflow pipeline
3
+ * Updates issue status at each phase of the development workflow
4
+ */
5
+ import type { IssueStatus } from '../../types/index.js';
6
+ interface StatusUpdateOptions {
7
+ readonly issueId: string;
8
+ readonly status: IssueStatus;
9
+ readonly verbose?: boolean;
10
+ }
11
+ /**
12
+ * Check if moving from currentStatus to newStatus is forward progression
13
+ *
14
+ * Special cases for archived status:
15
+ * - Any status → archived: Always allowed (archiving from any state)
16
+ * - Archived → backlog: Always allowed (unarchiving restores to backlog)
17
+ */
18
+ export declare function isForwardProgression(currentStatus: IssueStatus, newStatus: IssueStatus): boolean;
19
+ /**
20
+ * Update issue status via MCP endpoint
21
+ */
22
+ export declare function updateIssueStatus({ issueId, status, verbose, }: StatusUpdateOptions): Promise<boolean>;
23
+ /**
24
+ * Map pipeline phase to issue status
25
+ */
26
+ export declare const getStatusForPhase: (phase: string) => IssueStatus | null;
27
+ /**
28
+ * Update issue status based on pipeline phase
29
+ *
30
+ * @param issueId - The issue ID to update
31
+ * @param phase - The pipeline phase name
32
+ * @param verbose - Whether to log verbose output
33
+ * @returns Promise<boolean> - true if update succeeded, false if skipped or failed
34
+ *
35
+ * BREAKING CHANGE: This function was changed from synchronous to asynchronous in PR #87
36
+ * to support regression prevention checks. All callers must now use await/then to handle
37
+ * the Promise return type. The function now validates against status regression and will
38
+ * skip updates that would move an issue backward in the development workflow.
39
+ */
40
+ export declare const updateIssueStatusForPhase: (issueId: string, phase: string, verbose?: boolean) => Promise<boolean>;
41
+ export {};
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Issue status updater for workflow pipeline
3
+ * Updates issue status at each phase of the development workflow
4
+ */
5
+ import { PHASE_STATUS_MAP, STATUS_PROGRESSION_ORDER, } from '../../config/issue-status.js';
6
+ import { logError, logInfo } from '../../utils/logger.js';
7
+ import { callMcpEndpoint } from '../mcp-client.js';
8
+ import { getIssue } from './get-issue.js';
9
+ /**
10
+ * Check if moving from currentStatus to newStatus is forward progression
11
+ *
12
+ * Special cases for archived status:
13
+ * - Any status → archived: Always allowed (archiving from any state)
14
+ * - Archived → backlog: Always allowed (unarchiving restores to backlog)
15
+ */
16
+ export function isForwardProgression(currentStatus, newStatus) {
17
+ // Any status can transition to archived
18
+ if (newStatus === 'archived') {
19
+ return true;
20
+ }
21
+ // Archived can only transition back to backlog (unarchive)
22
+ if (currentStatus === 'archived') {
23
+ return newStatus === 'backlog';
24
+ }
25
+ const currentIndex = STATUS_PROGRESSION_ORDER.indexOf(currentStatus);
26
+ const newIndex = STATUS_PROGRESSION_ORDER.indexOf(newStatus);
27
+ // Allow moving forward or staying at same level (for retries, etc.)
28
+ return newIndex >= currentIndex;
29
+ }
30
+ /**
31
+ * Update issue status via MCP endpoint
32
+ */
33
+ export async function updateIssueStatus({ issueId, status, verbose = false, }) {
34
+ try {
35
+ if (verbose) {
36
+ logInfo(`Updating issue ${issueId} status to: ${status}`);
37
+ }
38
+ // Get current issue status to check for regression
39
+ let issue;
40
+ let currentStatus;
41
+ try {
42
+ issue = await getIssue(issueId, verbose);
43
+ currentStatus = issue.status;
44
+ }
45
+ catch (error) {
46
+ const errorMessage = error instanceof Error ? error.message : String(error);
47
+ logError(`Failed to get current issue status for ${issueId}: ${errorMessage}`);
48
+ // If we can't get the current status, we can't safely check for regression
49
+ // so we'll skip the update to prevent potential regression
50
+ if (verbose) {
51
+ logInfo('⚠️ Skipping status update due to inability to verify current status');
52
+ }
53
+ return false;
54
+ }
55
+ // Check if this would be a regression
56
+ if (!isForwardProgression(currentStatus, status)) {
57
+ const message = `⚠️ Skipping status regression: ${currentStatus} → ${status}. Only forward progression allowed.`;
58
+ if (verbose) {
59
+ logInfo(message);
60
+ }
61
+ return false;
62
+ }
63
+ // Only proceed if status actually changed
64
+ if (currentStatus === status) {
65
+ if (verbose) {
66
+ logInfo(`Status already at ${status}, no update needed`);
67
+ }
68
+ return true;
69
+ }
70
+ // Update status
71
+ await callMcpEndpoint('issues/update', {
72
+ issue_id: issueId,
73
+ status,
74
+ });
75
+ if (verbose) {
76
+ logInfo(`✅ Issue status updated successfully from ${currentStatus} to: ${status}`);
77
+ }
78
+ return true;
79
+ }
80
+ catch (error) {
81
+ const errorMessage = error instanceof Error ? error.message : String(error);
82
+ if (verbose) {
83
+ logError(`Failed to update issue status: ${errorMessage}`);
84
+ }
85
+ return false;
86
+ }
87
+ }
88
+ /**
89
+ * Map pipeline phase to issue status
90
+ */
91
+ export const getStatusForPhase = (phase) => {
92
+ // Use the externalized phase-to-status mapping
93
+ return PHASE_STATUS_MAP[phase] ?? null;
94
+ };
95
+ /**
96
+ * Update issue status based on pipeline phase
97
+ *
98
+ * @param issueId - The issue ID to update
99
+ * @param phase - The pipeline phase name
100
+ * @param verbose - Whether to log verbose output
101
+ * @returns Promise<boolean> - true if update succeeded, false if skipped or failed
102
+ *
103
+ * BREAKING CHANGE: This function was changed from synchronous to asynchronous in PR #87
104
+ * to support regression prevention checks. All callers must now use await/then to handle
105
+ * the Promise return type. The function now validates against status regression and will
106
+ * skip updates that would move an issue backward in the development workflow.
107
+ */
108
+ export const updateIssueStatusForPhase = async (issueId, phase, verbose) => {
109
+ const status = getStatusForPhase(phase);
110
+ if (!status) {
111
+ const message = `⚠️ Unknown phase '${phase}' - skipping status update to prevent regression`;
112
+ if (verbose) {
113
+ logInfo(message);
114
+ }
115
+ return false;
116
+ }
117
+ return updateIssueStatus({
118
+ issueId,
119
+ status,
120
+ verbose,
121
+ });
122
+ };
@@ -0,0 +1,29 @@
1
+ import { type TestCase, type TestCaseStatus } from '../../types/issues.js';
2
+ /**
3
+ * Get test cases for an issue
4
+ */
5
+ export declare function getTestCases(issueId: string, verbose?: boolean): Promise<TestCase[]>;
6
+ /**
7
+ * Create a new test case for an issue
8
+ */
9
+ export declare function createTestCase(issueId: string, testCase: {
10
+ name: string;
11
+ description: string;
12
+ is_critical?: boolean;
13
+ }, verbose?: boolean): Promise<boolean>;
14
+ /**
15
+ * Create multiple test cases for an issue
16
+ */
17
+ export declare function createTestCases(mcpServerUrl: string, mcpToken: string, issueId: string, testCases: {
18
+ name: string;
19
+ description: string;
20
+ is_critical?: boolean;
21
+ }[], verbose?: boolean): Promise<boolean>;
22
+ /**
23
+ * Delete a test case
24
+ */
25
+ export declare function deleteTestCase(testCaseId: string, verbose?: boolean): Promise<boolean>;
26
+ /**
27
+ * Update test case status
28
+ */
29
+ export declare function updateTestCaseStatus(testCaseId: string, status: TestCaseStatus, verbose?: boolean): Promise<boolean>;