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,279 @@
1
+ /**
2
+ * Find-features phase: synthesise opportunities from user feedback +
3
+ * intelligence reports + the codebase, and file each one as an issue.
4
+ *
5
+ * The repo is cloned and the model runs with Read/Grep/Glob available so it
6
+ * can **verify existing functionality before proposing a new feature**. Many
7
+ * "obvious" feature asks ("add CSV export") turn out to be discoverability
8
+ * issues on something already shipped — the model needs to see the code to
9
+ * avoid those mistakes.
10
+ *
11
+ * Time-windowed on the PM data side (last N days of feedback) rather than
12
+ * diff-incremental on the repo side — we don't care what changed in the
13
+ * code, we care what exists there.
14
+ */
15
+ import { query } from '@anthropic-ai/claude-agent-sdk';
16
+ import { callMcpEndpoint } from '../../api/mcp-client.js';
17
+ import { DEFAULT_MODEL } from '../../constants.js';
18
+ import { logError, logInfo, logSuccess, logWarning, } from '../../utils/logger.js';
19
+ import { cloneIssueRepo, ensureWorkspaceDir, syncRepoToRef, } from '../../workspace/workspace-manager.js';
20
+ import { detectDefaultBranch } from '../find-shared/git.js';
21
+ import { createIssue, fetchOpenIssues, fetchProductBasics, } from '../find-shared/mcp.js';
22
+ import { createPromptGenerator, extractTextFromContent, tryExtractResult, } from '../pr-shared/agent-utils.js';
23
+ import { createFindFeaturesSystemPrompt, createFindFeaturesUserPrompt, } from './prompts.js';
24
+ import { acquireFindFeaturesLock, updateFindFeaturesState } from './state.js';
25
+ import { isDiscoveryResult, } from './types.js';
26
+ /**
27
+ * Upper bound on turns for the in-CLI Claude session.
28
+ *
29
+ * Feature discovery is primarily synthesis (cluster feedback, compare to
30
+ * intel, rank) but the model now also spot-checks the codebase to avoid
31
+ * proposing features that already exist. 150 turns leaves room for 5-10
32
+ * targeted Read/Grep passes per candidate without being an open-ended audit.
33
+ */
34
+ const MAX_TURNS = 150;
35
+ const WORKSPACE_KEY = 'find-features';
36
+ const DEFAULT_SINCE = '90d';
37
+ const DEFAULT_MIN_CLUSTER = 3;
38
+ const DEFAULT_MAX_SUGGESTIONS = 10;
39
+ // eslint-disable-next-line complexity
40
+ export async function scanForFeatures(options) {
41
+ const { productId, githubToken, owner, repo, since = DEFAULT_SINCE, minClusterSize = DEFAULT_MIN_CLUSTER, maxSuggestions = DEFAULT_MAX_SUGGESTIONS, focusReportId, verbose, } = options;
42
+ logInfo(`Starting feature discovery for product ${productId} (${owner}/${repo})`);
43
+ const lock = acquireFindFeaturesLock(productId);
44
+ if (!lock) {
45
+ logWarning(`Another feature discovery run is already in progress for product ${productId}; skipping.`);
46
+ return {
47
+ status: 'error',
48
+ message: 'Another feature discovery run is already in progress for this product',
49
+ };
50
+ }
51
+ try {
52
+ updateFindFeaturesState(productId, {
53
+ lastAttemptedAt: new Date().toISOString(),
54
+ });
55
+ // Clone / refresh the repo so the model can verify existing functionality
56
+ // before proposing new features. Same workspace pattern as find-bugs —
57
+ // one reusable clone per product, keyed by WORKSPACE_KEY.
58
+ const workspaceRoot = ensureWorkspaceDir();
59
+ const repoKey = `${WORKSPACE_KEY}-${productId}`;
60
+ const cloned = cloneIssueRepo(workspaceRoot, repoKey, owner, repo, githubToken);
61
+ const { repoPath } = cloned;
62
+ const branch = options.branch ?? detectDefaultBranch(repoPath);
63
+ logInfo(`Syncing ${owner}/${repo} to branch ${branch}`);
64
+ syncRepoToRef(repoPath, { branch }, githubToken);
65
+ const sinceIso = resolveSinceIso(since);
66
+ const product = await fetchProductBasics(productId);
67
+ const [feedbacks, intelligenceReports, existingIssues] = await Promise.all([
68
+ fetchFeedbacks(productId, sinceIso),
69
+ fetchIntelligenceReports(productId, focusReportId),
70
+ fetchOpenIssues(productId),
71
+ ]);
72
+ logInfo(`Loaded ${feedbacks.length} feedbacks (since ${since}), ${intelligenceReports.length} reports, ${existingIssues.length} open issues`);
73
+ const codeOnlyMode = feedbacks.length === 0 && intelligenceReports.length === 0;
74
+ if (codeOnlyMode) {
75
+ logInfo('No feedback or intelligence reports in scope — running code-only analysis on the repo.');
76
+ }
77
+ const systemPrompt = createFindFeaturesSystemPrompt({ codeOnlyMode });
78
+ const userPrompt = createFindFeaturesUserPrompt({
79
+ productName: product.name,
80
+ productDescription: product.description,
81
+ feedbacks,
82
+ intelligenceReports,
83
+ existingIssues: existingIssues.map((i) => ({
84
+ id: i.id,
85
+ name: i.name,
86
+ description: i.description,
87
+ })),
88
+ minClusterSize,
89
+ maxSuggestions,
90
+ sinceWindow: since,
91
+ focusReportId,
92
+ codeOnlyMode,
93
+ });
94
+ let lastAssistantResponse = '';
95
+ let discoveryResult = null;
96
+ logInfo('Running Claude opportunity synthesis...');
97
+ for await (const message of query({
98
+ prompt: createPromptGenerator(userPrompt),
99
+ options: {
100
+ systemPrompt: {
101
+ type: 'preset',
102
+ preset: 'claude_code',
103
+ append: systemPrompt,
104
+ },
105
+ model: DEFAULT_MODEL,
106
+ maxTurns: MAX_TURNS,
107
+ permissionMode: 'bypassPermissions',
108
+ cwd: repoPath,
109
+ },
110
+ })) {
111
+ if (message.type === 'assistant') {
112
+ lastAssistantResponse += extractTextFromContent(message.message?.content ?? [], verbose);
113
+ continue;
114
+ }
115
+ if (message.type !== 'result') {
116
+ continue;
117
+ }
118
+ const responseText = message.subtype === 'success'
119
+ ? message.result || lastAssistantResponse
120
+ : lastAssistantResponse;
121
+ const parsed = tryExtractResult(responseText, 'discovery_result');
122
+ if (isDiscoveryResult(parsed)) {
123
+ discoveryResult = parsed;
124
+ }
125
+ else if (message.subtype !== 'success') {
126
+ logError(`Synthesis incomplete: ${message.subtype}`);
127
+ }
128
+ }
129
+ if (!discoveryResult) {
130
+ const msg = 'Synthesis failed: could not parse a discovery_result from the agent';
131
+ updateFindFeaturesState(productId, { lastError: msg });
132
+ return { status: 'error', message: msg };
133
+ }
134
+ const { summary, opportunities } = discoveryResult;
135
+ logInfo(`Synthesis produced ${opportunities.length} opportunities. ${summary}`);
136
+ let created = 0;
137
+ for (const opp of opportunities) {
138
+ const issueId = await createIssueForOpportunity(productId, opp);
139
+ if (issueId) {
140
+ created++;
141
+ logSuccess(`Filed issue ${issueId}: ${opp.title}`);
142
+ }
143
+ }
144
+ // The previous schema captured `lastSeenFeedbackId / lastSeenReportId /
145
+ // lastScannedCommitSha` here, but the reader side never used them — kept
146
+ // it lean and only persist the run-status fields the worker actually
147
+ // reads on retry. See find-features/state.ts for the schema rationale.
148
+ updateFindFeaturesState(productId, {
149
+ lastRunAt: new Date().toISOString(),
150
+ lastError: undefined,
151
+ });
152
+ return {
153
+ status: 'success',
154
+ message: `Filed ${created} of ${opportunities.length} opportunities`,
155
+ opportunitiesFound: opportunities.length,
156
+ issuesCreated: created,
157
+ summary,
158
+ };
159
+ }
160
+ catch (error) {
161
+ const errorMessage = error instanceof Error ? error.message : String(error);
162
+ logError(`Feature discovery failed: ${errorMessage}`);
163
+ updateFindFeaturesState(productId, { lastError: errorMessage });
164
+ return {
165
+ status: 'error',
166
+ message: `Feature discovery failed: ${errorMessage}`,
167
+ };
168
+ }
169
+ finally {
170
+ lock.release();
171
+ }
172
+ }
173
+ /**
174
+ * Convert a user-friendly "since" value (e.g. "30d", "12h", ISO timestamp) to
175
+ * an ISO string usable as a lower bound. Falls back to 90 days ago on parse
176
+ * failure — better to over-fetch than silently skip half the signal.
177
+ */
178
+ const DURATION_UNIT_MS = {
179
+ h: 60 * 60 * 1000,
180
+ d: 24 * 60 * 60 * 1000,
181
+ w: 7 * 24 * 60 * 60 * 1000,
182
+ };
183
+ export function resolveSinceIso(since) {
184
+ const now = Date.now();
185
+ const durationMatch = /^(\d+)([dhw])$/.exec(since.trim());
186
+ if (durationMatch) {
187
+ const n = parseInt(durationMatch[1], 10);
188
+ const unit = durationMatch[2];
189
+ const ms = n * (DURATION_UNIT_MS[unit] ?? DURATION_UNIT_MS.d);
190
+ return new Date(now - ms).toISOString();
191
+ }
192
+ const ts = Date.parse(since);
193
+ if (!Number.isNaN(ts)) {
194
+ return new Date(ts).toISOString();
195
+ }
196
+ return new Date(now - 90 * 24 * 60 * 60 * 1000).toISOString();
197
+ }
198
+ async function fetchFeedbacks(productId, sinceIso) {
199
+ try {
200
+ // `product_user_feedbacks/list_for_product` queries the
201
+ // product_user_feedbacks table — the *external user* feedback surface
202
+ // (submitted via the public feedback page, no auth). Schema: title +
203
+ // description + category (bug | feature_request | improvement |
204
+ // question | other) + status + priority. Server-side filter on
205
+ // `since` keeps the response size bounded.
206
+ //
207
+ // NOT to be confused with `feedbacks/list_for_product`, which returns
208
+ // Claude-Code phase feedback and is an internal-workflow artefact.
209
+ const result = (await callMcpEndpoint('product_user_feedbacks/list_for_product', {
210
+ product_id: productId,
211
+ since: sinceIso,
212
+ }));
213
+ const rows = result.feedbacks || [];
214
+ return rows.map((f) => ({
215
+ id: f.id,
216
+ body: f.title ? `${f.title}\n${f.description}`.trim() : f.description,
217
+ category: f.category,
218
+ createdAt: f.created_at,
219
+ }));
220
+ }
221
+ catch (error) {
222
+ logWarning(`Could not load user feedbacks: ${error instanceof Error ? error.message : String(error)}`);
223
+ return [];
224
+ }
225
+ }
226
+ async function fetchIntelligenceReports(productId, focusReportId) {
227
+ try {
228
+ // `intelligence_reports` schema (20260327000000_create_intelligence.sql:69):
229
+ // id, product_id, report_type, title, summary, full_report, …, created_at.
230
+ const result = (await callMcpEndpoint('intelligence/reports/list', {
231
+ product_id: productId,
232
+ }));
233
+ let reports = result.reports || [];
234
+ if (focusReportId) {
235
+ // If focused, put the focus report first and keep 5 others for context.
236
+ const focus = reports.filter((r) => r.id === focusReportId);
237
+ const rest = reports.filter((r) => r.id !== focusReportId).slice(0, 5);
238
+ reports = [...focus, ...rest];
239
+ }
240
+ else {
241
+ reports = reports.slice(0, 10);
242
+ }
243
+ return reports.map((r) => ({
244
+ id: r.id,
245
+ title: r.title,
246
+ summary: r.summary,
247
+ createdAt: r.created_at,
248
+ }));
249
+ }
250
+ catch (error) {
251
+ logWarning(`Could not load intelligence reports: ${error instanceof Error ? error.message : String(error)}`);
252
+ return [];
253
+ }
254
+ }
255
+ async function createIssueForOpportunity(productId, opp) {
256
+ return createIssue({
257
+ productId,
258
+ title: opp.title,
259
+ description: formatIssueDescription(opp),
260
+ });
261
+ }
262
+ function formatIssueDescription(opp) {
263
+ const evidenceLine = opp.supporting_evidence_ids.length > 0
264
+ ? opp.supporting_evidence_ids.join(', ')
265
+ : '(none provided — review manually)';
266
+ const lines = [
267
+ `**Source**: feature-discovery`,
268
+ `**Confidence**: ${opp.confidence}`,
269
+ `**Signal**: ${opp.source}`,
270
+ `**User outcome**: ${opp.user_outcome}`,
271
+ `**Supporting evidence**: ${evidenceLine}`,
272
+ '',
273
+ opp.description,
274
+ '',
275
+ '---',
276
+ '_Filed automatically by `edsger find-features`._',
277
+ ];
278
+ return lines.join('\n');
279
+ }
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Prompts for the find-features phase. The agent runs with cwd=repo checkout
3
+ * and has Read/Grep/Glob available — it's expected to consult the codebase
4
+ * to verify an idea isn't already shipped before proposing it. That check
5
+ * catches the most common failure mode of feature-discovery: surfacing
6
+ * "opportunities" that are really just discoverability issues on existing
7
+ * functionality.
8
+ */
9
+ export interface FindFeaturesSystemPromptParams {
10
+ /** True when no feedback/reports were available; agent must derive opportunities purely from code. */
11
+ codeOnlyMode?: boolean;
12
+ }
13
+ export declare function createFindFeaturesSystemPrompt(params?: FindFeaturesSystemPromptParams): string;
14
+ export interface FindFeaturesUserPromptParams {
15
+ productName: string;
16
+ productDescription?: string;
17
+ feedbacks: {
18
+ id: string;
19
+ body: string;
20
+ category?: string;
21
+ createdAt?: string;
22
+ }[];
23
+ intelligenceReports: {
24
+ id: string;
25
+ title: string;
26
+ summary?: string;
27
+ createdAt?: string;
28
+ }[];
29
+ existingIssues: {
30
+ id: string;
31
+ name: string;
32
+ description?: string;
33
+ }[];
34
+ minClusterSize: number;
35
+ maxSuggestions: number;
36
+ /** Upper bound on the feedback window this run considers (human readable). */
37
+ sinceWindow: string;
38
+ /** Optional narrowing to a specific intelligence report's context. */
39
+ focusReportId?: string;
40
+ /** True when the run has no feedback/reports and must analyse the codebase only. */
41
+ codeOnlyMode?: boolean;
42
+ }
43
+ export declare function createFindFeaturesUserPrompt(params: FindFeaturesUserPromptParams): string;
@@ -0,0 +1,138 @@
1
+ /**
2
+ * Prompts for the find-features phase. The agent runs with cwd=repo checkout
3
+ * and has Read/Grep/Glob available — it's expected to consult the codebase
4
+ * to verify an idea isn't already shipped before proposing it. That check
5
+ * catches the most common failure mode of feature-discovery: surfacing
6
+ * "opportunities" that are really just discoverability issues on existing
7
+ * functionality.
8
+ */
9
+ export function createFindFeaturesSystemPrompt(params = {}) {
10
+ const { codeOnlyMode = false } = params;
11
+ const evidenceClause = codeOnlyMode
12
+ ? `2. **Evidence from the codebase** — since no user feedback or reports are available this run, opportunities must be grounded in concrete observations of the code: half-finished flows, TODO/FIXME clusters, obvious gaps next to existing functionality, missing standard capabilities for this kind of product. Cite file paths (e.g. \`src/foo/bar.ts:42\`) as your evidence in \`supporting_evidence_ids\`.`
13
+ : `2. **Evidence beyond one voice** — backed by multiple feedbacks, a competitor gap, or a measurable trend. Cite specific IDs.`;
14
+ return `You are a senior product manager synthesising **opportunities worth building** for a product. You are reading user feedback, competitive intelligence, and the product's current codebase, then picking the few ideas with the strongest evidence.${codeOnlyMode
15
+ ? '\n\nThis run has **no user feedback and no intelligence reports** in scope. Derive opportunities purely from the codebase: look for half-built flows, TODO/FIXME clusters, missing standard capabilities, and natural extensions of existing features. Cite file paths as evidence.'
16
+ : ''}
17
+
18
+ You have read-only access to the repository via Read/Grep/Glob. Use it — the single most common failure mode of this role is proposing a feature that already exists but is badly discoverable. Before filing an opportunity, grep the code for the feature you're about to propose; if it's already implemented, either reframe the opportunity as a discoverability fix or drop it.
19
+
20
+ **What counts as an opportunity worth filing**:
21
+ 1. **Clear user outcome** — you can articulate in one sentence what changes for the user.
22
+ ${evidenceClause}
23
+ 3. **Feasible in this product's shape** — adjacent to existing workflows, not a pivot. Verify against the code.
24
+ 4. **Not already in the backlog** — cross-check the existing-issues list; skip anything that overlaps, even if the wording differs.
25
+ 5. **Not already in the code** — grep before you file. If the feature exists but is hidden, the opportunity is "improve discoverability of X", not "add X".
26
+
27
+ **What does NOT count** (skip these — they cost product velocity for little signal):
28
+ - Nice-to-haves with no evidence ("would be cool if…")
29
+ - Pure refactors or tech debt (those are issues, not opportunities)
30
+ - Things that belong in support docs, not in the product
31
+ - "We should do X like CompetitorY" with no evidence any user wants X
32
+ - Generic platform expansions ("add a mobile app", "add an API") unless specific evidence supports it
33
+ - Features that already exist in the code — check before filing
34
+
35
+ **Discipline**:
36
+ - Prefer **fewer**, **better-evidenced** ideas over a long list. Ten mediocre suggestions dilute the good ones.
37
+ - Each opportunity must cite \`supporting_evidence_ids\` — feedback IDs, report IDs, ${codeOnlyMode ? 'or **file paths** (e.g. `src/foo/bar.ts:42`) when running in code-only mode' : 'or, when no PM signal exists, file paths in the form `src/foo/bar.ts:42`'}. Zero evidence = you're speculating; cut it.
38
+ - Confidence rubric${codeOnlyMode ? ' (code-only mode)' : ''}:
39
+ - high = ${codeOnlyMode ? 'a half-finished flow with multiple TODOs **or** an obvious gap next to existing functionality with clear product framing' : '3+ independent user signals **or** a clear competitor parity gap backed by a report'}
40
+ - medium = ${codeOnlyMode ? 'a noticeable gap or natural extension supported by 2+ code references' : '2 signals, or a strong theme in one report'}
41
+ - low = ${codeOnlyMode ? 'a single thoughtful code observation that still deserves surfacing' : 'a single thoughtful signal that still deserves surfacing'}
42
+ - **Deduplication**: skip findings that overlap any existing open issue. Be conservative — rephrased overlap is still overlap.
43
+ - **Verification**: for each candidate, grep the repo for the functionality. Note in the opportunity description what you checked and why you're confident it's genuinely missing.
44
+
45
+ **CRITICAL — Output Format**:
46
+ End your response with a single JSON code block in this exact shape:
47
+
48
+ \`\`\`json
49
+ {
50
+ "discovery_result": {
51
+ "summary": "Reviewed N feedbacks and M reports; surfacing K opportunities.",
52
+ "analyzed_through": "<ISO timestamp of the most recent signal considered>",
53
+ "opportunities": [
54
+ {
55
+ "title": "Short, action-oriented title under 80 chars",
56
+ "description": "## Opportunity\\nPlain-language pitch.\\n\\n## Evidence\\n- feedback:abc123 — quote\\n- report:def456 — key finding\\n\\n## Why now\\nTiming rationale (trend, blocker unblocking, etc).\\n\\n## Rough scope\\nOne paragraph on what building it looks like.",
57
+ "user_outcome": "The user can now X without having to Y.",
58
+ "confidence": "medium",
59
+ "source": "user_feedback",
60
+ "supporting_evidence_ids": ["abc123", "def456"],
61
+ "dedup_signature": "invoice-bulk-csv-export"
62
+ }
63
+ ]
64
+ }
65
+ }
66
+ \`\`\`
67
+
68
+ If nothing meets the bar, emit the JSON with an empty \`opportunities\` array and a summary that says so plainly.`;
69
+ }
70
+ export function createFindFeaturesUserPrompt(params) {
71
+ const { productName, productDescription, feedbacks, intelligenceReports, existingIssues, minClusterSize, maxSuggestions, sinceWindow, focusReportId, codeOnlyMode = false, } = params;
72
+ const productBlock = productDescription
73
+ ? `**Product**: ${productName}\n${productDescription}`
74
+ : `**Product**: ${productName}`;
75
+ const feedbackBlock = feedbacks.length === 0
76
+ ? 'No user feedback available in the current window.'
77
+ : `**User feedback** (${feedbacks.length} items, window: ${sinceWindow}):\n${feedbacks
78
+ .slice(0, 300)
79
+ .map((f) => `- [${f.id}] ${f.category ? `[${f.category}] ` : ''}${f.createdAt ? `(${f.createdAt.slice(0, 10)}) ` : ''}${truncate(f.body, 300)}`)
80
+ .join('\n')}${feedbacks.length > 300 ? `\n…and ${feedbacks.length - 300} more.` : ''}`;
81
+ const focusBlock = focusReportId
82
+ ? `\n**Focus**: report id \`${focusReportId}\` — prioritise opportunities implied by this specific report.`
83
+ : '';
84
+ const reportsBlock = intelligenceReports.length === 0
85
+ ? 'No intelligence reports available.'
86
+ : `**Intelligence reports** (${intelligenceReports.length}):\n${intelligenceReports
87
+ .slice(0, 30)
88
+ .map((r) => `- [${r.id}] ${r.title}${r.summary ? `\n ${truncate(r.summary, 200)}` : ''}`)
89
+ .join('\n')}`;
90
+ const issuesBlock = existingIssues.length === 0
91
+ ? 'No existing open issues — any opportunity you surface is new.'
92
+ : `**Existing open issues** (${existingIssues.length}) — skip overlaps:\n${existingIssues
93
+ .slice(0, 200)
94
+ .map((i) => `- [${i.id}] ${i.name}${i.description ? `\n ${truncate(i.description, 160)}` : ''}`)
95
+ .join('\n')}`;
96
+ return `${productBlock}
97
+
98
+ ${feedbackBlock}${focusBlock}
99
+
100
+ ${reportsBlock}
101
+
102
+ ${issuesBlock}
103
+
104
+ ## Budget and discipline
105
+ - Surface **at most ${maxSuggestions} opportunities**. Rank by confidence + evidence strength; drop the weakest.
106
+ - A "theme" needs at least ${minClusterSize} independent feedback mentions to count as high-confidence (solo mentions may still appear at low confidence if they're specific and concrete).
107
+
108
+ ${codeOnlyMode
109
+ ? `## How to work (code-only mode — no feedback or reports this run)
110
+ 1. Orient: Glob top-level source dirs, Read the README and any docs/ index, list the main routes/screens/commands. Goal: build a one-paragraph mental model of what the product already does.
111
+ 2. Identify candidate gaps from the code itself:
112
+ - Half-finished flows (UI exists but handler is a stub, route returns 501, TODO/FIXME clusters).
113
+ - Standard capabilities a product of this shape would normally have but doesn't (search, export, filtering, bulk actions, audit logs, settings, empty-state guidance, error recovery).
114
+ - Natural extensions of existing features (one-off where a list/multi version is the obvious next step).
115
+ - Inconsistencies (feature available in one entity but not its peers).
116
+ 3. For each candidate: (a) cross-check the existing-issues list for overlap, (b) grep more carefully to confirm the gap is real, not just code you missed.
117
+ 4. Rank by signal strength. Keep at most ${maxSuggestions}; cut hard. Skip pure refactors and tech debt.
118
+ 5. For each survivor: write a clear user outcome, cite **file paths** in \`supporting_evidence_ids\` (e.g. \`src/exports/index.ts:42\`), set \`source\` to \`code_analysis\`, and pick a confidence level honestly using the code-only rubric.
119
+ 6. Produce the final JSON described in the system prompt. If nothing meets the bar, emit an empty \`opportunities\` array with a summary that says so plainly.
120
+
121
+ Begin.`
122
+ : `## How to work
123
+ 1. Start with a lightweight orientation pass on the repo: Glob for top-level source dirs, Read the README and any docs/ index, grep for obvious domain concepts. Goal: know what the product already does before you synthesise what it should do.
124
+ 2. Scan feedbacks. Group by theme. Note which themes have ≥${minClusterSize} mentions.
125
+ 3. Scan intelligence reports. Note any gaps, trends, or competitor parity points.
126
+ 4. For each candidate theme: (a) check the existing-issues list for overlap, (b) **grep the code** to verify the feature isn't already implemented. If found in code but users don't seem to know, reframe as a discoverability opportunity instead of a net-new feature.
127
+ 5. Rank the survivors. Keep the top ${maxSuggestions} with the strongest evidence.
128
+ 6. For each: write a clear user outcome, cite evidence IDs, pick a confidence level honestly. In the description's "Rough scope" section, note what you verified in code (e.g. "confirmed no CSV export code path under src/exports/").
129
+ 7. Produce the final JSON described in the system prompt.
130
+
131
+ Begin.`}`;
132
+ }
133
+ function truncate(s, n) {
134
+ if (s.length <= n) {
135
+ return s;
136
+ }
137
+ return `${s.slice(0, n)}…`;
138
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Per-product discovery state for find-features. Storage at
3
+ * `~/.edsger/find-features-state/<productId>.json`.
4
+ *
5
+ * Tracks only run-status fields (last successful run, last attempt, last
6
+ * error) — feature discovery uses a time-based "since" window passed at
7
+ * call time, so there's no per-run cursor to persist. The earlier schema
8
+ * captured `lastSeenFeedbackId / lastSeenReportId / lastScannedCommitSha`
9
+ * but they were never read; trimmed in favour of a leaner schema. If a
10
+ * future run wants to skip already-clustered material, restore them and
11
+ * wire the read side at the same time.
12
+ *
13
+ * File layout + lock semantics shared via createScanStateModule.
14
+ */
15
+ import { type LockHandle } from '../find-shared/scan-state.js';
16
+ export type { LockHandle };
17
+ export interface FindFeaturesState {
18
+ lastRunAt?: string;
19
+ lastAttemptedAt?: string;
20
+ lastError?: string;
21
+ }
22
+ export declare const loadFindFeaturesState: (productId: string) => FindFeaturesState;
23
+ export declare const saveFindFeaturesState: (productId: string, state: FindFeaturesState) => void;
24
+ export declare const updateFindFeaturesState: (productId: string, patch: Partial<FindFeaturesState>) => FindFeaturesState;
25
+ export declare const acquireFindFeaturesLock: (productId: string, staleAfterMs?: number) => LockHandle | null;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Per-product discovery state for find-features. Storage at
3
+ * `~/.edsger/find-features-state/<productId>.json`.
4
+ *
5
+ * Tracks only run-status fields (last successful run, last attempt, last
6
+ * error) — feature discovery uses a time-based "since" window passed at
7
+ * call time, so there's no per-run cursor to persist. The earlier schema
8
+ * captured `lastSeenFeedbackId / lastSeenReportId / lastScannedCommitSha`
9
+ * but they were never read; trimmed in favour of a leaner schema. If a
10
+ * future run wants to skip already-clustered material, restore them and
11
+ * wire the read side at the same time.
12
+ *
13
+ * File layout + lock semantics shared via createScanStateModule.
14
+ */
15
+ import { createScanStateModule, } from '../find-shared/scan-state.js';
16
+ const m = createScanStateModule({
17
+ dirName: 'find-features-state',
18
+ });
19
+ export const loadFindFeaturesState = m.load;
20
+ export const saveFindFeaturesState = m.save;
21
+ export const updateFindFeaturesState = m.update;
22
+ export const acquireFindFeaturesLock = m.acquireLock;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Types for the find-features phase.
3
+ */
4
+ export type OpportunityConfidence = 'high' | 'medium' | 'low';
5
+ export type OpportunitySource = 'user_feedback' | 'competitor_gap' | 'market_trend' | 'adjacent_workflow' | 'code_analysis' | 'other';
6
+ export interface FeatureOpportunity {
7
+ /** Short, action-oriented title (e.g. "Add bulk CSV export for invoices"). */
8
+ title: string;
9
+ /** Structured markdown body — see prompt for the required sections. */
10
+ description: string;
11
+ /** One-line hypothesis of the user outcome the feature unlocks. */
12
+ user_outcome: string;
13
+ /** Rough confidence; keeps the agent honest about evidence strength. */
14
+ confidence: OpportunityConfidence;
15
+ /** What signal surfaced this idea. */
16
+ source: OpportunitySource;
17
+ /** Specific evidence IDs (feedback IDs, report IDs) backing the idea. */
18
+ supporting_evidence_ids: string[];
19
+ /** Free-form stable slug for logging/audit. Not used for dedup persistence. */
20
+ dedup_signature?: string;
21
+ }
22
+ export interface DiscoveryResult {
23
+ summary: string;
24
+ analyzed_through: string;
25
+ opportunities: FeatureOpportunity[];
26
+ }
27
+ export declare function isDiscoveryResult(value: unknown): value is DiscoveryResult;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Types for the find-features phase.
3
+ */
4
+ export function isDiscoveryResult(value) {
5
+ if (!value || typeof value !== 'object') {
6
+ return false;
7
+ }
8
+ const v = value;
9
+ return (typeof v.summary === 'string' &&
10
+ Array.isArray(v.opportunities) &&
11
+ v.opportunities.every((o) => o &&
12
+ typeof o === 'object' &&
13
+ typeof o.title === 'string' &&
14
+ typeof o.description === 'string' &&
15
+ typeof o.user_outcome === 'string'));
16
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Git helpers shared by the find-* phases (find-bugs, find-features,
3
+ * find-smells). All three clone a product's repo, sync to a branch, and need
4
+ * the same low-level rev/diff queries — keep them here so behaviour stays in
5
+ * lock-step.
6
+ *
7
+ * Read-only on the working tree; safe to call against any cwd that is a git
8
+ * repo.
9
+ */
10
+ export declare function gitRevParse(repoPath: string, ref: string): string;
11
+ /**
12
+ * Resolve the remote's default branch (e.g. "main", "master", "trunk") via the
13
+ * symbolic ref `refs/remotes/origin/HEAD`. Falls back to "main" if the ref is
14
+ * missing — the caller will surface a sync error if that's wrong.
15
+ */
16
+ export declare function detectDefaultBranch(repoPath: string): string;
17
+ /**
18
+ * True iff `ancestor` is reachable from `descendant` (i.e. `descendant`
19
+ * contains all of `ancestor`'s history). Used by incremental scans to decide
20
+ * whether a previously-scanned commit is still part of HEAD's history before
21
+ * trusting a `git diff base..head`.
22
+ */
23
+ export declare function isAncestor(repoPath: string, ancestor: string, descendant: string): boolean;
24
+ export declare function listChangedPaths(repoPath: string, baseSha: string, headSha: string): string[];
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Git helpers shared by the find-* phases (find-bugs, find-features,
3
+ * find-smells). All three clone a product's repo, sync to a branch, and need
4
+ * the same low-level rev/diff queries — keep them here so behaviour stays in
5
+ * lock-step.
6
+ *
7
+ * Read-only on the working tree; safe to call against any cwd that is a git
8
+ * repo.
9
+ */
10
+ import { execFileSync } from 'child_process';
11
+ export function gitRevParse(repoPath, ref) {
12
+ return execFileSync('git', ['rev-parse', ref], {
13
+ cwd: repoPath,
14
+ encoding: 'utf-8',
15
+ }).trim();
16
+ }
17
+ /**
18
+ * Resolve the remote's default branch (e.g. "main", "master", "trunk") via the
19
+ * symbolic ref `refs/remotes/origin/HEAD`. Falls back to "main" if the ref is
20
+ * missing — the caller will surface a sync error if that's wrong.
21
+ */
22
+ export function detectDefaultBranch(repoPath) {
23
+ try {
24
+ const ref = execFileSync('git', ['symbolic-ref', '--short', 'refs/remotes/origin/HEAD'], { cwd: repoPath, encoding: 'utf-8' }).trim();
25
+ return ref.replace(/^origin\//, '');
26
+ }
27
+ catch {
28
+ return 'main';
29
+ }
30
+ }
31
+ /**
32
+ * True iff `ancestor` is reachable from `descendant` (i.e. `descendant`
33
+ * contains all of `ancestor`'s history). Used by incremental scans to decide
34
+ * whether a previously-scanned commit is still part of HEAD's history before
35
+ * trusting a `git diff base..head`.
36
+ */
37
+ export function isAncestor(repoPath, ancestor, descendant) {
38
+ try {
39
+ execFileSync('git', ['merge-base', '--is-ancestor', ancestor, descendant], {
40
+ cwd: repoPath,
41
+ stdio: 'pipe',
42
+ });
43
+ return true;
44
+ }
45
+ catch {
46
+ return false;
47
+ }
48
+ }
49
+ export function listChangedPaths(repoPath, baseSha, headSha) {
50
+ try {
51
+ const out = execFileSync('git', ['diff', '--name-only', `${baseSha}..${headSha}`], { cwd: repoPath, encoding: 'utf-8' });
52
+ return out
53
+ .split('\n')
54
+ .map((s) => s.trim())
55
+ .filter((s) => s.length > 0);
56
+ }
57
+ catch {
58
+ return [];
59
+ }
60
+ }