edsger 0.50.0 → 0.52.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 (470) hide show
  1. package/.claude/settings.local.json +23 -3
  2. package/.env.local +12 -0
  3. package/README.md +25 -25
  4. package/dist/api/chat.d.ts +7 -7
  5. package/dist/api/chat.js +13 -13
  6. package/dist/api/cross-product.d.ts +10 -10
  7. package/dist/api/cross-product.js +30 -30
  8. package/dist/api/github.d.ts +5 -5
  9. package/dist/api/github.js +10 -10
  10. package/dist/api/intelligence.d.ts +3 -3
  11. package/dist/api/issues/approval-checker.d.ts +20 -0
  12. package/dist/api/{features → issues}/approval-checker.js +16 -16
  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/{features → issues}/status-updater.js +23 -23
  21. package/dist/api/{features → issues}/test-cases.d.ts +7 -7
  22. package/dist/api/{features → issues}/test-cases.js +12 -12
  23. package/dist/api/issues/update-issue.d.ts +20 -0
  24. package/dist/api/{features/update-feature.js → issues/update-issue.js} +22 -22
  25. package/dist/api/{features → issues}/user-stories.d.ts +5 -5
  26. package/dist/api/{features → issues}/user-stories.js +8 -8
  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/{feature-worker.d.ts → issue-worker.d.ts} +4 -4
  37. package/dist/commands/agent-workflow/{feature-worker.js → issue-worker.js} +12 -12
  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/find-smells/index.d.ts +21 -0
  46. package/dist/commands/find-smells/index.js +65 -0
  47. package/dist/commands/init/prompts.js +1 -1
  48. package/dist/commands/init/templates.d.ts +1 -1
  49. package/dist/commands/init/templates.js +4 -4
  50. package/dist/commands/workflow/config/phase-configs.js +17 -17
  51. package/dist/commands/workflow/core/index.d.ts +1 -1
  52. package/dist/commands/workflow/core/index.js +2 -2
  53. package/dist/commands/workflow/core/issue-filter.d.ts +16 -0
  54. package/dist/commands/workflow/core/issue-filter.js +47 -0
  55. package/dist/commands/workflow/core/state-manager.d.ts +10 -10
  56. package/dist/commands/workflow/core/state-manager.js +10 -10
  57. package/dist/commands/workflow/core/workflow-logger.d.ts +9 -9
  58. package/dist/commands/workflow/core/workflow-logger.js +21 -21
  59. package/dist/commands/workflow/executors/phase-executor.d.ts +2 -2
  60. package/dist/commands/workflow/executors/phase-executor.js +32 -32
  61. package/dist/commands/workflow/issue-coordinator.d.ts +18 -0
  62. package/dist/commands/workflow/{feature-coordinator.js → issue-coordinator.js} +29 -29
  63. package/dist/commands/workflow/phase-orchestrator.d.ts +2 -2
  64. package/dist/commands/workflow/phase-orchestrator.js +82 -82
  65. package/dist/commands/workflow/processor.d.ts +7 -7
  66. package/dist/commands/workflow/processor.js +44 -44
  67. package/dist/config/{feature-status.d.ts → issue-status.d.ts} +14 -14
  68. package/dist/config/{feature-status.js → issue-status.js} +14 -14
  69. package/dist/errors/index.d.ts +6 -6
  70. package/dist/errors/index.js +11 -11
  71. package/dist/index.js +90 -1
  72. package/dist/phases/app-store-generation/context.js +6 -6
  73. package/dist/phases/app-store-generation/index.js +2 -2
  74. package/dist/phases/app-store-generation/prompts.js +2 -2
  75. package/dist/phases/autonomous/index.d.ts +3 -3
  76. package/dist/phases/autonomous/index.js +37 -37
  77. package/dist/phases/autonomous/prompts.d.ts +2 -2
  78. package/dist/phases/autonomous/prompts.js +4 -4
  79. package/dist/phases/branch-planning/context.d.ts +3 -3
  80. package/dist/phases/branch-planning/context.js +12 -12
  81. package/dist/phases/branch-planning/index.d.ts +3 -3
  82. package/dist/phases/branch-planning/index.js +32 -32
  83. package/dist/phases/branch-planning/outcome.d.ts +5 -5
  84. package/dist/phases/branch-planning/outcome.js +12 -12
  85. package/dist/phases/branch-planning/prompts.d.ts +3 -3
  86. package/dist/phases/branch-planning/prompts.js +13 -13
  87. package/dist/phases/bug-fixing/analyzer.d.ts +2 -2
  88. package/dist/phases/bug-fixing/analyzer.js +13 -13
  89. package/dist/phases/bug-fixing/context-fetcher.d.ts +3 -3
  90. package/dist/phases/bug-fixing/context-fetcher.js +18 -18
  91. package/dist/phases/bug-fixing/mcp-server.js +17 -18
  92. package/dist/phases/chat-processor/context.d.ts +5 -5
  93. package/dist/phases/chat-processor/context.js +17 -17
  94. package/dist/phases/chat-processor/index.d.ts +4 -4
  95. package/dist/phases/chat-processor/index.js +17 -17
  96. package/dist/phases/chat-processor/product-context.d.ts +3 -3
  97. package/dist/phases/chat-processor/product-context.js +16 -16
  98. package/dist/phases/chat-processor/product-prompts.d.ts +1 -1
  99. package/dist/phases/chat-processor/product-prompts.js +10 -10
  100. package/dist/phases/chat-processor/product-tools.d.ts +2 -2
  101. package/dist/phases/chat-processor/product-tools.js +33 -33
  102. package/dist/phases/chat-processor/prompts.d.ts +3 -3
  103. package/dist/phases/chat-processor/prompts.js +22 -22
  104. package/dist/phases/chat-processor/tools.js +46 -46
  105. package/dist/phases/code-implementation/branch-pr-creator.d.ts +3 -3
  106. package/dist/phases/code-implementation/branch-pr-creator.js +5 -5
  107. package/dist/phases/code-implementation/context.d.ts +3 -3
  108. package/dist/phases/code-implementation/context.js +18 -18
  109. package/dist/phases/code-implementation/index.d.ts +4 -4
  110. package/dist/phases/code-implementation/index.js +88 -88
  111. package/dist/phases/code-implementation/outcome.d.ts +3 -3
  112. package/dist/phases/code-implementation/outcome.js +6 -6
  113. package/dist/phases/code-implementation/prompts.d.ts +1 -1
  114. package/dist/phases/code-implementation/prompts.js +6 -6
  115. package/dist/phases/code-implementation-verification/agent.d.ts +3 -3
  116. package/dist/phases/code-implementation-verification/agent.js +5 -5
  117. package/dist/phases/code-implementation-verification/index.d.ts +3 -3
  118. package/dist/phases/code-implementation-verification/index.js +11 -11
  119. package/dist/phases/code-implementation-verification/prompts.d.ts +3 -3
  120. package/dist/phases/code-implementation-verification/prompts.js +7 -7
  121. package/dist/phases/code-refine/context.d.ts +8 -8
  122. package/dist/phases/code-refine/context.js +29 -29
  123. package/dist/phases/code-refine/index.d.ts +2 -2
  124. package/dist/phases/code-refine/index.js +20 -20
  125. package/dist/phases/code-refine/prompts.d.ts +1 -1
  126. package/dist/phases/code-refine/prompts.js +3 -3
  127. package/dist/phases/code-refine/refine-iteration.d.ts +1 -1
  128. package/dist/phases/code-refine/refine-iteration.js +4 -4
  129. package/dist/phases/code-refine/retry-handler.js +2 -2
  130. package/dist/phases/code-refine-verification/index.js +10 -10
  131. package/dist/phases/code-refine-verification/types.d.ts +2 -2
  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 +216 -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 +19 -0
  149. package/dist/phases/find-bugs/state.js +13 -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 +279 -0
  154. package/dist/phases/find-features/prompts.d.ts +43 -0
  155. package/dist/phases/find-features/prompts.js +138 -0
  156. package/dist/phases/find-features/state.d.ts +25 -0
  157. package/dist/phases/find-features/state.js +22 -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/find-shared/git.d.ts +24 -0
  161. package/dist/phases/find-shared/git.js +60 -0
  162. package/dist/phases/find-shared/mcp.d.ts +33 -0
  163. package/dist/phases/find-shared/mcp.js +69 -0
  164. package/dist/phases/find-shared/scan-state.d.ts +33 -0
  165. package/dist/phases/find-shared/scan-state.js +112 -0
  166. package/dist/phases/find-smells/index.d.ts +47 -0
  167. package/dist/phases/find-smells/index.js +278 -0
  168. package/dist/phases/find-smells/prompts.d.ts +30 -0
  169. package/dist/phases/find-smells/prompts.js +129 -0
  170. package/dist/phases/find-smells/state.d.ts +21 -0
  171. package/dist/phases/find-smells/state.js +17 -0
  172. package/dist/phases/find-smells/types.d.ts +51 -0
  173. package/dist/phases/find-smells/types.js +64 -0
  174. package/dist/phases/functional-testing/analyzer.d.ts +2 -2
  175. package/dist/phases/functional-testing/analyzer.js +40 -40
  176. package/dist/phases/functional-testing/context-fetcher.d.ts +3 -3
  177. package/dist/phases/functional-testing/context-fetcher.js +16 -16
  178. package/dist/phases/functional-testing/http-fallback.d.ts +2 -2
  179. package/dist/phases/functional-testing/http-fallback.js +9 -9
  180. package/dist/phases/functional-testing/mcp-server.js +23 -24
  181. package/dist/phases/functional-testing/prompts.d.ts +1 -1
  182. package/dist/phases/functional-testing/prompts.js +4 -4
  183. package/dist/phases/functional-testing/test-report-creator.d.ts +2 -2
  184. package/dist/phases/functional-testing/test-report-creator.js +10 -10
  185. package/dist/phases/functional-testing/test-retry-handler.js +3 -3
  186. package/dist/phases/growth-analysis/context.js +6 -6
  187. package/dist/phases/growth-analysis/index.js +2 -2
  188. package/dist/phases/growth-analysis/prompts.js +2 -2
  189. package/dist/phases/intelligence-analysis/context.js +7 -7
  190. package/dist/phases/intelligence-analysis/index.js +3 -3
  191. package/dist/phases/{feature-analysis → issue-analysis}/agent.js +1 -1
  192. package/dist/phases/issue-analysis/context.d.ts +24 -0
  193. package/dist/phases/{feature-analysis → issue-analysis}/context.js +30 -30
  194. package/dist/phases/issue-analysis/index.d.ts +8 -0
  195. package/dist/phases/{feature-analysis → issue-analysis}/index.js +29 -29
  196. package/dist/phases/issue-analysis/outcome.d.ts +40 -0
  197. package/dist/phases/{feature-analysis → issue-analysis}/outcome.js +17 -17
  198. package/dist/phases/{feature-analysis → issue-analysis}/prompts.d.ts +3 -3
  199. package/dist/phases/{feature-analysis → issue-analysis}/prompts.js +12 -12
  200. package/dist/phases/{feature-analysis-verification → issue-analysis-verification}/agent.d.ts +2 -2
  201. package/dist/phases/{feature-analysis-verification → issue-analysis-verification}/agent.js +1 -1
  202. package/dist/phases/{feature-analysis-verification → issue-analysis-verification}/index.d.ts +5 -5
  203. package/dist/phases/{feature-analysis-verification → issue-analysis-verification}/index.js +9 -9
  204. package/dist/phases/{feature-analysis-verification → issue-analysis-verification}/prompts.d.ts +2 -2
  205. package/dist/phases/{feature-analysis-verification → issue-analysis-verification}/prompts.js +7 -7
  206. package/dist/phases/output-contracts.js +37 -37
  207. package/dist/phases/pr-execution/context.d.ts +3 -3
  208. package/dist/phases/pr-execution/context.js +14 -14
  209. package/dist/phases/pr-execution/index.d.ts +2 -2
  210. package/dist/phases/pr-execution/index.js +22 -22
  211. package/dist/phases/pr-execution/outcome.d.ts +4 -4
  212. package/dist/phases/pr-execution/outcome.js +6 -6
  213. package/dist/phases/pr-execution/prompts.d.ts +4 -4
  214. package/dist/phases/pr-execution/prompts.js +6 -6
  215. package/dist/phases/pr-resolve/checklist-learner.js +2 -2
  216. package/dist/phases/pr-review/index.d.ts +1 -1
  217. package/dist/phases/pr-review/index.js +1 -1
  218. package/dist/phases/pr-review/prompts.d.ts +1 -1
  219. package/dist/phases/pr-review/prompts.js +1 -1
  220. package/dist/phases/pr-shared/context.d.ts +3 -3
  221. package/dist/phases/pr-shared/context.js +3 -3
  222. package/dist/phases/pr-splitting/context.d.ts +3 -3
  223. package/dist/phases/pr-splitting/context.js +16 -16
  224. package/dist/phases/pr-splitting/index.d.ts +4 -4
  225. package/dist/phases/pr-splitting/index.js +29 -29
  226. package/dist/phases/pr-splitting/outcome.d.ts +3 -3
  227. package/dist/phases/pr-splitting/outcome.js +7 -7
  228. package/dist/phases/pr-splitting/prompts.d.ts +3 -3
  229. package/dist/phases/pr-splitting/prompts.js +11 -11
  230. package/dist/phases/pull-request/creator.d.ts +4 -4
  231. package/dist/phases/pull-request/creator.js +25 -25
  232. package/dist/phases/pull-request/handler.d.ts +3 -3
  233. package/dist/phases/pull-request/handler.js +16 -16
  234. package/dist/phases/release-sync/index.js +2 -2
  235. package/dist/phases/run-sheet/agent.js +1 -2
  236. package/dist/phases/run-sheet/index.js +3 -3
  237. package/dist/phases/smoke-test/index.js +2 -2
  238. package/dist/phases/technical-design/context.d.ts +3 -3
  239. package/dist/phases/technical-design/context.js +11 -11
  240. package/dist/phases/technical-design/index.d.ts +2 -2
  241. package/dist/phases/technical-design/index.js +27 -27
  242. package/dist/phases/technical-design/outcome.d.ts +4 -4
  243. package/dist/phases/technical-design/outcome.js +6 -6
  244. package/dist/phases/technical-design/prompts.d.ts +2 -2
  245. package/dist/phases/technical-design/prompts.js +10 -10
  246. package/dist/phases/technical-design-verification/agent.d.ts +3 -3
  247. package/dist/phases/technical-design-verification/agent.js +4 -4
  248. package/dist/phases/technical-design-verification/index.d.ts +4 -4
  249. package/dist/phases/technical-design-verification/index.js +12 -12
  250. package/dist/phases/technical-design-verification/prompts.d.ts +3 -3
  251. package/dist/phases/technical-design-verification/prompts.js +6 -6
  252. package/dist/phases/test-cases-analysis/context.d.ts +5 -5
  253. package/dist/phases/test-cases-analysis/context.js +18 -18
  254. package/dist/phases/test-cases-analysis/formatters.js +7 -7
  255. package/dist/phases/test-cases-analysis/index.d.ts +1 -1
  256. package/dist/phases/test-cases-analysis/index.js +21 -21
  257. package/dist/phases/test-cases-analysis/outcome.d.ts +7 -7
  258. package/dist/phases/test-cases-analysis/outcome.js +13 -13
  259. package/dist/phases/test-cases-analysis/prompts.d.ts +3 -3
  260. package/dist/phases/test-cases-analysis/prompts.js +6 -6
  261. package/dist/phases/user-stories-analysis/context.d.ts +5 -5
  262. package/dist/phases/user-stories-analysis/context.js +18 -18
  263. package/dist/phases/user-stories-analysis/formatters.js +7 -7
  264. package/dist/phases/user-stories-analysis/index.d.ts +1 -1
  265. package/dist/phases/user-stories-analysis/index.js +21 -21
  266. package/dist/phases/user-stories-analysis/outcome.d.ts +7 -7
  267. package/dist/phases/user-stories-analysis/outcome.js +13 -13
  268. package/dist/phases/user-stories-analysis/prompts.d.ts +3 -3
  269. package/dist/phases/user-stories-analysis/prompts.js +10 -10
  270. package/dist/services/audit-logs.d.ts +10 -10
  271. package/dist/services/audit-logs.js +12 -12
  272. package/dist/services/branches.d.ts +6 -6
  273. package/dist/services/branches.js +16 -16
  274. package/dist/services/checklist.d.ts +3 -3
  275. package/dist/services/checklist.js +11 -11
  276. package/dist/services/coaching/coaching-agent.js +2 -2
  277. package/dist/services/coaching/coaching-loop.d.ts +1 -1
  278. package/dist/services/coaching/coaching-loop.js +2 -2
  279. package/dist/services/coaching/phase-coaching.d.ts +2 -2
  280. package/dist/services/coaching/phase-coaching.js +3 -3
  281. package/dist/services/coaching/self-rating.js +1 -1
  282. package/dist/services/feedbacks.d.ts +4 -4
  283. package/dist/services/feedbacks.js +8 -8
  284. package/dist/services/phase-hooks/bindings-fetcher.d.ts +4 -4
  285. package/dist/services/phase-hooks/bindings-fetcher.js +8 -8
  286. package/dist/services/phase-hooks/hook-executor.js +1 -1
  287. package/dist/services/phase-hooks/hook-logging.d.ts +2 -2
  288. package/dist/services/phase-hooks/hook-logging.js +4 -4
  289. package/dist/services/phase-hooks/hook-runner.d.ts +1 -1
  290. package/dist/services/phase-hooks/hook-runner.js +4 -4
  291. package/dist/services/phase-hooks/types.d.ts +3 -3
  292. package/dist/services/phase-ratings.d.ts +7 -7
  293. package/dist/services/phase-ratings.js +8 -8
  294. package/dist/services/pull-requests.d.ts +4 -4
  295. package/dist/services/pull-requests.js +11 -11
  296. package/dist/services/skill-resolver.d.ts +1 -1
  297. package/dist/services/skill-resolver.js +1 -1
  298. package/dist/skills/phase/app-store-generation/SKILL.md +9 -9
  299. package/dist/skills/phase/autonomous/SKILL.md +2 -2
  300. package/dist/skills/phase/branch-planning/SKILL.md +12 -12
  301. package/dist/skills/phase/bug-fixing/SKILL.md +1 -1
  302. package/dist/skills/phase/code-implementation/SKILL.md +6 -6
  303. package/dist/skills/phase/code-implementation-verification/SKILL.md +3 -3
  304. package/dist/skills/phase/code-testing/SKILL.md +5 -5
  305. package/dist/skills/phase/functional-testing/SKILL.md +3 -3
  306. package/dist/skills/phase/growth-analysis/SKILL.md +8 -8
  307. package/dist/skills/phase/incremental-sync/SKILL.md +6 -6
  308. package/dist/skills/phase/intelligence-analysis/SKILL.md +7 -7
  309. package/dist/skills/phase/{feature-analysis → issue-analysis}/SKILL.md +8 -8
  310. package/dist/skills/phase/pr-execution/SKILL.md +7 -7
  311. package/dist/skills/phase/pr-splitting/SKILL.md +14 -14
  312. package/dist/skills/phase/smoke-test/SKILL.md +1 -1
  313. package/dist/skills/phase/technical-design/SKILL.md +5 -5
  314. package/dist/skills/phase/test-cases-analysis/SKILL.md +4 -4
  315. package/dist/skills/phase/user-stories-analysis/SKILL.md +13 -13
  316. package/dist/system/session-manager.d.ts +3 -3
  317. package/dist/system/session-manager.js +3 -3
  318. package/dist/system/sleep-notification.js +2 -2
  319. package/dist/system/sleep-prevention.js +1 -1
  320. package/dist/types/index.d.ts +21 -21
  321. package/dist/types/{features.d.ts → issues.d.ts} +3 -3
  322. package/dist/types/pipeline.d.ts +4 -4
  323. package/dist/updater/auto-updater.d.ts +2 -2
  324. package/dist/updater/auto-updater.js +3 -3
  325. package/dist/utils/conflict-resolver.d.ts +1 -1
  326. package/dist/utils/conflict-resolver.js +5 -5
  327. package/dist/utils/formatters.d.ts +4 -4
  328. package/dist/utils/formatters.js +29 -29
  329. package/dist/utils/git-branch-manager-async.d.ts +6 -6
  330. package/dist/utils/git-branch-manager-async.js +41 -41
  331. package/dist/utils/git-branch-manager.d.ts +11 -11
  332. package/dist/utils/git-branch-manager.js +42 -42
  333. package/dist/utils/image-downloader.d.ts +4 -4
  334. package/dist/utils/image-downloader.js +17 -17
  335. package/dist/utils/pipeline-logger.d.ts +1 -1
  336. package/dist/utils/pipeline-logger.js +5 -5
  337. package/dist/workspace/workspace-manager.d.ts +17 -17
  338. package/dist/workspace/workspace-manager.js +21 -21
  339. package/package.json +1 -1
  340. package/vitest.config.ts +4 -0
  341. package/dist/api/__tests__/app-store.test.d.ts +0 -7
  342. package/dist/api/__tests__/app-store.test.js +0 -60
  343. package/dist/api/__tests__/intelligence.test.d.ts +0 -11
  344. package/dist/api/__tests__/intelligence.test.js +0 -315
  345. package/dist/api/features/__tests__/feature-utils.test.d.ts +0 -4
  346. package/dist/api/features/__tests__/feature-utils.test.js +0 -370
  347. package/dist/api/features/__tests__/status-updater.test.d.ts +0 -4
  348. package/dist/api/features/__tests__/status-updater.test.js +0 -88
  349. package/dist/api/features/approval-checker.d.ts +0 -20
  350. package/dist/api/features/feature-utils.d.ts +0 -23
  351. package/dist/api/features/feature-utils.js +0 -80
  352. package/dist/api/features/get-feature.d.ts +0 -5
  353. package/dist/api/features/get-feature.js +0 -21
  354. package/dist/api/features/index.d.ts +0 -8
  355. package/dist/api/features/index.js +0 -10
  356. package/dist/api/features/status-updater.d.ts +0 -41
  357. package/dist/api/features/update-feature.d.ts +0 -20
  358. package/dist/commands/build/__tests__/build.test.d.ts +0 -5
  359. package/dist/commands/build/__tests__/build.test.js +0 -206
  360. package/dist/commands/build/__tests__/detect-project.test.d.ts +0 -6
  361. package/dist/commands/build/__tests__/detect-project.test.js +0 -160
  362. package/dist/commands/build/__tests__/run-build.test.d.ts +0 -6
  363. package/dist/commands/build/__tests__/run-build.test.js +0 -433
  364. package/dist/commands/intelligence/__tests__/command.test.d.ts +0 -4
  365. package/dist/commands/intelligence/__tests__/command.test.js +0 -48
  366. package/dist/commands/workflow/core/__tests__/feature-filter.test.d.ts +0 -5
  367. package/dist/commands/workflow/core/__tests__/feature-filter.test.js +0 -316
  368. package/dist/commands/workflow/core/__tests__/pipeline-evaluator.test.d.ts +0 -4
  369. package/dist/commands/workflow/core/__tests__/pipeline-evaluator.test.js +0 -397
  370. package/dist/commands/workflow/core/__tests__/state-manager.test.d.ts +0 -4
  371. package/dist/commands/workflow/core/__tests__/state-manager.test.js +0 -384
  372. package/dist/commands/workflow/core/feature-filter.d.ts +0 -16
  373. package/dist/commands/workflow/core/feature-filter.js +0 -47
  374. package/dist/commands/workflow/feature-coordinator.d.ts +0 -18
  375. package/dist/config/__tests__/config.test.d.ts +0 -4
  376. package/dist/config/__tests__/config.test.js +0 -286
  377. package/dist/config/__tests__/feature-status.test.d.ts +0 -4
  378. package/dist/config/__tests__/feature-status.test.js +0 -111
  379. package/dist/errors/__tests__/index.test.d.ts +0 -4
  380. package/dist/errors/__tests__/index.test.js +0 -349
  381. package/dist/phases/app-store-generation/__tests__/agent.test.d.ts +0 -5
  382. package/dist/phases/app-store-generation/__tests__/agent.test.js +0 -142
  383. package/dist/phases/app-store-generation/__tests__/context.test.d.ts +0 -4
  384. package/dist/phases/app-store-generation/__tests__/context.test.js +0 -284
  385. package/dist/phases/app-store-generation/__tests__/prompts.test.d.ts +0 -4
  386. package/dist/phases/app-store-generation/__tests__/prompts.test.js +0 -122
  387. package/dist/phases/app-store-generation/__tests__/screenshot-composer.test.d.ts +0 -5
  388. package/dist/phases/app-store-generation/__tests__/screenshot-composer.test.js +0 -826
  389. package/dist/phases/code-review/__tests__/diff-utils.test.js +0 -101
  390. package/dist/phases/feature-analysis/context.d.ts +0 -24
  391. package/dist/phases/feature-analysis/index.d.ts +0 -8
  392. package/dist/phases/feature-analysis/outcome.d.ts +0 -40
  393. package/dist/phases/intelligence-analysis/__tests__/context.test.d.ts +0 -4
  394. package/dist/phases/intelligence-analysis/__tests__/context.test.js +0 -192
  395. package/dist/phases/intelligence-analysis/__tests__/matching.test.d.ts +0 -13
  396. package/dist/phases/intelligence-analysis/__tests__/matching.test.js +0 -154
  397. package/dist/phases/intelligence-analysis/__tests__/orchestration.test.d.ts +0 -5
  398. package/dist/phases/intelligence-analysis/__tests__/orchestration.test.js +0 -378
  399. package/dist/phases/intelligence-analysis/__tests__/prompts.test.d.ts +0 -4
  400. package/dist/phases/intelligence-analysis/__tests__/prompts.test.js +0 -33
  401. package/dist/phases/pr-execution/__tests__/file-assigner.test.d.ts +0 -1
  402. package/dist/phases/pr-execution/__tests__/file-assigner.test.js +0 -303
  403. package/dist/phases/pr-resolve/__tests__/checklist-learner.test.d.ts +0 -1
  404. package/dist/phases/pr-resolve/__tests__/checklist-learner.test.js +0 -157
  405. package/dist/phases/pr-resolve/__tests__/prompts.test.d.ts +0 -1
  406. package/dist/phases/pr-resolve/__tests__/prompts.test.js +0 -116
  407. package/dist/phases/pr-resolve/__tests__/resolve-mapping.test.d.ts +0 -1
  408. package/dist/phases/pr-resolve/__tests__/resolve-mapping.test.js +0 -138
  409. package/dist/phases/pr-resolve/__tests__/types.test.d.ts +0 -1
  410. package/dist/phases/pr-resolve/__tests__/types.test.js +0 -43
  411. package/dist/phases/pr-resolve/__tests__/workspace.test.d.ts +0 -1
  412. package/dist/phases/pr-resolve/__tests__/workspace.test.js +0 -111
  413. package/dist/phases/pr-review/__tests__/prompts.test.d.ts +0 -1
  414. package/dist/phases/pr-review/__tests__/prompts.test.js +0 -49
  415. package/dist/phases/pr-review/__tests__/review-comments.test.d.ts +0 -1
  416. package/dist/phases/pr-review/__tests__/review-comments.test.js +0 -110
  417. package/dist/phases/pr-shared/__tests__/agent-utils.test.d.ts +0 -1
  418. package/dist/phases/pr-shared/__tests__/agent-utils.test.js +0 -91
  419. package/dist/phases/pr-shared/__tests__/context.test.d.ts +0 -1
  420. package/dist/phases/pr-shared/__tests__/context.test.js +0 -94
  421. package/dist/phases/pr-splitting/__tests__/import-dep-validator.test.d.ts +0 -1
  422. package/dist/phases/pr-splitting/__tests__/import-dep-validator.test.js +0 -331
  423. package/dist/phases/run-sheet/render.d.ts +0 -60
  424. package/dist/phases/run-sheet/render.js +0 -297
  425. package/dist/phases/smoke-test/__tests__/agent.test.d.ts +0 -4
  426. package/dist/phases/smoke-test/__tests__/agent.test.js +0 -84
  427. package/dist/phases/smoke-test/__tests__/github.test.d.ts +0 -9
  428. package/dist/phases/smoke-test/__tests__/github.test.js +0 -120
  429. package/dist/phases/smoke-test/__tests__/snapshot.test.d.ts +0 -8
  430. package/dist/phases/smoke-test/__tests__/snapshot.test.js +0 -93
  431. package/dist/phases/smoke-test/github.d.ts +0 -54
  432. package/dist/phases/smoke-test/github.js +0 -101
  433. package/dist/phases/smoke-test/snapshot.d.ts +0 -27
  434. package/dist/phases/smoke-test/snapshot.js +0 -157
  435. package/dist/services/coaching/__tests__/coaching-agent.test.d.ts +0 -1
  436. package/dist/services/coaching/__tests__/coaching-agent.test.js +0 -74
  437. package/dist/services/coaching/__tests__/coaching-loop.test.d.ts +0 -1
  438. package/dist/services/coaching/__tests__/coaching-loop.test.js +0 -59
  439. package/dist/services/coaching/__tests__/self-rating.test.d.ts +0 -1
  440. package/dist/services/coaching/__tests__/self-rating.test.js +0 -188
  441. package/dist/services/lifecycle-agent/__tests__/phase-criteria.test.d.ts +0 -4
  442. package/dist/services/lifecycle-agent/__tests__/phase-criteria.test.js +0 -133
  443. package/dist/services/lifecycle-agent/__tests__/transition-rules.test.d.ts +0 -4
  444. package/dist/services/lifecycle-agent/__tests__/transition-rules.test.js +0 -336
  445. package/dist/services/lifecycle-agent/index.d.ts +0 -24
  446. package/dist/services/lifecycle-agent/index.js +0 -25
  447. package/dist/services/lifecycle-agent/phase-criteria.d.ts +0 -57
  448. package/dist/services/lifecycle-agent/phase-criteria.js +0 -335
  449. package/dist/services/lifecycle-agent/transition-rules.d.ts +0 -60
  450. package/dist/services/lifecycle-agent/transition-rules.js +0 -184
  451. package/dist/services/lifecycle-agent/types.d.ts +0 -190
  452. package/dist/services/lifecycle-agent/types.js +0 -12
  453. package/dist/services/phase-hooks/__tests__/bindings-fetcher.test.d.ts +0 -1
  454. package/dist/services/phase-hooks/__tests__/bindings-fetcher.test.js +0 -122
  455. package/dist/services/phase-hooks/__tests__/hook-executor.test.d.ts +0 -1
  456. package/dist/services/phase-hooks/__tests__/hook-executor.test.js +0 -321
  457. package/dist/services/phase-hooks/__tests__/hook-runner.test.d.ts +0 -1
  458. package/dist/services/phase-hooks/__tests__/hook-runner.test.js +0 -261
  459. package/dist/services/phase-hooks/__tests__/plugin-loader.test.d.ts +0 -1
  460. package/dist/services/phase-hooks/__tests__/plugin-loader.test.js +0 -158
  461. package/dist/services/video/__tests__/video-pipeline.test.d.ts +0 -6
  462. package/dist/services/video/__tests__/video-pipeline.test.js +0 -249
  463. package/dist/types/features.js +0 -1
  464. package/dist/workspace/__tests__/workspace-manager.test.d.ts +0 -7
  465. package/dist/workspace/__tests__/workspace-manager.test.js +0 -52
  466. /package/dist/api/{features → issues}/batch-operations.d.ts +0 -0
  467. /package/dist/api/{features → issues}/batch-operations.js +0 -0
  468. /package/dist/phases/{feature-analysis → issue-analysis}/agent.d.ts +0 -0
  469. /package/dist/skills/phase/{feature-analysis-verification → issue-analysis-verification}/SKILL.md +0 -0
  470. /package/dist/{phases/code-review/__tests__/diff-utils.test.d.ts → types/issues.js} +0 -0
@@ -0,0 +1,33 @@
1
+ /**
2
+ * MCP helpers shared by find-bugs / find-features / find-smells.
3
+ *
4
+ * All three load a product's basics (name, description) for prompt context,
5
+ * pull the open-issue list for dedup, and file findings via `issues/create`.
6
+ * Centralising the calls means a schema change in MCP only needs touching one
7
+ * place, and the per-phase orchestrators stay focused on their own logic.
8
+ */
9
+ import { type IssueInfo } from '../../types/issues.js';
10
+ export interface ProductBasics {
11
+ name: string;
12
+ description?: string;
13
+ }
14
+ export declare function fetchProductBasics(productId: string): Promise<ProductBasics>;
15
+ /**
16
+ * Fetch the product's open issues for dedup context. Filters out terminal
17
+ * statuses (shipped/archived/closed/...) since those can't conflict with new
18
+ * findings the agent might surface.
19
+ */
20
+ export declare function fetchOpenIssues(productId: string): Promise<IssueInfo[]>;
21
+ export declare function isTerminalStatus(status: string): boolean;
22
+ export interface CreateIssueInput {
23
+ productId: string;
24
+ /** Issue title for `name`. */
25
+ title: string;
26
+ /** Already-formatted markdown body. The caller decides the layout. */
27
+ description: string;
28
+ }
29
+ /**
30
+ * File a new issue via MCP. Returns the new issue id, or null if MCP returned
31
+ * an error / unexpected shape (already logged).
32
+ */
33
+ export declare function createIssue(input: CreateIssueInput): Promise<string | null>;
@@ -0,0 +1,69 @@
1
+ /**
2
+ * MCP helpers shared by find-bugs / find-features / find-smells.
3
+ *
4
+ * All three load a product's basics (name, description) for prompt context,
5
+ * pull the open-issue list for dedup, and file findings via `issues/create`.
6
+ * Centralising the calls means a schema change in MCP only needs touching one
7
+ * place, and the per-phase orchestrators stay focused on their own logic.
8
+ */
9
+ import { callMcpEndpoint } from '../../api/mcp-client.js';
10
+ import { logError, logWarning } from '../../utils/logger.js';
11
+ export async function fetchProductBasics(productId) {
12
+ try {
13
+ const result = (await callMcpEndpoint('resources/read', {
14
+ uri: `product://${productId}`,
15
+ }));
16
+ const text = result.contents?.[0]?.text || '{}';
17
+ const parsed = JSON.parse(text);
18
+ return {
19
+ name: parsed.name || productId,
20
+ description: parsed.description,
21
+ };
22
+ }
23
+ catch {
24
+ return { name: productId };
25
+ }
26
+ }
27
+ /**
28
+ * Fetch the product's open issues for dedup context. Filters out terminal
29
+ * statuses (shipped/archived/closed/...) since those can't conflict with new
30
+ * findings the agent might surface.
31
+ */
32
+ export async function fetchOpenIssues(productId) {
33
+ try {
34
+ const result = (await callMcpEndpoint('issues/list', {
35
+ product_id: productId,
36
+ }));
37
+ const all = result.issues || [];
38
+ return all.filter((i) => !isTerminalStatus(i.status));
39
+ }
40
+ catch (error) {
41
+ logWarning(`Could not load existing issues for dedup: ${error instanceof Error ? error.message : String(error)}`);
42
+ return [];
43
+ }
44
+ }
45
+ export function isTerminalStatus(status) {
46
+ return (status === 'shipped' ||
47
+ status === 'archived' ||
48
+ status === 'cancelled' ||
49
+ status === 'closed' ||
50
+ status === 'completed');
51
+ }
52
+ /**
53
+ * File a new issue via MCP. Returns the new issue id, or null if MCP returned
54
+ * an error / unexpected shape (already logged).
55
+ */
56
+ export async function createIssue(input) {
57
+ try {
58
+ const result = (await callMcpEndpoint('issues/create', {
59
+ product_id: input.productId,
60
+ name: input.title,
61
+ description: input.description,
62
+ }));
63
+ return result.issue?.id || result.id || null;
64
+ }
65
+ catch (error) {
66
+ logError(`Failed to create issue for "${input.title}": ${error instanceof Error ? error.message : String(error)}`);
67
+ return null;
68
+ }
69
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Per-product scan state, generic across the find-* phases. Each phase has
3
+ * its own state schema (find-bugs tracks a commit sha, find-features tracks
4
+ * the most-recent-seen feedback id, etc.) so the type is parametric, but the
5
+ * file layout, atomic-write, and lock semantics are identical and live here.
6
+ *
7
+ * Storage layout: `~/.edsger/<dirName>/<productId>.json` plus a sibling
8
+ * `.lock` file. The lockfile uses O_EXCL so concurrent acquirers race on the
9
+ * filesystem, not on application code — atomic on local POSIX filesystems
10
+ * (good enough; the workspace clone is also machine-local).
11
+ *
12
+ * Known limitation: state is machine-local. A scan started on machine A and
13
+ * next on machine B will look like a first run.
14
+ */
15
+ export interface LockHandle {
16
+ release: () => void;
17
+ }
18
+ export interface ScanStateModule<T extends object> {
19
+ load: (productId: string) => T;
20
+ save: (productId: string, state: T) => void;
21
+ /** Merge `patch` into the stored state. Fields not mentioned are preserved. */
22
+ update: (productId: string, patch: Partial<T>) => T;
23
+ /**
24
+ * Acquire an exclusive lock for this product's state. Returns null if held.
25
+ * Stale locks older than `staleAfterMs` (default 1h) are reclaimed.
26
+ */
27
+ acquireLock: (productId: string, staleAfterMs?: number) => LockHandle | null;
28
+ }
29
+ export interface CreateScanStateModuleOptions {
30
+ /** Subdirectory under ~/.edsger/. Example: 'find-bugs-state'. */
31
+ dirName: string;
32
+ }
33
+ export declare function createScanStateModule<T extends object>(opts: CreateScanStateModuleOptions): ScanStateModule<T>;
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Per-product scan state, generic across the find-* phases. Each phase has
3
+ * its own state schema (find-bugs tracks a commit sha, find-features tracks
4
+ * the most-recent-seen feedback id, etc.) so the type is parametric, but the
5
+ * file layout, atomic-write, and lock semantics are identical and live here.
6
+ *
7
+ * Storage layout: `~/.edsger/<dirName>/<productId>.json` plus a sibling
8
+ * `.lock` file. The lockfile uses O_EXCL so concurrent acquirers race on the
9
+ * filesystem, not on application code — atomic on local POSIX filesystems
10
+ * (good enough; the workspace clone is also machine-local).
11
+ *
12
+ * Known limitation: state is machine-local. A scan started on machine A and
13
+ * next on machine B will look like a first run.
14
+ */
15
+ import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, unlinkSync, writeFileSync, } from 'fs';
16
+ import { homedir } from 'os';
17
+ import { join } from 'path';
18
+ const DEFAULT_STALE_AFTER_MS = 60 * 60 * 1000;
19
+ export function createScanStateModule(opts) {
20
+ const { dirName } = opts;
21
+ // Resolve at call time, not module-load time, so test setups that swap
22
+ // process.env.HOME between cases see the change.
23
+ function stateDir() {
24
+ return join(homedir(), '.edsger', dirName);
25
+ }
26
+ function safeProductId(productId) {
27
+ return productId.replace(/[^a-zA-Z0-9_-]/g, '_');
28
+ }
29
+ function statePath(productId) {
30
+ return join(stateDir(), `${safeProductId(productId)}.json`);
31
+ }
32
+ function lockPath(productId) {
33
+ return join(stateDir(), `${safeProductId(productId)}.lock`);
34
+ }
35
+ function ensureStateDir() {
36
+ const dir = stateDir();
37
+ if (!existsSync(dir)) {
38
+ mkdirSync(dir, { recursive: true });
39
+ }
40
+ }
41
+ function load(productId) {
42
+ const p = statePath(productId);
43
+ if (!existsSync(p)) {
44
+ return {};
45
+ }
46
+ try {
47
+ const raw = readFileSync(p, 'utf-8');
48
+ const parsed = JSON.parse(raw);
49
+ return parsed && typeof parsed === 'object' ? parsed : {};
50
+ }
51
+ catch {
52
+ return {};
53
+ }
54
+ }
55
+ /** Atomic write: stage to a tempfile, then rename. */
56
+ function save(productId, state) {
57
+ ensureStateDir();
58
+ const finalPath = statePath(productId);
59
+ const tmpPath = `${finalPath}.${process.pid}.tmp`;
60
+ writeFileSync(tmpPath, JSON.stringify(state, null, 2), 'utf-8');
61
+ renameSync(tmpPath, finalPath);
62
+ }
63
+ function update(productId, patch) {
64
+ const merged = { ...load(productId), ...patch };
65
+ save(productId, merged);
66
+ return merged;
67
+ }
68
+ function acquireLock(productId, staleAfterMs = DEFAULT_STALE_AFTER_MS) {
69
+ ensureStateDir();
70
+ const lock = lockPath(productId);
71
+ if (existsSync(lock)) {
72
+ try {
73
+ const raw = readFileSync(lock, 'utf-8');
74
+ const parsed = JSON.parse(raw);
75
+ const age = Date.now() - new Date(parsed.acquiredAt ?? 0).getTime();
76
+ if (age < staleAfterMs) {
77
+ return null;
78
+ }
79
+ // Stale or corrupt — reclaim. Only reachable if a previous run died
80
+ // without releasing (SIGKILL, OOM).
81
+ rmSync(lock, { force: true });
82
+ }
83
+ catch {
84
+ rmSync(lock, { force: true });
85
+ }
86
+ }
87
+ try {
88
+ // `flag: 'wx'` = open with O_CREAT | O_EXCL — atomic against a racing
89
+ // peer, and writeFileSync(path, ...) closes the fd internally so no
90
+ // manual closeSync is needed (vs. the openSync + writeFileSync(fd)
91
+ // form, which leaks the fd).
92
+ writeFileSync(lock, JSON.stringify({
93
+ acquiredAt: new Date().toISOString(),
94
+ pid: process.pid,
95
+ }), { flag: 'wx' });
96
+ return {
97
+ release: () => {
98
+ try {
99
+ unlinkSync(lock);
100
+ }
101
+ catch {
102
+ // Already gone — fine.
103
+ }
104
+ },
105
+ };
106
+ }
107
+ catch {
108
+ return null;
109
+ }
110
+ }
111
+ return { load, save, update, acquireLock };
112
+ }
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Find-smells phase: clone the product's repo, ask Claude to audit code for
3
+ * code smells (refactor candidates, perf cliffs, dead code, etc.), and file
4
+ * each new finding as an issue. Subsequent runs are incremental, scoped to
5
+ * commits since the previous successful scan.
6
+ *
7
+ * Companion to find-bugs (real defects) and find-features (missing user
8
+ * capability). The three phases share the same workspace + state pattern.
9
+ */
10
+ import { type SmellCategory } from './types.js';
11
+ export interface FindSmellsOptions {
12
+ productId: string;
13
+ githubToken: string;
14
+ owner: string;
15
+ repo: string;
16
+ /** Force a full scan even if previous-scan state exists. */
17
+ full?: boolean;
18
+ /** Branch to scan; defaults to the repo's default branch. */
19
+ branch?: string;
20
+ /** Upper bound on files the auditor may Read. Keeps token cost predictable. */
21
+ maxFiles?: number;
22
+ /**
23
+ * Optional category filter. Agent is asked to honour it via the prompt
24
+ * AND its output is re-filtered after parsing — both are required because
25
+ * the agent can't be trusted to obey perfectly.
26
+ */
27
+ categories?: SmellCategory[];
28
+ verbose?: boolean;
29
+ }
30
+ export interface FindSmellsResult {
31
+ status: 'success' | 'error';
32
+ message: string;
33
+ scannedCommitSha?: string;
34
+ smellsFound?: number;
35
+ issuesCreated?: number;
36
+ /** Findings the agent passed off to find-bugs (not filed by this run). */
37
+ deferredToBugs?: number;
38
+ /** Findings the agent passed off to find-features (not filed by this run). */
39
+ deferredToFeatures?: number;
40
+ summary?: string;
41
+ }
42
+ /** Single source of truth — referenced by the CLI help string too. */
43
+ export declare const DEFAULT_MAX_FILES = 200;
44
+ /**
45
+ * Scan a product's repository for code smells and file each new finding as an issue.
46
+ */
47
+ export declare function scanForSmells(options: FindSmellsOptions): Promise<FindSmellsResult>;
@@ -0,0 +1,278 @@
1
+ /**
2
+ * Find-smells phase: clone the product's repo, ask Claude to audit code for
3
+ * code smells (refactor candidates, perf cliffs, dead code, etc.), and file
4
+ * each new finding as an issue. Subsequent runs are incremental, scoped to
5
+ * commits since the previous successful scan.
6
+ *
7
+ * Companion to find-bugs (real defects) and find-features (missing user
8
+ * capability). The three phases share the same workspace + state pattern.
9
+ */
10
+ import { query } from '@anthropic-ai/claude-agent-sdk';
11
+ import { DEFAULT_MODEL } from '../../constants.js';
12
+ import { logError, logInfo, logSuccess, logWarning, } from '../../utils/logger.js';
13
+ import { cloneIssueRepo, ensureWorkspaceDir, syncRepoToRef, } from '../../workspace/workspace-manager.js';
14
+ import { detectDefaultBranch, gitRevParse, isAncestor, listChangedPaths, } from '../find-shared/git.js';
15
+ import { createIssue, fetchOpenIssues, fetchProductBasics, } from '../find-shared/mcp.js';
16
+ import { createPromptGenerator, extractTextFromContent, tryExtractResult, } from '../pr-shared/agent-utils.js';
17
+ import { createFindSmellsSystemPrompt, createFindSmellsUserPrompt, } from './prompts.js';
18
+ import { acquireFindSmellsLock, loadFindSmellsState, updateFindSmellsState, } from './state.js';
19
+ import { isScanResult, isSmellCategory, } from './types.js';
20
+ const WORKSPACE_KEY = 'find-smells';
21
+ /** Single source of truth — referenced by the CLI help string too. */
22
+ export const DEFAULT_MAX_FILES = 200;
23
+ /**
24
+ * Upper bound on turns for the in-CLI Claude session. Same rationale as
25
+ * find-bugs: read-only but open-scope audit needs headroom for repo-wide
26
+ * Glob/Read/Grep without runaway exploration.
27
+ */
28
+ const MAX_TURNS = 200;
29
+ /**
30
+ * Scan a product's repository for code smells and file each new finding as an issue.
31
+ */
32
+ // eslint-disable-next-line complexity
33
+ export async function scanForSmells(options) {
34
+ const { productId, githubToken, owner, repo, full, maxFiles, categories, verbose, } = options;
35
+ logInfo(`Starting smell scan for product ${productId} (${owner}/${repo})`);
36
+ const lock = acquireFindSmellsLock(productId);
37
+ if (!lock) {
38
+ logWarning(`Another smell scan is already in progress for product ${productId}; skipping.`);
39
+ return {
40
+ status: 'error',
41
+ message: 'Another smell scan is already in progress for this product',
42
+ };
43
+ }
44
+ try {
45
+ updateFindSmellsState(productId, {
46
+ lastAttemptedAt: new Date().toISOString(),
47
+ });
48
+ const workspaceRoot = ensureWorkspaceDir();
49
+ const repoKey = `${WORKSPACE_KEY}-${productId}`;
50
+ const cloned = cloneIssueRepo(workspaceRoot, repoKey, owner, repo, githubToken);
51
+ const { repoPath } = cloned;
52
+ const branch = options.branch ?? detectDefaultBranch(repoPath);
53
+ logInfo(`Syncing ${owner}/${repo} to branch ${branch}`);
54
+ syncRepoToRef(repoPath, { branch }, githubToken);
55
+ const headSha = gitRevParse(repoPath, 'HEAD');
56
+ const state = loadFindSmellsState(productId);
57
+ const baseSha = full ? undefined : state.lastScannedCommitSha;
58
+ let scope = 'full';
59
+ let changedPaths;
60
+ if (baseSha && baseSha !== headSha) {
61
+ const sameTree = isAncestor(repoPath, baseSha, headSha);
62
+ if (sameTree) {
63
+ scope = 'incremental';
64
+ changedPaths = listChangedPaths(repoPath, baseSha, headSha);
65
+ logInfo(`Incremental scan: ${changedPaths.length} files changed since ${baseSha.slice(0, 8)}`);
66
+ if (changedPaths.length === 0) {
67
+ logSuccess('No code changes since last scan; nothing to do.');
68
+ updateFindSmellsState(productId, {
69
+ lastScannedCommitSha: headSha,
70
+ lastScannedAt: new Date().toISOString(),
71
+ lastError: undefined,
72
+ });
73
+ return {
74
+ status: 'success',
75
+ message: 'No changes since last scan',
76
+ scannedCommitSha: headSha,
77
+ smellsFound: 0,
78
+ issuesCreated: 0,
79
+ };
80
+ }
81
+ }
82
+ else {
83
+ logWarning(`Last scanned sha ${baseSha.slice(0, 8)} not reachable from HEAD; falling back to full scan.`);
84
+ }
85
+ }
86
+ else if (baseSha === headSha) {
87
+ // Symmetric with the "no changed files" early return above: even though
88
+ // the sha didn't move, advance lastScannedAt + clear lastError so the
89
+ // state file accurately reflects when we last verified the repo.
90
+ logSuccess('HEAD unchanged since last scan; nothing to do.');
91
+ updateFindSmellsState(productId, {
92
+ lastScannedAt: new Date().toISOString(),
93
+ lastError: undefined,
94
+ });
95
+ return {
96
+ status: 'success',
97
+ message: 'HEAD unchanged since last scan',
98
+ scannedCommitSha: headSha,
99
+ smellsFound: 0,
100
+ issuesCreated: 0,
101
+ };
102
+ }
103
+ const product = await fetchProductBasics(productId);
104
+ const existingIssues = await fetchOpenIssues(productId);
105
+ logInfo(`Loaded ${existingIssues.length} existing issues for dedup context`);
106
+ const systemPrompt = createFindSmellsSystemPrompt();
107
+ const userPrompt = createFindSmellsUserPrompt({
108
+ productName: product.name,
109
+ productDescription: product.description,
110
+ scope,
111
+ baseSha,
112
+ headSha,
113
+ changedPaths,
114
+ maxFiles: maxFiles ?? DEFAULT_MAX_FILES,
115
+ categories,
116
+ existingIssues: existingIssues.map((i) => ({
117
+ id: i.id,
118
+ name: i.name,
119
+ description: i.description,
120
+ })),
121
+ });
122
+ let lastAssistantResponse = '';
123
+ let scanResult = null;
124
+ logInfo('Running Claude code-smell audit...');
125
+ for await (const message of query({
126
+ prompt: createPromptGenerator(userPrompt),
127
+ options: {
128
+ systemPrompt: {
129
+ type: 'preset',
130
+ preset: 'claude_code',
131
+ append: systemPrompt,
132
+ },
133
+ model: DEFAULT_MODEL,
134
+ maxTurns: MAX_TURNS,
135
+ permissionMode: 'bypassPermissions',
136
+ cwd: repoPath,
137
+ },
138
+ })) {
139
+ if (message.type === 'assistant') {
140
+ lastAssistantResponse += extractTextFromContent(message.message?.content ?? [], verbose);
141
+ continue;
142
+ }
143
+ if (message.type !== 'result') {
144
+ continue;
145
+ }
146
+ const responseText = message.subtype === 'success'
147
+ ? message.result || lastAssistantResponse
148
+ : lastAssistantResponse;
149
+ const parsed = tryExtractResult(responseText, 'scan_result');
150
+ if (isScanResult(parsed)) {
151
+ scanResult = parsed;
152
+ }
153
+ else if (message.subtype !== 'success') {
154
+ logError(`Audit incomplete: ${message.subtype}`);
155
+ }
156
+ }
157
+ if (!scanResult) {
158
+ const msg = 'Audit failed: could not parse a scan_result from the agent';
159
+ updateFindSmellsState(productId, { lastError: msg });
160
+ return {
161
+ status: 'error',
162
+ message: msg,
163
+ };
164
+ }
165
+ const { summary, smells } = scanResult;
166
+ logInfo(`Audit produced ${smells.length} candidate smells. ${summary}`);
167
+ const deferredBugs = scanResult.deferred_to_bugs ?? [];
168
+ const deferredFeatures = scanResult.deferred_to_features ?? [];
169
+ if (deferredBugs.length > 0) {
170
+ logInfo(`${deferredBugs.length} finding(s) deferred to find-bugs — run \`edsger find-bugs ${productId}\` to pick them up:`);
171
+ for (const d of deferredBugs) {
172
+ const loc = d.file ? ` (${d.file}${d.line ? `:${d.line}` : ''})` : '';
173
+ logInfo(` • ${d.title}${loc} — ${d.reason}`);
174
+ }
175
+ }
176
+ if (deferredFeatures.length > 0) {
177
+ logInfo(`${deferredFeatures.length} finding(s) deferred to find-features — run \`edsger find-features ${productId}\` to pick them up:`);
178
+ for (const d of deferredFeatures) {
179
+ const loc = d.file ? ` (${d.file}${d.line ? `:${d.line}` : ''})` : '';
180
+ logInfo(` • ${d.title}${loc} — ${d.reason}`);
181
+ }
182
+ }
183
+ const { kept: filteredSmells, droppedCategories } = filterByCategories(smells, categories);
184
+ if (droppedCategories.length > 0) {
185
+ const summaryLine = droppedCategories
186
+ .map(({ category, count }) => `${category}×${count}`)
187
+ .join(', ');
188
+ logWarning(`Dropped findings outside the requested categories or with unknown category: ${summaryLine}.`);
189
+ }
190
+ let created = 0;
191
+ for (const smell of filteredSmells) {
192
+ const issueId = await createIssueForSmell(productId, smell);
193
+ if (issueId) {
194
+ created++;
195
+ logSuccess(`Filed issue ${issueId}: ${smell.title}`);
196
+ }
197
+ }
198
+ updateFindSmellsState(productId, {
199
+ lastScannedCommitSha: headSha,
200
+ lastScannedAt: new Date().toISOString(),
201
+ lastError: undefined,
202
+ });
203
+ const droppedCount = droppedCategories.reduce((acc, d) => acc + d.count, 0);
204
+ return {
205
+ status: 'success',
206
+ message: `Filed ${created} of ${filteredSmells.length} candidate smells (${droppedCount} dropped by category filter; ${deferredBugs.length} deferred to bugs, ${deferredFeatures.length} to features)`,
207
+ scannedCommitSha: headSha,
208
+ smellsFound: filteredSmells.length,
209
+ issuesCreated: created,
210
+ deferredToBugs: deferredBugs.length,
211
+ deferredToFeatures: deferredFeatures.length,
212
+ summary,
213
+ };
214
+ }
215
+ catch (error) {
216
+ const errorMessage = error instanceof Error ? error.message : String(error);
217
+ logError(`Smell scan failed: ${errorMessage}`);
218
+ updateFindSmellsState(productId, { lastError: errorMessage });
219
+ return {
220
+ status: 'error',
221
+ message: `Smell scan failed: ${errorMessage}`,
222
+ };
223
+ }
224
+ finally {
225
+ lock.release();
226
+ }
227
+ }
228
+ async function createIssueForSmell(productId, smell) {
229
+ return createIssue({
230
+ productId,
231
+ title: smell.title,
232
+ description: formatIssueDescription(smell),
233
+ });
234
+ }
235
+ /**
236
+ * Filter the agent's findings down to the requested categories. The system
237
+ * prompt asks the agent to honour the filter, but trusting the prompt alone
238
+ * lets bad output through; we re-check here. Items with an unknown category
239
+ * are also dropped — the type system can't enforce that across the JSON
240
+ * boundary.
241
+ *
242
+ * Returns per-category drop counts so the user-facing warning can name the
243
+ * specific categories that were filtered out (more actionable than a bare
244
+ * total).
245
+ */
246
+ function filterByCategories(smells, categories) {
247
+ const allow = categories?.length ? new Set(categories) : null;
248
+ const kept = [];
249
+ const droppedTally = new Map();
250
+ for (const s of smells) {
251
+ const known = isSmellCategory(s.category);
252
+ const inAllow = !allow || (known && allow.has(s.category));
253
+ if (known && inAllow) {
254
+ kept.push(s);
255
+ continue;
256
+ }
257
+ const key = known ? s.category : '<unknown>';
258
+ droppedTally.set(key, (droppedTally.get(key) ?? 0) + 1);
259
+ }
260
+ const droppedCategories = Array.from(droppedTally.entries())
261
+ .map(([category, count]) => ({ category, count }))
262
+ .sort((a, b) => b.count - a.count);
263
+ return { kept, droppedCategories };
264
+ }
265
+ function formatIssueDescription(smell) {
266
+ const location = smell.line ? `${smell.file}:${smell.line}` : smell.file;
267
+ const lines = [
268
+ `**Severity**: ${smell.severity}`,
269
+ `**Category**: ${smell.category}`,
270
+ `**Location**: \`${location}\``,
271
+ '',
272
+ smell.description,
273
+ '',
274
+ '---',
275
+ '_Filed automatically by `edsger find-smells`._',
276
+ ];
277
+ return lines.join('\n');
278
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Prompts for the find-smells phase. The agent runs with cwd=repo checkout
3
+ * and has Read/Grep/Glob/Bash available — it explores the code itself
4
+ * rather than receiving a pre-baked diff.
5
+ *
6
+ * Boundary against neighbouring phases:
7
+ * - find-bugs handles real defects (security, correctness, races, etc.)
8
+ * - find-features handles missing user-facing capability
9
+ * - find-smells (this phase) handles "the code would be better if changed":
10
+ * refactor candidates, dead code, perf cliffs, type-safety gaps, etc.
11
+ */
12
+ export declare function createFindSmellsSystemPrompt(): string;
13
+ export interface FindSmellsUserPromptParams {
14
+ productName: string;
15
+ productDescription?: string;
16
+ scope: 'full' | 'incremental';
17
+ baseSha?: string;
18
+ headSha: string;
19
+ changedPaths?: string[];
20
+ existingIssues: {
21
+ id: string;
22
+ name: string;
23
+ description?: string;
24
+ }[];
25
+ /** Upper bound on files the auditor may Read. Keeps token cost predictable. */
26
+ maxFiles?: number;
27
+ /** Optional comma-separated category filter from the CLI. */
28
+ categories?: string[];
29
+ }
30
+ export declare function createFindSmellsUserPrompt(params: FindSmellsUserPromptParams): string;