@reqord/cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (649) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +73 -0
  3. package/dist/commands/context/init.d.ts +3 -0
  4. package/dist/commands/context/init.d.ts.map +1 -0
  5. package/dist/commands/context/init.js +38 -0
  6. package/dist/commands/context/init.js.map +1 -0
  7. package/dist/commands/context/show.d.ts +3 -0
  8. package/dist/commands/context/show.d.ts.map +1 -0
  9. package/dist/commands/context/show.js +69 -0
  10. package/dist/commands/context/show.js.map +1 -0
  11. package/dist/commands/context/update.d.ts +3 -0
  12. package/dist/commands/context/update.d.ts.map +1 -0
  13. package/dist/commands/context/update.js +58 -0
  14. package/dist/commands/context/update.js.map +1 -0
  15. package/dist/commands/feedback/close.d.ts +3 -0
  16. package/dist/commands/feedback/close.d.ts.map +1 -0
  17. package/dist/commands/feedback/close.js +32 -0
  18. package/dist/commands/feedback/close.js.map +1 -0
  19. package/dist/commands/feedback/create.d.ts +3 -0
  20. package/dist/commands/feedback/create.d.ts.map +1 -0
  21. package/dist/commands/feedback/create.js +32 -0
  22. package/dist/commands/feedback/create.js.map +1 -0
  23. package/dist/commands/feedback/index.d.ts +3 -0
  24. package/dist/commands/feedback/index.d.ts.map +1 -0
  25. package/dist/commands/feedback/index.js +20 -0
  26. package/dist/commands/feedback/index.js.map +1 -0
  27. package/dist/commands/feedback/link.d.ts +3 -0
  28. package/dist/commands/feedback/link.d.ts.map +1 -0
  29. package/dist/commands/feedback/link.js +54 -0
  30. package/dist/commands/feedback/link.js.map +1 -0
  31. package/dist/commands/feedback/list.d.ts +3 -0
  32. package/dist/commands/feedback/list.d.ts.map +1 -0
  33. package/dist/commands/feedback/list.js +50 -0
  34. package/dist/commands/feedback/list.js.map +1 -0
  35. package/dist/commands/feedback/resolve.d.ts +3 -0
  36. package/dist/commands/feedback/resolve.d.ts.map +1 -0
  37. package/dist/commands/feedback/resolve.js +24 -0
  38. package/dist/commands/feedback/resolve.js.map +1 -0
  39. package/dist/commands/feedback/show.d.ts +3 -0
  40. package/dist/commands/feedback/show.d.ts.map +1 -0
  41. package/dist/commands/feedback/show.js +35 -0
  42. package/dist/commands/feedback/show.js.map +1 -0
  43. package/dist/commands/feedback/sync.d.ts +3 -0
  44. package/dist/commands/feedback/sync.d.ts.map +1 -0
  45. package/dist/commands/feedback/sync.js +29 -0
  46. package/dist/commands/feedback/sync.js.map +1 -0
  47. package/dist/commands/feedback/unlink.d.ts +3 -0
  48. package/dist/commands/feedback/unlink.d.ts.map +1 -0
  49. package/dist/commands/feedback/unlink.js +39 -0
  50. package/dist/commands/feedback/unlink.js.map +1 -0
  51. package/dist/commands/impact/analyze.d.ts +3 -0
  52. package/dist/commands/impact/analyze.d.ts.map +1 -0
  53. package/dist/commands/impact/analyze.js +131 -0
  54. package/dist/commands/impact/analyze.js.map +1 -0
  55. package/dist/commands/impact/analyze.test.d.ts +2 -0
  56. package/dist/commands/impact/analyze.test.d.ts.map +1 -0
  57. package/dist/commands/impact/analyze.test.js +203 -0
  58. package/dist/commands/impact/analyze.test.js.map +1 -0
  59. package/dist/commands/impact/index.d.ts +3 -0
  60. package/dist/commands/impact/index.d.ts.map +1 -0
  61. package/dist/commands/impact/index.js +8 -0
  62. package/dist/commands/impact/index.js.map +1 -0
  63. package/dist/commands/impact/integration.test.d.ts +2 -0
  64. package/dist/commands/impact/integration.test.d.ts.map +1 -0
  65. package/dist/commands/impact/integration.test.js +183 -0
  66. package/dist/commands/impact/integration.test.js.map +1 -0
  67. package/dist/commands/impact/notify.d.ts +3 -0
  68. package/dist/commands/impact/notify.d.ts.map +1 -0
  69. package/dist/commands/impact/notify.js +78 -0
  70. package/dist/commands/impact/notify.js.map +1 -0
  71. package/dist/commands/impact/notify.test.d.ts +2 -0
  72. package/dist/commands/impact/notify.test.d.ts.map +1 -0
  73. package/dist/commands/impact/notify.test.js +136 -0
  74. package/dist/commands/impact/notify.test.js.map +1 -0
  75. package/dist/commands/init.d.ts +3 -0
  76. package/dist/commands/init.d.ts.map +1 -0
  77. package/dist/commands/init.js +31 -0
  78. package/dist/commands/init.js.map +1 -0
  79. package/dist/commands/issue/create.d.ts +3 -0
  80. package/dist/commands/issue/create.d.ts.map +1 -0
  81. package/dist/commands/issue/create.js +62 -0
  82. package/dist/commands/issue/create.js.map +1 -0
  83. package/dist/commands/issue/create.test.d.ts +2 -0
  84. package/dist/commands/issue/create.test.d.ts.map +1 -0
  85. package/dist/commands/issue/create.test.js +204 -0
  86. package/dist/commands/issue/create.test.js.map +1 -0
  87. package/dist/commands/issue/fetch.d.ts +3 -0
  88. package/dist/commands/issue/fetch.d.ts.map +1 -0
  89. package/dist/commands/issue/fetch.js +66 -0
  90. package/dist/commands/issue/fetch.js.map +1 -0
  91. package/dist/commands/issue/fetch.test.d.ts +2 -0
  92. package/dist/commands/issue/fetch.test.d.ts.map +1 -0
  93. package/dist/commands/issue/fetch.test.js +135 -0
  94. package/dist/commands/issue/fetch.test.js.map +1 -0
  95. package/dist/commands/issue/index.d.ts +3 -0
  96. package/dist/commands/issue/index.d.ts.map +1 -0
  97. package/dist/commands/issue/index.js +13 -0
  98. package/dist/commands/issue/index.js.map +1 -0
  99. package/dist/commands/issue/sync.d.ts +4 -0
  100. package/dist/commands/issue/sync.d.ts.map +1 -0
  101. package/dist/commands/issue/sync.js +65 -0
  102. package/dist/commands/issue/sync.js.map +1 -0
  103. package/dist/commands/issue/sync.test.d.ts +2 -0
  104. package/dist/commands/issue/sync.test.d.ts.map +1 -0
  105. package/dist/commands/issue/sync.test.js +275 -0
  106. package/dist/commands/issue/sync.test.js.map +1 -0
  107. package/dist/commands/issue/validate.d.ts +14 -0
  108. package/dist/commands/issue/validate.d.ts.map +1 -0
  109. package/dist/commands/issue/validate.js +88 -0
  110. package/dist/commands/issue/validate.js.map +1 -0
  111. package/dist/commands/issue/validate.test.d.ts +2 -0
  112. package/dist/commands/issue/validate.test.d.ts.map +1 -0
  113. package/dist/commands/issue/validate.test.js +83 -0
  114. package/dist/commands/issue/validate.test.js.map +1 -0
  115. package/dist/commands/migrate-to-yaml.d.ts +3 -0
  116. package/dist/commands/migrate-to-yaml.d.ts.map +1 -0
  117. package/dist/commands/migrate-to-yaml.js +53 -0
  118. package/dist/commands/migrate-to-yaml.js.map +1 -0
  119. package/dist/commands/req/approve.d.ts +3 -0
  120. package/dist/commands/req/approve.d.ts.map +1 -0
  121. package/dist/commands/req/approve.js +61 -0
  122. package/dist/commands/req/approve.js.map +1 -0
  123. package/dist/commands/req/approve.test.d.ts +2 -0
  124. package/dist/commands/req/approve.test.d.ts.map +1 -0
  125. package/dist/commands/req/approve.test.js +207 -0
  126. package/dist/commands/req/approve.test.js.map +1 -0
  127. package/dist/commands/req/create.d.ts +3 -0
  128. package/dist/commands/req/create.d.ts.map +1 -0
  129. package/dist/commands/req/create.js +33 -0
  130. package/dist/commands/req/create.js.map +1 -0
  131. package/dist/commands/req/delete.d.ts +3 -0
  132. package/dist/commands/req/delete.d.ts.map +1 -0
  133. package/dist/commands/req/delete.js +37 -0
  134. package/dist/commands/req/delete.js.map +1 -0
  135. package/dist/commands/req/draft.d.ts +3 -0
  136. package/dist/commands/req/draft.d.ts.map +1 -0
  137. package/dist/commands/req/draft.js +93 -0
  138. package/dist/commands/req/draft.js.map +1 -0
  139. package/dist/commands/req/draft.test.d.ts +2 -0
  140. package/dist/commands/req/draft.test.d.ts.map +1 -0
  141. package/dist/commands/req/draft.test.js +235 -0
  142. package/dist/commands/req/draft.test.js.map +1 -0
  143. package/dist/commands/req/history.d.ts +3 -0
  144. package/dist/commands/req/history.d.ts.map +1 -0
  145. package/dist/commands/req/history.js +48 -0
  146. package/dist/commands/req/history.js.map +1 -0
  147. package/dist/commands/req/implement.d.ts +3 -0
  148. package/dist/commands/req/implement.d.ts.map +1 -0
  149. package/dist/commands/req/implement.js +61 -0
  150. package/dist/commands/req/implement.js.map +1 -0
  151. package/dist/commands/req/implement.test.d.ts +2 -0
  152. package/dist/commands/req/implement.test.d.ts.map +1 -0
  153. package/dist/commands/req/implement.test.js +235 -0
  154. package/dist/commands/req/implement.test.js.map +1 -0
  155. package/dist/commands/req/implemented.d.ts +3 -0
  156. package/dist/commands/req/implemented.d.ts.map +1 -0
  157. package/dist/commands/req/implemented.js +46 -0
  158. package/dist/commands/req/implemented.js.map +1 -0
  159. package/dist/commands/req/implemented.test.d.ts +2 -0
  160. package/dist/commands/req/implemented.test.d.ts.map +1 -0
  161. package/dist/commands/req/implemented.test.js +157 -0
  162. package/dist/commands/req/implemented.test.js.map +1 -0
  163. package/dist/commands/req/list.d.ts +3 -0
  164. package/dist/commands/req/list.d.ts.map +1 -0
  165. package/dist/commands/req/list.js +50 -0
  166. package/dist/commands/req/list.js.map +1 -0
  167. package/dist/commands/req/show.d.ts +3 -0
  168. package/dist/commands/req/show.d.ts.map +1 -0
  169. package/dist/commands/req/show.js +40 -0
  170. package/dist/commands/req/show.js.map +1 -0
  171. package/dist/commands/req/update.d.ts +3 -0
  172. package/dist/commands/req/update.d.ts.map +1 -0
  173. package/dist/commands/req/update.js +112 -0
  174. package/dist/commands/req/update.js.map +1 -0
  175. package/dist/commands/req/validate.d.ts +3 -0
  176. package/dist/commands/req/validate.d.ts.map +1 -0
  177. package/dist/commands/req/validate.js +71 -0
  178. package/dist/commands/req/validate.js.map +1 -0
  179. package/dist/commands/spec/approve.d.ts +3 -0
  180. package/dist/commands/spec/approve.d.ts.map +1 -0
  181. package/dist/commands/spec/approve.js +88 -0
  182. package/dist/commands/spec/approve.js.map +1 -0
  183. package/dist/commands/spec/approve.test.d.ts +2 -0
  184. package/dist/commands/spec/approve.test.d.ts.map +1 -0
  185. package/dist/commands/spec/approve.test.js +304 -0
  186. package/dist/commands/spec/approve.test.js.map +1 -0
  187. package/dist/commands/spec/coverage.d.ts +3 -0
  188. package/dist/commands/spec/coverage.d.ts.map +1 -0
  189. package/dist/commands/spec/coverage.js +57 -0
  190. package/dist/commands/spec/coverage.js.map +1 -0
  191. package/dist/commands/spec/create.d.ts +3 -0
  192. package/dist/commands/spec/create.d.ts.map +1 -0
  193. package/dist/commands/spec/create.js +30 -0
  194. package/dist/commands/spec/create.js.map +1 -0
  195. package/dist/commands/spec/design.d.ts +3 -0
  196. package/dist/commands/spec/design.d.ts.map +1 -0
  197. package/dist/commands/spec/design.js +30 -0
  198. package/dist/commands/spec/design.js.map +1 -0
  199. package/dist/commands/spec/draft.d.ts +3 -0
  200. package/dist/commands/spec/draft.d.ts.map +1 -0
  201. package/dist/commands/spec/draft.js +93 -0
  202. package/dist/commands/spec/draft.js.map +1 -0
  203. package/dist/commands/spec/draft.test.d.ts +2 -0
  204. package/dist/commands/spec/draft.test.d.ts.map +1 -0
  205. package/dist/commands/spec/draft.test.js +213 -0
  206. package/dist/commands/spec/draft.test.js.map +1 -0
  207. package/dist/commands/spec/history.d.ts +3 -0
  208. package/dist/commands/spec/history.d.ts.map +1 -0
  209. package/dist/commands/spec/history.js +48 -0
  210. package/dist/commands/spec/history.js.map +1 -0
  211. package/dist/commands/spec/history.test.d.ts +2 -0
  212. package/dist/commands/spec/history.test.d.ts.map +1 -0
  213. package/dist/commands/spec/history.test.js +137 -0
  214. package/dist/commands/spec/history.test.js.map +1 -0
  215. package/dist/commands/spec/implement.d.ts +3 -0
  216. package/dist/commands/spec/implement.d.ts.map +1 -0
  217. package/dist/commands/spec/implement.js +41 -0
  218. package/dist/commands/spec/implement.js.map +1 -0
  219. package/dist/commands/spec/implement.test.d.ts +2 -0
  220. package/dist/commands/spec/implement.test.d.ts.map +1 -0
  221. package/dist/commands/spec/implement.test.js +118 -0
  222. package/dist/commands/spec/implement.test.js.map +1 -0
  223. package/dist/commands/spec/implemented.d.ts +3 -0
  224. package/dist/commands/spec/implemented.d.ts.map +1 -0
  225. package/dist/commands/spec/implemented.js +56 -0
  226. package/dist/commands/spec/implemented.js.map +1 -0
  227. package/dist/commands/spec/implemented.test.d.ts +2 -0
  228. package/dist/commands/spec/implemented.test.d.ts.map +1 -0
  229. package/dist/commands/spec/implemented.test.js +175 -0
  230. package/dist/commands/spec/implemented.test.js.map +1 -0
  231. package/dist/commands/spec/list.d.ts +3 -0
  232. package/dist/commands/spec/list.d.ts.map +1 -0
  233. package/dist/commands/spec/list.js +53 -0
  234. package/dist/commands/spec/list.js.map +1 -0
  235. package/dist/commands/spec/research.d.ts +3 -0
  236. package/dist/commands/spec/research.d.ts.map +1 -0
  237. package/dist/commands/spec/research.js +30 -0
  238. package/dist/commands/spec/research.js.map +1 -0
  239. package/dist/commands/spec/show.d.ts +3 -0
  240. package/dist/commands/spec/show.d.ts.map +1 -0
  241. package/dist/commands/spec/show.js +51 -0
  242. package/dist/commands/spec/show.js.map +1 -0
  243. package/dist/commands/spec/spec-approval-flow.integration.test.d.ts +2 -0
  244. package/dist/commands/spec/spec-approval-flow.integration.test.d.ts.map +1 -0
  245. package/dist/commands/spec/spec-approval-flow.integration.test.js +249 -0
  246. package/dist/commands/spec/spec-approval-flow.integration.test.js.map +1 -0
  247. package/dist/commands/spec/update.d.ts +3 -0
  248. package/dist/commands/spec/update.d.ts.map +1 -0
  249. package/dist/commands/spec/update.js +81 -0
  250. package/dist/commands/spec/update.js.map +1 -0
  251. package/dist/commands/spec/update.test.d.ts +2 -0
  252. package/dist/commands/spec/update.test.d.ts.map +1 -0
  253. package/dist/commands/spec/update.test.js +172 -0
  254. package/dist/commands/spec/update.test.js.map +1 -0
  255. package/dist/commands/spec/validate.d.ts +3 -0
  256. package/dist/commands/spec/validate.d.ts.map +1 -0
  257. package/dist/commands/spec/validate.js +62 -0
  258. package/dist/commands/spec/validate.js.map +1 -0
  259. package/dist/commands/spec/validate.test.d.ts +2 -0
  260. package/dist/commands/spec/validate.test.d.ts.map +1 -0
  261. package/dist/commands/spec/validate.test.js +135 -0
  262. package/dist/commands/spec/validate.test.js.map +1 -0
  263. package/dist/commands/status.d.ts +3 -0
  264. package/dist/commands/status.d.ts.map +1 -0
  265. package/dist/commands/status.js +190 -0
  266. package/dist/commands/status.js.map +1 -0
  267. package/dist/commands/status.test.d.ts +2 -0
  268. package/dist/commands/status.test.d.ts.map +1 -0
  269. package/dist/commands/status.test.js +175 -0
  270. package/dist/commands/status.test.js.map +1 -0
  271. package/dist/commands/task/create.d.ts +3 -0
  272. package/dist/commands/task/create.d.ts.map +1 -0
  273. package/dist/commands/task/create.js +62 -0
  274. package/dist/commands/task/create.js.map +1 -0
  275. package/dist/commands/task/create.test.d.ts +2 -0
  276. package/dist/commands/task/create.test.d.ts.map +1 -0
  277. package/dist/commands/task/create.test.js +204 -0
  278. package/dist/commands/task/create.test.js.map +1 -0
  279. package/dist/commands/task/fetch.d.ts +3 -0
  280. package/dist/commands/task/fetch.d.ts.map +1 -0
  281. package/dist/commands/task/fetch.js +66 -0
  282. package/dist/commands/task/fetch.js.map +1 -0
  283. package/dist/commands/task/fetch.test.d.ts +2 -0
  284. package/dist/commands/task/fetch.test.d.ts.map +1 -0
  285. package/dist/commands/task/fetch.test.js +135 -0
  286. package/dist/commands/task/fetch.test.js.map +1 -0
  287. package/dist/commands/task/index.d.ts +3 -0
  288. package/dist/commands/task/index.d.ts.map +1 -0
  289. package/dist/commands/task/index.js +13 -0
  290. package/dist/commands/task/index.js.map +1 -0
  291. package/dist/commands/task/sync.d.ts +4 -0
  292. package/dist/commands/task/sync.d.ts.map +1 -0
  293. package/dist/commands/task/sync.js +65 -0
  294. package/dist/commands/task/sync.js.map +1 -0
  295. package/dist/commands/task/sync.test.d.ts +2 -0
  296. package/dist/commands/task/sync.test.d.ts.map +1 -0
  297. package/dist/commands/task/sync.test.js +275 -0
  298. package/dist/commands/task/sync.test.js.map +1 -0
  299. package/dist/commands/task/validate.d.ts +14 -0
  300. package/dist/commands/task/validate.d.ts.map +1 -0
  301. package/dist/commands/task/validate.js +88 -0
  302. package/dist/commands/task/validate.js.map +1 -0
  303. package/dist/commands/task/validate.test.d.ts +2 -0
  304. package/dist/commands/task/validate.test.d.ts.map +1 -0
  305. package/dist/commands/task/validate.test.js +83 -0
  306. package/dist/commands/task/validate.test.js.map +1 -0
  307. package/dist/commands/ui.d.ts +3 -0
  308. package/dist/commands/ui.d.ts.map +1 -0
  309. package/dist/commands/ui.js +107 -0
  310. package/dist/commands/ui.js.map +1 -0
  311. package/dist/commands/validate/impl.d.ts +3 -0
  312. package/dist/commands/validate/impl.d.ts.map +1 -0
  313. package/dist/commands/validate/impl.js +71 -0
  314. package/dist/commands/validate/impl.js.map +1 -0
  315. package/dist/commands/validate/impl.test.d.ts +2 -0
  316. package/dist/commands/validate/impl.test.d.ts.map +1 -0
  317. package/dist/commands/validate/impl.test.js +83 -0
  318. package/dist/commands/validate/impl.test.js.map +1 -0
  319. package/dist/commands/version/version.d.ts +3 -0
  320. package/dist/commands/version/version.d.ts.map +1 -0
  321. package/dist/commands/version/version.js +61 -0
  322. package/dist/commands/version/version.js.map +1 -0
  323. package/dist/commands/version/version.test.d.ts +2 -0
  324. package/dist/commands/version/version.test.d.ts.map +1 -0
  325. package/dist/commands/version/version.test.js +262 -0
  326. package/dist/commands/version/version.test.js.map +1 -0
  327. package/dist/index.d.ts +3 -0
  328. package/dist/index.d.ts.map +1 -0
  329. package/dist/index.js +114 -0
  330. package/dist/index.js.map +1 -0
  331. package/dist/middleware/reqord-check.d.ts +2 -0
  332. package/dist/middleware/reqord-check.d.ts.map +1 -0
  333. package/dist/middleware/reqord-check.js +9 -0
  334. package/dist/middleware/reqord-check.js.map +1 -0
  335. package/dist/middleware/reqord-check.test.d.ts +2 -0
  336. package/dist/middleware/reqord-check.test.d.ts.map +1 -0
  337. package/dist/middleware/reqord-check.test.js +44 -0
  338. package/dist/middleware/reqord-check.test.js.map +1 -0
  339. package/dist/repositories/__tests__/file-system-yaml.test.d.ts +2 -0
  340. package/dist/repositories/__tests__/file-system-yaml.test.d.ts.map +1 -0
  341. package/dist/repositories/__tests__/file-system-yaml.test.js +132 -0
  342. package/dist/repositories/__tests__/file-system-yaml.test.js.map +1 -0
  343. package/dist/repositories/feedback.d.ts +7 -0
  344. package/dist/repositories/feedback.d.ts.map +1 -0
  345. package/dist/repositories/feedback.js +62 -0
  346. package/dist/repositories/feedback.js.map +1 -0
  347. package/dist/repositories/feedback.test.d.ts +2 -0
  348. package/dist/repositories/feedback.test.d.ts.map +1 -0
  349. package/dist/repositories/feedback.test.js +108 -0
  350. package/dist/repositories/feedback.test.js.map +1 -0
  351. package/dist/repositories/file-system-yaml.test.d.ts +2 -0
  352. package/dist/repositories/file-system-yaml.test.d.ts.map +1 -0
  353. package/dist/repositories/file-system-yaml.test.js +246 -0
  354. package/dist/repositories/file-system-yaml.test.js.map +1 -0
  355. package/dist/repositories/file-system.d.ts +15 -0
  356. package/dist/repositories/file-system.d.ts.map +1 -0
  357. package/dist/repositories/file-system.js +156 -0
  358. package/dist/repositories/file-system.js.map +1 -0
  359. package/dist/repositories/git.d.ts +8 -0
  360. package/dist/repositories/git.d.ts.map +1 -0
  361. package/dist/repositories/git.js +29 -0
  362. package/dist/repositories/git.js.map +1 -0
  363. package/dist/repositories/git.test.d.ts +2 -0
  364. package/dist/repositories/git.test.d.ts.map +1 -0
  365. package/dist/repositories/git.test.js +112 -0
  366. package/dist/repositories/git.test.js.map +1 -0
  367. package/dist/repositories/github.d.ts +18 -0
  368. package/dist/repositories/github.d.ts.map +1 -0
  369. package/dist/repositories/github.js +59 -0
  370. package/dist/repositories/github.js.map +1 -0
  371. package/dist/repositories/github.test.d.ts +2 -0
  372. package/dist/repositories/github.test.d.ts.map +1 -0
  373. package/dist/repositories/github.test.js +180 -0
  374. package/dist/repositories/github.test.js.map +1 -0
  375. package/dist/repositories/project-context.d.ts +8 -0
  376. package/dist/repositories/project-context.d.ts.map +1 -0
  377. package/dist/repositories/project-context.js +43 -0
  378. package/dist/repositories/project-context.js.map +1 -0
  379. package/dist/repositories/requirement.d.ts +9 -0
  380. package/dist/repositories/requirement.d.ts.map +1 -0
  381. package/dist/repositories/requirement.js +65 -0
  382. package/dist/repositories/requirement.js.map +1 -0
  383. package/dist/repositories/specification.d.ts +10 -0
  384. package/dist/repositories/specification.d.ts.map +1 -0
  385. package/dist/repositories/specification.js +67 -0
  386. package/dist/repositories/specification.js.map +1 -0
  387. package/dist/services/approval-service.d.ts +28 -0
  388. package/dist/services/approval-service.d.ts.map +1 -0
  389. package/dist/services/approval-service.js +59 -0
  390. package/dist/services/approval-service.js.map +1 -0
  391. package/dist/services/approval-service.test.d.ts +2 -0
  392. package/dist/services/approval-service.test.d.ts.map +1 -0
  393. package/dist/services/approval-service.test.js +187 -0
  394. package/dist/services/approval-service.test.js.map +1 -0
  395. package/dist/services/context-service.d.ts +33 -0
  396. package/dist/services/context-service.d.ts.map +1 -0
  397. package/dist/services/context-service.js +118 -0
  398. package/dist/services/context-service.js.map +1 -0
  399. package/dist/services/context-service.test.d.ts +2 -0
  400. package/dist/services/context-service.test.d.ts.map +1 -0
  401. package/dist/services/context-service.test.js +182 -0
  402. package/dist/services/context-service.test.js.map +1 -0
  403. package/dist/services/coverage-service.d.ts +27 -0
  404. package/dist/services/coverage-service.d.ts.map +1 -0
  405. package/dist/services/coverage-service.js +48 -0
  406. package/dist/services/coverage-service.js.map +1 -0
  407. package/dist/services/coverage-service.test.d.ts +2 -0
  408. package/dist/services/coverage-service.test.d.ts.map +1 -0
  409. package/dist/services/coverage-service.test.js +100 -0
  410. package/dist/services/coverage-service.test.js.map +1 -0
  411. package/dist/services/draft-reversion-service.d.ts +11 -0
  412. package/dist/services/draft-reversion-service.d.ts.map +1 -0
  413. package/dist/services/draft-reversion-service.js +132 -0
  414. package/dist/services/draft-reversion-service.js.map +1 -0
  415. package/dist/services/draft-reversion-service.test.d.ts +2 -0
  416. package/dist/services/draft-reversion-service.test.d.ts.map +1 -0
  417. package/dist/services/draft-reversion-service.test.js +349 -0
  418. package/dist/services/draft-reversion-service.test.js.map +1 -0
  419. package/dist/services/feedback-service.d.ts +64 -0
  420. package/dist/services/feedback-service.d.ts.map +1 -0
  421. package/dist/services/feedback-service.js +329 -0
  422. package/dist/services/feedback-service.js.map +1 -0
  423. package/dist/services/feedback-service.test.d.ts +2 -0
  424. package/dist/services/feedback-service.test.d.ts.map +1 -0
  425. package/dist/services/feedback-service.test.js +977 -0
  426. package/dist/services/feedback-service.test.js.map +1 -0
  427. package/dist/services/feedback-sync-service.d.ts +7 -0
  428. package/dist/services/feedback-sync-service.d.ts.map +1 -0
  429. package/dist/services/feedback-sync-service.js +70 -0
  430. package/dist/services/feedback-sync-service.js.map +1 -0
  431. package/dist/services/feedback-sync-service.test.d.ts +2 -0
  432. package/dist/services/feedback-sync-service.test.d.ts.map +1 -0
  433. package/dist/services/feedback-sync-service.test.js +328 -0
  434. package/dist/services/feedback-sync-service.test.js.map +1 -0
  435. package/dist/services/github-client.d.ts +42 -0
  436. package/dist/services/github-client.d.ts.map +1 -0
  437. package/dist/services/github-client.js +120 -0
  438. package/dist/services/github-client.js.map +1 -0
  439. package/dist/services/github-client.test.d.ts +2 -0
  440. package/dist/services/github-client.test.d.ts.map +1 -0
  441. package/dist/services/github-client.test.js +393 -0
  442. package/dist/services/github-client.test.js.map +1 -0
  443. package/dist/services/impact-service.d.ts +57 -0
  444. package/dist/services/impact-service.d.ts.map +1 -0
  445. package/dist/services/impact-service.js +302 -0
  446. package/dist/services/impact-service.js.map +1 -0
  447. package/dist/services/impact-service.test.d.ts +2 -0
  448. package/dist/services/impact-service.test.d.ts.map +1 -0
  449. package/dist/services/impact-service.test.js +566 -0
  450. package/dist/services/impact-service.test.js.map +1 -0
  451. package/dist/services/impl-validation-service.d.ts +63 -0
  452. package/dist/services/impl-validation-service.d.ts.map +1 -0
  453. package/dist/services/impl-validation-service.js +189 -0
  454. package/dist/services/impl-validation-service.js.map +1 -0
  455. package/dist/services/impl-validation-service.test.d.ts +2 -0
  456. package/dist/services/impl-validation-service.test.d.ts.map +1 -0
  457. package/dist/services/impl-validation-service.test.js +407 -0
  458. package/dist/services/impl-validation-service.test.js.map +1 -0
  459. package/dist/services/init-service.d.ts +6 -0
  460. package/dist/services/init-service.d.ts.map +1 -0
  461. package/dist/services/init-service.js +57 -0
  462. package/dist/services/init-service.js.map +1 -0
  463. package/dist/services/init-service.test.d.ts +2 -0
  464. package/dist/services/init-service.test.d.ts.map +1 -0
  465. package/dist/services/init-service.test.js +103 -0
  466. package/dist/services/init-service.test.js.map +1 -0
  467. package/dist/services/issue-fetch-service.d.ts +24 -0
  468. package/dist/services/issue-fetch-service.d.ts.map +1 -0
  469. package/dist/services/issue-fetch-service.js +109 -0
  470. package/dist/services/issue-fetch-service.js.map +1 -0
  471. package/dist/services/issue-fetch-service.test.d.ts +2 -0
  472. package/dist/services/issue-fetch-service.test.d.ts.map +1 -0
  473. package/dist/services/issue-fetch-service.test.js +243 -0
  474. package/dist/services/issue-fetch-service.test.js.map +1 -0
  475. package/dist/services/issue-service.d.ts +25 -0
  476. package/dist/services/issue-service.d.ts.map +1 -0
  477. package/dist/services/issue-service.js +114 -0
  478. package/dist/services/issue-service.js.map +1 -0
  479. package/dist/services/issue-service.test.d.ts +2 -0
  480. package/dist/services/issue-service.test.d.ts.map +1 -0
  481. package/dist/services/issue-service.test.js +235 -0
  482. package/dist/services/issue-service.test.js.map +1 -0
  483. package/dist/services/issue-sync-service.d.ts +25 -0
  484. package/dist/services/issue-sync-service.d.ts.map +1 -0
  485. package/dist/services/issue-sync-service.js +84 -0
  486. package/dist/services/issue-sync-service.js.map +1 -0
  487. package/dist/services/issue-sync-service.test.d.ts +2 -0
  488. package/dist/services/issue-sync-service.test.d.ts.map +1 -0
  489. package/dist/services/issue-sync-service.test.js +187 -0
  490. package/dist/services/issue-sync-service.test.js.map +1 -0
  491. package/dist/services/migration-service.d.ts +19 -0
  492. package/dist/services/migration-service.d.ts.map +1 -0
  493. package/dist/services/migration-service.js +114 -0
  494. package/dist/services/migration-service.js.map +1 -0
  495. package/dist/services/migration-service.test.d.ts +2 -0
  496. package/dist/services/migration-service.test.d.ts.map +1 -0
  497. package/dist/services/migration-service.test.js +269 -0
  498. package/dist/services/migration-service.test.js.map +1 -0
  499. package/dist/services/reqord-comment.d.ts +15 -0
  500. package/dist/services/reqord-comment.d.ts.map +1 -0
  501. package/dist/services/reqord-comment.js +46 -0
  502. package/dist/services/reqord-comment.js.map +1 -0
  503. package/dist/services/reqord-comment.test.d.ts +2 -0
  504. package/dist/services/reqord-comment.test.d.ts.map +1 -0
  505. package/dist/services/reqord-comment.test.js +304 -0
  506. package/dist/services/reqord-comment.test.js.map +1 -0
  507. package/dist/services/requirement-approval-handler.d.ts +15 -0
  508. package/dist/services/requirement-approval-handler.d.ts.map +1 -0
  509. package/dist/services/requirement-approval-handler.js +68 -0
  510. package/dist/services/requirement-approval-handler.js.map +1 -0
  511. package/dist/services/requirement-approval-handler.test.d.ts +2 -0
  512. package/dist/services/requirement-approval-handler.test.d.ts.map +1 -0
  513. package/dist/services/requirement-approval-handler.test.js +41 -0
  514. package/dist/services/requirement-approval-handler.test.js.map +1 -0
  515. package/dist/services/requirement-service.d.ts +38 -0
  516. package/dist/services/requirement-service.d.ts.map +1 -0
  517. package/dist/services/requirement-service.js +167 -0
  518. package/dist/services/requirement-service.js.map +1 -0
  519. package/dist/services/requirement-service.test.d.ts +2 -0
  520. package/dist/services/requirement-service.test.d.ts.map +1 -0
  521. package/dist/services/requirement-service.test.js +356 -0
  522. package/dist/services/requirement-service.test.js.map +1 -0
  523. package/dist/services/spec-approval-helpers.d.ts +15 -0
  524. package/dist/services/spec-approval-helpers.d.ts.map +1 -0
  525. package/dist/services/spec-approval-helpers.js +84 -0
  526. package/dist/services/spec-approval-helpers.js.map +1 -0
  527. package/dist/services/spec-approval-helpers.test.d.ts +2 -0
  528. package/dist/services/spec-approval-helpers.test.d.ts.map +1 -0
  529. package/dist/services/spec-approval-helpers.test.js +132 -0
  530. package/dist/services/spec-approval-helpers.test.js.map +1 -0
  531. package/dist/services/spec-validation-service.d.ts +26 -0
  532. package/dist/services/spec-validation-service.d.ts.map +1 -0
  533. package/dist/services/spec-validation-service.js +235 -0
  534. package/dist/services/spec-validation-service.js.map +1 -0
  535. package/dist/services/spec-validation-service.test.d.ts +2 -0
  536. package/dist/services/spec-validation-service.test.d.ts.map +1 -0
  537. package/dist/services/spec-validation-service.test.js +149 -0
  538. package/dist/services/spec-validation-service.test.js.map +1 -0
  539. package/dist/services/specification-approval-handler.d.ts +3 -0
  540. package/dist/services/specification-approval-handler.d.ts.map +1 -0
  541. package/dist/services/specification-approval-handler.js +32 -0
  542. package/dist/services/specification-approval-handler.js.map +1 -0
  543. package/dist/services/specification-service.d.ts +63 -0
  544. package/dist/services/specification-service.d.ts.map +1 -0
  545. package/dist/services/specification-service.js +194 -0
  546. package/dist/services/specification-service.js.map +1 -0
  547. package/dist/services/specification-service.test.d.ts +2 -0
  548. package/dist/services/specification-service.test.d.ts.map +1 -0
  549. package/dist/services/specification-service.test.js +549 -0
  550. package/dist/services/specification-service.test.js.map +1 -0
  551. package/dist/services/status-service.d.ts +72 -0
  552. package/dist/services/status-service.d.ts.map +1 -0
  553. package/dist/services/status-service.js +253 -0
  554. package/dist/services/status-service.js.map +1 -0
  555. package/dist/services/status-service.test.d.ts +2 -0
  556. package/dist/services/status-service.test.d.ts.map +1 -0
  557. package/dist/services/status-service.test.js +447 -0
  558. package/dist/services/status-service.test.js.map +1 -0
  559. package/dist/services/task-fetch-service.d.ts +24 -0
  560. package/dist/services/task-fetch-service.d.ts.map +1 -0
  561. package/dist/services/task-fetch-service.js +109 -0
  562. package/dist/services/task-fetch-service.js.map +1 -0
  563. package/dist/services/task-fetch-service.test.d.ts +2 -0
  564. package/dist/services/task-fetch-service.test.d.ts.map +1 -0
  565. package/dist/services/task-fetch-service.test.js +243 -0
  566. package/dist/services/task-fetch-service.test.js.map +1 -0
  567. package/dist/services/task-service.d.ts +25 -0
  568. package/dist/services/task-service.d.ts.map +1 -0
  569. package/dist/services/task-service.js +114 -0
  570. package/dist/services/task-service.js.map +1 -0
  571. package/dist/services/task-service.test.d.ts +2 -0
  572. package/dist/services/task-service.test.d.ts.map +1 -0
  573. package/dist/services/task-service.test.js +235 -0
  574. package/dist/services/task-service.test.js.map +1 -0
  575. package/dist/services/task-sync-service.d.ts +25 -0
  576. package/dist/services/task-sync-service.d.ts.map +1 -0
  577. package/dist/services/task-sync-service.js +84 -0
  578. package/dist/services/task-sync-service.js.map +1 -0
  579. package/dist/services/task-sync-service.test.d.ts +2 -0
  580. package/dist/services/task-sync-service.test.d.ts.map +1 -0
  581. package/dist/services/task-sync-service.test.js +187 -0
  582. package/dist/services/task-sync-service.test.js.map +1 -0
  583. package/dist/services/validation-service.d.ts +6 -0
  584. package/dist/services/validation-service.d.ts.map +1 -0
  585. package/dist/services/validation-service.js +167 -0
  586. package/dist/services/validation-service.js.map +1 -0
  587. package/dist/services/validation-service.test.d.ts +2 -0
  588. package/dist/services/validation-service.test.d.ts.map +1 -0
  589. package/dist/services/validation-service.test.js +136 -0
  590. package/dist/services/validation-service.test.js.map +1 -0
  591. package/dist/services/version-service.d.ts +85 -0
  592. package/dist/services/version-service.d.ts.map +1 -0
  593. package/dist/services/version-service.js +184 -0
  594. package/dist/services/version-service.js.map +1 -0
  595. package/dist/services/version-service.test.d.ts +2 -0
  596. package/dist/services/version-service.test.d.ts.map +1 -0
  597. package/dist/services/version-service.test.js +332 -0
  598. package/dist/services/version-service.test.js.map +1 -0
  599. package/dist/templates/finalize-approval.yml +135 -0
  600. package/dist/templates/templates/finalize-approval.yml +144 -0
  601. package/dist/utils/display.d.ts +6 -0
  602. package/dist/utils/display.d.ts.map +1 -0
  603. package/dist/utils/display.js +27 -0
  604. package/dist/utils/display.js.map +1 -0
  605. package/dist/utils/error-handler.d.ts +4 -0
  606. package/dist/utils/error-handler.d.ts.map +1 -0
  607. package/dist/utils/error-handler.js +17 -0
  608. package/dist/utils/error-handler.js.map +1 -0
  609. package/dist/utils/error-handler.test.d.ts +2 -0
  610. package/dist/utils/error-handler.test.d.ts.map +1 -0
  611. package/dist/utils/error-handler.test.js +65 -0
  612. package/dist/utils/error-handler.test.js.map +1 -0
  613. package/dist/utils/errors.d.ts +17 -0
  614. package/dist/utils/errors.d.ts.map +1 -0
  615. package/dist/utils/errors.js +23 -0
  616. package/dist/utils/errors.js.map +1 -0
  617. package/dist/utils/errors.test.d.ts +2 -0
  618. package/dist/utils/errors.test.d.ts.map +1 -0
  619. package/dist/utils/errors.test.js +39 -0
  620. package/dist/utils/errors.test.js.map +1 -0
  621. package/dist/utils/id-generator.d.ts +3 -0
  622. package/dist/utils/id-generator.d.ts.map +1 -0
  623. package/dist/utils/id-generator.js +24 -0
  624. package/dist/utils/id-generator.js.map +1 -0
  625. package/dist/utils/progress-calculator.d.ts +11 -0
  626. package/dist/utils/progress-calculator.d.ts.map +1 -0
  627. package/dist/utils/progress-calculator.js +11 -0
  628. package/dist/utils/progress-calculator.js.map +1 -0
  629. package/dist/utils/progress-calculator.test.d.ts +2 -0
  630. package/dist/utils/progress-calculator.test.d.ts.map +1 -0
  631. package/dist/utils/progress-calculator.test.js +186 -0
  632. package/dist/utils/progress-calculator.test.js.map +1 -0
  633. package/dist/utils/spec-id-generator.d.ts +2 -0
  634. package/dist/utils/spec-id-generator.d.ts.map +1 -0
  635. package/dist/utils/spec-id-generator.js +3 -0
  636. package/dist/utils/spec-id-generator.js.map +1 -0
  637. package/dist/utils/spec-tag-parser.d.ts +7 -0
  638. package/dist/utils/spec-tag-parser.d.ts.map +1 -0
  639. package/dist/utils/spec-tag-parser.js +27 -0
  640. package/dist/utils/spec-tag-parser.js.map +1 -0
  641. package/dist/utils/spec-tag-parser.test.d.ts +2 -0
  642. package/dist/utils/spec-tag-parser.test.d.ts.map +1 -0
  643. package/dist/utils/spec-tag-parser.test.js +73 -0
  644. package/dist/utils/spec-tag-parser.test.js.map +1 -0
  645. package/dist/utils/templates.d.ts +5 -0
  646. package/dist/utils/templates.d.ts.map +1 -0
  647. package/dist/utils/templates.js +116 -0
  648. package/dist/utils/templates.js.map +1 -0
  649. package/package.json +56 -0
@@ -0,0 +1,977 @@
1
+ import { describe, it, expect, vi, beforeEach } from "vitest";
2
+ vi.mock("../repositories/feedback.js", () => ({
3
+ loadIndex: vi.fn(),
4
+ saveIndex: vi.fn(),
5
+ }));
6
+ vi.mock("../repositories/requirement.js", () => ({
7
+ findByIdOrThrow: vi.fn(),
8
+ save: vi.fn(),
9
+ }));
10
+ vi.mock("../repositories/specification.js", () => ({
11
+ findByIdOrThrow: vi.fn(),
12
+ save: vi.fn(),
13
+ }));
14
+ vi.mock("./github-client.js", () => ({
15
+ getIssue: vi.fn(),
16
+ closeIssue: vi.fn(),
17
+ updateIssueBody: vi.fn(),
18
+ createIssue: vi.fn(),
19
+ }));
20
+ vi.mock("./requirement-service.js", () => ({
21
+ createRequirement: vi.fn(),
22
+ }));
23
+ import * as feedbackRepo from "../repositories/feedback.js";
24
+ import * as reqRepo from "../repositories/requirement.js";
25
+ import * as specRepo from "../repositories/specification.js";
26
+ import * as githubClient from "./github-client.js";
27
+ import * as reqService from "./requirement-service.js";
28
+ import { listFeedbacks, showFeedback, linkToRequirement, linkWithNewRequirement, linkToSpecification, closeFeedback, resolveFeedback, createFeedbackIssue, unlinkFromRequirement, unlinkFromSpecification, checkRemainingFlags, } from "./feedback-service.js";
29
+ const mockFeedbackRepo = vi.mocked(feedbackRepo);
30
+ const mockReqRepo = vi.mocked(reqRepo);
31
+ const mockSpecRepo = vi.mocked(specRepo);
32
+ const mockGithubClient = vi.mocked(githubClient);
33
+ const mockReqService = vi.mocked(reqService);
34
+ function makeFeedbackEntry(overrides = {}) {
35
+ return {
36
+ githubIssue: 17,
37
+ type: "bug",
38
+ severity: "medium",
39
+ linkedTo: {
40
+ requirements: [],
41
+ createdRequirements: [],
42
+ specifications: [],
43
+ createdSpecifications: [],
44
+ },
45
+ syncedAt: "2026-01-01T00:00:00.000Z",
46
+ status: "open",
47
+ ...overrides,
48
+ };
49
+ }
50
+ function makeFeedbackIndex(feedbacks = []) {
51
+ return { feedbacks };
52
+ }
53
+ function makeRequirement(overrides = {}) {
54
+ return {
55
+ id: "req-000001",
56
+ version: "1.0.0",
57
+ title: "Test Requirement",
58
+ status: "draft",
59
+ priority: "medium",
60
+ createdAt: "2025-01-01T00:00:00.000Z",
61
+ updatedAt: "2025-01-01T00:00:00.000Z",
62
+ versionHistory: [],
63
+ files: { description: "requirements/req-000001/description.md", supplementary: [] },
64
+ successCriteria: [],
65
+ format: { type: "free-form" },
66
+ dependencies: { blockedBy: [], blocks: [], relatedTo: [] },
67
+ ...overrides,
68
+ };
69
+ }
70
+ function makeSpecification(overrides = {}) {
71
+ return {
72
+ id: "spec-000001",
73
+ requirementId: "req-000001",
74
+ version: "1.0.0",
75
+ status: "draft",
76
+ createdAt: "2025-01-01T00:00:00.000Z",
77
+ updatedAt: "2025-01-01T00:00:00.000Z",
78
+ versionHistory: [],
79
+ files: { design: "specifications/spec-000001/design.md", supplementary: [] },
80
+ ...overrides,
81
+ };
82
+ }
83
+ function makeGitHubIssue(overrides = {}) {
84
+ return {
85
+ number: 17,
86
+ title: "Test feedback issue",
87
+ state: "open",
88
+ labels: ["feedback"],
89
+ createdAt: "2026-01-01T00:00:00Z",
90
+ body: "Issue body content",
91
+ ...overrides,
92
+ };
93
+ }
94
+ describe("listFeedbacks", () => {
95
+ beforeEach(() => {
96
+ vi.clearAllMocks();
97
+ });
98
+ it("フィルタなしで全feedbackを返す", async () => {
99
+ const feedbacks = [
100
+ makeFeedbackEntry({ githubIssue: 1, status: "open" }),
101
+ makeFeedbackEntry({ githubIssue: 2, status: "closed" }),
102
+ ];
103
+ mockFeedbackRepo.loadIndex.mockResolvedValue(makeFeedbackIndex(feedbacks));
104
+ const result = await listFeedbacks("/test/cwd");
105
+ expect(result).toEqual(feedbacks);
106
+ });
107
+ it("stateでフィルタリングできる (open)", async () => {
108
+ const feedbacks = [
109
+ makeFeedbackEntry({ githubIssue: 1, status: "open" }),
110
+ makeFeedbackEntry({ githubIssue: 2, status: "closed" }),
111
+ ];
112
+ mockFeedbackRepo.loadIndex.mockResolvedValue(makeFeedbackIndex(feedbacks));
113
+ const result = await listFeedbacks("/test/cwd", { state: "open" });
114
+ expect(result).toHaveLength(1);
115
+ expect(result[0].status).toBe("open");
116
+ });
117
+ it("stateでフィルタリングできる (closed)", async () => {
118
+ const feedbacks = [
119
+ makeFeedbackEntry({ githubIssue: 1, status: "open" }),
120
+ makeFeedbackEntry({ githubIssue: 2, status: "closed" }),
121
+ ];
122
+ mockFeedbackRepo.loadIndex.mockResolvedValue(makeFeedbackIndex(feedbacks));
123
+ const result = await listFeedbacks("/test/cwd", { state: "closed" });
124
+ expect(result).toHaveLength(1);
125
+ expect(result[0].status).toBe("closed");
126
+ });
127
+ it("state=allでフィルタリングしない", async () => {
128
+ const feedbacks = [
129
+ makeFeedbackEntry({ githubIssue: 1, status: "open" }),
130
+ makeFeedbackEntry({ githubIssue: 2, status: "closed" }),
131
+ ];
132
+ mockFeedbackRepo.loadIndex.mockResolvedValue(makeFeedbackIndex(feedbacks));
133
+ const result = await listFeedbacks("/test/cwd", { state: "all" });
134
+ expect(result).toHaveLength(2);
135
+ });
136
+ it("typeでフィルタリングできる", async () => {
137
+ const feedbacks = [
138
+ makeFeedbackEntry({ githubIssue: 1, type: "bug" }),
139
+ makeFeedbackEntry({ githubIssue: 2, type: "improvement" }),
140
+ ];
141
+ mockFeedbackRepo.loadIndex.mockResolvedValue(makeFeedbackIndex(feedbacks));
142
+ const result = await listFeedbacks("/test/cwd", { type: "bug" });
143
+ expect(result).toHaveLength(1);
144
+ expect(result[0].type).toBe("bug");
145
+ });
146
+ });
147
+ describe("showFeedback", () => {
148
+ beforeEach(() => {
149
+ vi.clearAllMocks();
150
+ });
151
+ it("index.yamlとGitHub IssueのマージデータをReturn", async () => {
152
+ const feedback = makeFeedbackEntry({ githubIssue: 17 });
153
+ mockFeedbackRepo.loadIndex.mockResolvedValue(makeFeedbackIndex([feedback]));
154
+ const issue = makeGitHubIssue({ number: 17 });
155
+ mockGithubClient.getIssue.mockResolvedValue(issue);
156
+ const result = await showFeedback("/test/cwd", 17);
157
+ expect(result).toEqual({ feedback, issue });
158
+ });
159
+ it("index.yamlに存在しないissueでエラーを投げる", async () => {
160
+ mockFeedbackRepo.loadIndex.mockResolvedValue(makeFeedbackIndex([]));
161
+ await expect(showFeedback("/test/cwd", 99)).rejects.toThrow("Feedback for issue #99 not found in index.yaml");
162
+ });
163
+ it("getIssueを呼び出してGitHub情報を取得する", async () => {
164
+ const feedback = makeFeedbackEntry({ githubIssue: 17 });
165
+ mockFeedbackRepo.loadIndex.mockResolvedValue(makeFeedbackIndex([feedback]));
166
+ const issue = makeGitHubIssue({ number: 17 });
167
+ mockGithubClient.getIssue.mockResolvedValue(issue);
168
+ await showFeedback("/test/cwd", 17);
169
+ expect(mockGithubClient.getIssue).toHaveBeenCalledWith(17);
170
+ });
171
+ });
172
+ describe("linkToRequirement", () => {
173
+ beforeEach(() => {
174
+ vi.clearAllMocks();
175
+ });
176
+ it("index.yamlのlinkedTo.requirementsに追加する", async () => {
177
+ const feedback = makeFeedbackEntry({ githubIssue: 17 });
178
+ mockFeedbackRepo.loadIndex.mockResolvedValue(makeFeedbackIndex([feedback]));
179
+ const requirement = makeRequirement({ id: "req-000001" });
180
+ mockReqRepo.findByIdOrThrow.mockResolvedValue(requirement);
181
+ await linkToRequirement("/test/cwd", {
182
+ issueNumber: 17,
183
+ requirementId: "req-000001",
184
+ });
185
+ expect(mockFeedbackRepo.saveIndex).toHaveBeenCalledWith("/test/cwd", expect.objectContaining({
186
+ feedbacks: expect.arrayContaining([
187
+ expect.objectContaining({
188
+ linkedTo: expect.objectContaining({
189
+ requirements: ["req-000001"],
190
+ }),
191
+ }),
192
+ ]),
193
+ }));
194
+ });
195
+ it("GitHub Issue bodyにHTMLコメントを挿入する", async () => {
196
+ const feedback = makeFeedbackEntry({ githubIssue: 17 });
197
+ mockFeedbackRepo.loadIndex.mockResolvedValue(makeFeedbackIndex([feedback]));
198
+ const requirement = makeRequirement({ id: "req-000001" });
199
+ mockReqRepo.findByIdOrThrow.mockResolvedValue(requirement);
200
+ const issue = makeGitHubIssue({ number: 17, body: "Issue body" });
201
+ mockGithubClient.getIssue.mockResolvedValue(issue);
202
+ await linkToRequirement("/test/cwd", {
203
+ issueNumber: 17,
204
+ requirementId: "req-000001",
205
+ type: "bug",
206
+ });
207
+ expect(mockGithubClient.updateIssueBody).toHaveBeenCalledWith(17, expect.stringContaining("<!-- reqord:feedback"));
208
+ expect(mockGithubClient.updateIssueBody).toHaveBeenCalledWith(17, expect.stringContaining("req-000001"));
209
+ });
210
+ it("重複するrequirementIdを追加しない", async () => {
211
+ const feedback = makeFeedbackEntry({
212
+ githubIssue: 17,
213
+ linkedTo: {
214
+ requirements: ["req-000001"],
215
+ createdRequirements: [],
216
+ specifications: [],
217
+ createdSpecifications: [],
218
+ },
219
+ });
220
+ mockFeedbackRepo.loadIndex.mockResolvedValue(makeFeedbackIndex([feedback]));
221
+ const requirement = makeRequirement({ id: "req-000001" });
222
+ mockReqRepo.findByIdOrThrow.mockResolvedValue(requirement);
223
+ await linkToRequirement("/test/cwd", {
224
+ issueNumber: 17,
225
+ requirementId: "req-000001",
226
+ });
227
+ const savedIndex = mockFeedbackRepo.saveIndex.mock.calls[0][1];
228
+ expect(savedIndex.feedbacks[0].linkedTo.requirements).toEqual(["req-000001"]);
229
+ });
230
+ it("index.yamlにfeedbackがない場合は新規作成する", async () => {
231
+ mockFeedbackRepo.loadIndex.mockResolvedValue(makeFeedbackIndex([]));
232
+ const requirement = makeRequirement({ id: "req-000001" });
233
+ mockReqRepo.findByIdOrThrow.mockResolvedValue(requirement);
234
+ await linkToRequirement("/test/cwd", {
235
+ issueNumber: 17,
236
+ requirementId: "req-000001",
237
+ type: "bug",
238
+ severity: "high",
239
+ });
240
+ const savedIndex = mockFeedbackRepo.saveIndex.mock.calls[0][1];
241
+ expect(savedIndex.feedbacks).toHaveLength(1);
242
+ expect(savedIndex.feedbacks[0]).toMatchObject({
243
+ githubIssue: 17,
244
+ type: "bug",
245
+ severity: "high",
246
+ status: "open",
247
+ });
248
+ });
249
+ });
250
+ describe("linkWithNewRequirement", () => {
251
+ beforeEach(() => {
252
+ vi.clearAllMocks();
253
+ });
254
+ it("GitHub Issueタイトルから新Requirementを作成する", async () => {
255
+ mockFeedbackRepo.loadIndex.mockResolvedValue(makeFeedbackIndex([]));
256
+ const issue = makeGitHubIssue({ number: 17, title: "Fix login bug" });
257
+ mockGithubClient.getIssue.mockResolvedValue(issue);
258
+ const newReq = makeRequirement({ id: "req-000002" });
259
+ mockReqService.createRequirement.mockResolvedValue({
260
+ requirement: newReq,
261
+ descriptionPath: "requirements/req-000002/description.md",
262
+ });
263
+ mockReqRepo.save.mockResolvedValue();
264
+ await linkWithNewRequirement("/test/cwd", { issueNumber: 17 });
265
+ expect(mockReqService.createRequirement).toHaveBeenCalledWith("/test/cwd", {
266
+ title: "[Feedback #17] Fix login bug",
267
+ priority: "medium",
268
+ });
269
+ });
270
+ it("新RequirementのタイトルはFeedbackプレフィックス付き", async () => {
271
+ mockFeedbackRepo.loadIndex.mockResolvedValue(makeFeedbackIndex([]));
272
+ const issue = makeGitHubIssue({ number: 17, title: "Improve UX" });
273
+ mockGithubClient.getIssue.mockResolvedValue(issue);
274
+ const newReq = makeRequirement({ id: "req-000002" });
275
+ mockReqService.createRequirement.mockResolvedValue({
276
+ requirement: newReq,
277
+ descriptionPath: "requirements/req-000002/description.md",
278
+ });
279
+ mockReqRepo.save.mockResolvedValue();
280
+ await linkWithNewRequirement("/test/cwd", { issueNumber: 17 });
281
+ expect(mockReqService.createRequirement).toHaveBeenCalledWith("/test/cwd", {
282
+ title: "[Feedback #17] Improve UX",
283
+ priority: "medium",
284
+ });
285
+ });
286
+ it("index.yamlのlinkedTo.createdRequirementsに追加する", async () => {
287
+ mockFeedbackRepo.loadIndex.mockResolvedValue(makeFeedbackIndex([]));
288
+ const issue = makeGitHubIssue({ number: 17, title: "Test" });
289
+ mockGithubClient.getIssue.mockResolvedValue(issue);
290
+ const newReq = makeRequirement({ id: "req-000002" });
291
+ mockReqService.createRequirement.mockResolvedValue({
292
+ requirement: newReq,
293
+ descriptionPath: "requirements/req-000002/description.md",
294
+ });
295
+ mockReqRepo.save.mockResolvedValue();
296
+ await linkWithNewRequirement("/test/cwd", { issueNumber: 17 });
297
+ const savedIndex = mockFeedbackRepo.saveIndex.mock.calls[0][1];
298
+ expect(savedIndex.feedbacks[0].linkedTo.createdRequirements).toEqual(["req-000002"]);
299
+ });
300
+ it("GitHub Issue bodyにHTMLコメントを挿入する", async () => {
301
+ mockFeedbackRepo.loadIndex.mockResolvedValue(makeFeedbackIndex([]));
302
+ const issue = makeGitHubIssue({ number: 17, title: "Test", body: "Issue body" });
303
+ mockGithubClient.getIssue.mockResolvedValue(issue);
304
+ const newReq = makeRequirement({ id: "req-000002" });
305
+ mockReqService.createRequirement.mockResolvedValue({
306
+ requirement: newReq,
307
+ descriptionPath: "requirements/req-000002/description.md",
308
+ });
309
+ mockReqRepo.save.mockResolvedValue();
310
+ await linkWithNewRequirement("/test/cwd", { issueNumber: 17, type: "bug" });
311
+ expect(mockGithubClient.updateIssueBody).toHaveBeenCalledWith(17, expect.stringContaining("<!-- reqord:feedback"));
312
+ });
313
+ });
314
+ describe("linkToSpecification", () => {
315
+ beforeEach(() => {
316
+ vi.clearAllMocks();
317
+ });
318
+ it("index.yamlのlinkedTo.specificationsに追加する", async () => {
319
+ const feedback = makeFeedbackEntry({ githubIssue: 17 });
320
+ mockFeedbackRepo.loadIndex.mockResolvedValue(makeFeedbackIndex([feedback]));
321
+ const specification = makeSpecification({ id: "spec-000001" });
322
+ mockSpecRepo.findByIdOrThrow.mockResolvedValue(specification);
323
+ await linkToSpecification("/test/cwd", {
324
+ issueNumber: 17,
325
+ specificationId: "spec-000001",
326
+ });
327
+ expect(mockFeedbackRepo.saveIndex).toHaveBeenCalledWith("/test/cwd", expect.objectContaining({
328
+ feedbacks: expect.arrayContaining([
329
+ expect.objectContaining({
330
+ linkedTo: expect.objectContaining({
331
+ specifications: ["spec-000001"],
332
+ }),
333
+ }),
334
+ ]),
335
+ }));
336
+ });
337
+ it("GitHub Issue bodyにHTMLコメントを挿入する", async () => {
338
+ const feedback = makeFeedbackEntry({ githubIssue: 17 });
339
+ mockFeedbackRepo.loadIndex.mockResolvedValue(makeFeedbackIndex([feedback]));
340
+ const specification = makeSpecification({ id: "spec-000001" });
341
+ mockSpecRepo.findByIdOrThrow.mockResolvedValue(specification);
342
+ const issue = makeGitHubIssue({ number: 17, body: "Issue body" });
343
+ mockGithubClient.getIssue.mockResolvedValue(issue);
344
+ await linkToSpecification("/test/cwd", {
345
+ issueNumber: 17,
346
+ specificationId: "spec-000001",
347
+ type: "spec-mismatch",
348
+ });
349
+ expect(mockGithubClient.updateIssueBody).toHaveBeenCalledWith(17, expect.stringContaining("<!-- reqord:feedback"));
350
+ expect(mockGithubClient.updateIssueBody).toHaveBeenCalledWith(17, expect.stringContaining("spec-000001"));
351
+ });
352
+ it("存在しないSpecificationでエラーを投げる", async () => {
353
+ const feedback = makeFeedbackEntry({ githubIssue: 17 });
354
+ mockFeedbackRepo.loadIndex.mockResolvedValue(makeFeedbackIndex([feedback]));
355
+ mockSpecRepo.findByIdOrThrow.mockRejectedValue(new Error("Specification spec-999999 not found."));
356
+ await expect(linkToSpecification("/test/cwd", {
357
+ issueNumber: 17,
358
+ specificationId: "spec-999999",
359
+ })).rejects.toThrow("Specification spec-999999 not found");
360
+ });
361
+ });
362
+ describe("closeFeedback", () => {
363
+ beforeEach(() => {
364
+ vi.clearAllMocks();
365
+ });
366
+ it("index.yamlのstatusをclosedに更新する", async () => {
367
+ const feedback = makeFeedbackEntry({ githubIssue: 17, status: "open" });
368
+ mockFeedbackRepo.loadIndex.mockResolvedValue(makeFeedbackIndex([feedback]));
369
+ await closeFeedback("/test/cwd", 17);
370
+ const savedIndex = mockFeedbackRepo.saveIndex.mock.calls[0][1];
371
+ expect(savedIndex.feedbacks[0].status).toBe("closed");
372
+ });
373
+ it("GitHub Issueをクローズする", async () => {
374
+ const feedback = makeFeedbackEntry({ githubIssue: 17 });
375
+ mockFeedbackRepo.loadIndex.mockResolvedValue(makeFeedbackIndex([feedback]));
376
+ await closeFeedback("/test/cwd", 17);
377
+ expect(mockGithubClient.closeIssue).toHaveBeenCalledWith(17, expect.any(String));
378
+ });
379
+ it("影響範囲サマリーをコメントとして付与する", async () => {
380
+ const feedback = makeFeedbackEntry({
381
+ githubIssue: 17,
382
+ linkedTo: {
383
+ requirements: ["req-000001"],
384
+ createdRequirements: ["req-000002"],
385
+ specifications: ["spec-000001"],
386
+ createdSpecifications: [],
387
+ },
388
+ });
389
+ mockFeedbackRepo.loadIndex.mockResolvedValue(makeFeedbackIndex([feedback]));
390
+ await closeFeedback("/test/cwd", 17);
391
+ expect(mockGithubClient.closeIssue).toHaveBeenCalledWith(17, expect.stringContaining("req-000001"));
392
+ expect(mockGithubClient.closeIssue).toHaveBeenCalledWith(17, expect.stringContaining("req-000002"));
393
+ expect(mockGithubClient.closeIssue).toHaveBeenCalledWith(17, expect.stringContaining("spec-000001"));
394
+ });
395
+ it("存在しないfeedbackでエラーを投げる", async () => {
396
+ mockFeedbackRepo.loadIndex.mockResolvedValue(makeFeedbackIndex([]));
397
+ await expect(closeFeedback("/test/cwd", 99)).rejects.toThrow("Feedback for issue #99 not found");
398
+ });
399
+ });
400
+ describe("resolveFeedback", () => {
401
+ beforeEach(() => {
402
+ vi.clearAllMocks();
403
+ });
404
+ it("req-プレフィックスのアーティファクトをresolvedに追加する", async () => {
405
+ const feedback = makeFeedbackEntry({
406
+ githubIssue: 17,
407
+ linkedTo: {
408
+ requirements: ["req-000001"],
409
+ createdRequirements: [],
410
+ specifications: [],
411
+ createdSpecifications: [],
412
+ },
413
+ });
414
+ mockFeedbackRepo.loadIndex.mockResolvedValue(makeFeedbackIndex([feedback]));
415
+ await resolveFeedback("/test/cwd", {
416
+ issueNumber: 17,
417
+ artifactId: "req-000001",
418
+ });
419
+ const savedIndex = mockFeedbackRepo.saveIndex.mock.calls[0][1];
420
+ expect(savedIndex.feedbacks[0].linkedTo.resolved).toEqual({
421
+ requirements: ["req-000001"],
422
+ specifications: [],
423
+ });
424
+ });
425
+ it("spec-プレフィックスのアーティファクトをresolvedに追加する", async () => {
426
+ const feedback = makeFeedbackEntry({
427
+ githubIssue: 17,
428
+ linkedTo: {
429
+ requirements: [],
430
+ createdRequirements: [],
431
+ specifications: ["spec-000001"],
432
+ createdSpecifications: [],
433
+ },
434
+ });
435
+ mockFeedbackRepo.loadIndex.mockResolvedValue(makeFeedbackIndex([feedback]));
436
+ await resolveFeedback("/test/cwd", {
437
+ issueNumber: 17,
438
+ artifactId: "spec-000001",
439
+ });
440
+ const savedIndex = mockFeedbackRepo.saveIndex.mock.calls[0][1];
441
+ expect(savedIndex.feedbacks[0].linkedTo.resolved).toEqual({
442
+ requirements: [],
443
+ specifications: ["spec-000001"],
444
+ });
445
+ });
446
+ it("createdRequirementsに含まれるアーティファクトもresolve可能", async () => {
447
+ const feedback = makeFeedbackEntry({
448
+ githubIssue: 17,
449
+ linkedTo: {
450
+ requirements: [],
451
+ createdRequirements: ["req-000002"],
452
+ specifications: [],
453
+ createdSpecifications: [],
454
+ },
455
+ });
456
+ mockFeedbackRepo.loadIndex.mockResolvedValue(makeFeedbackIndex([feedback]));
457
+ await resolveFeedback("/test/cwd", {
458
+ issueNumber: 17,
459
+ artifactId: "req-000002",
460
+ });
461
+ const savedIndex = mockFeedbackRepo.saveIndex.mock.calls[0][1];
462
+ expect(savedIndex.feedbacks[0].linkedTo.resolved?.requirements).toContain("req-000002");
463
+ });
464
+ it("createdSpecificationsに含まれるアーティファクトもresolve可能", async () => {
465
+ const feedback = makeFeedbackEntry({
466
+ githubIssue: 17,
467
+ linkedTo: {
468
+ requirements: [],
469
+ createdRequirements: [],
470
+ specifications: [],
471
+ createdSpecifications: ["spec-000002"],
472
+ },
473
+ });
474
+ mockFeedbackRepo.loadIndex.mockResolvedValue(makeFeedbackIndex([feedback]));
475
+ await resolveFeedback("/test/cwd", {
476
+ issueNumber: 17,
477
+ artifactId: "spec-000002",
478
+ });
479
+ const savedIndex = mockFeedbackRepo.saveIndex.mock.calls[0][1];
480
+ expect(savedIndex.feedbacks[0].linkedTo.resolved?.specifications).toContain("spec-000002");
481
+ });
482
+ it("linkedToに含まれないartifact-idでエラーを投げる", async () => {
483
+ const feedback = makeFeedbackEntry({
484
+ githubIssue: 17,
485
+ linkedTo: {
486
+ requirements: ["req-000001"],
487
+ createdRequirements: [],
488
+ specifications: [],
489
+ createdSpecifications: [],
490
+ },
491
+ });
492
+ mockFeedbackRepo.loadIndex.mockResolvedValue(makeFeedbackIndex([feedback]));
493
+ await expect(resolveFeedback("/test/cwd", {
494
+ issueNumber: 17,
495
+ artifactId: "req-000099",
496
+ })).rejects.toThrow("req-000099 is not linked to feedback #17");
497
+ });
498
+ it("無効なartifact-idプレフィックスでエラーを投げる", async () => {
499
+ const feedback = makeFeedbackEntry({ githubIssue: 17 });
500
+ mockFeedbackRepo.loadIndex.mockResolvedValue(makeFeedbackIndex([feedback]));
501
+ await expect(resolveFeedback("/test/cwd", {
502
+ issueNumber: 17,
503
+ artifactId: "invalid-000001",
504
+ })).rejects.toThrow("Invalid artifact ID: invalid-000001");
505
+ });
506
+ it("存在しないfeedbackでエラーを投げる", async () => {
507
+ mockFeedbackRepo.loadIndex.mockResolvedValue(makeFeedbackIndex([]));
508
+ await expect(resolveFeedback("/test/cwd", {
509
+ issueNumber: 99,
510
+ artifactId: "req-000001",
511
+ })).rejects.toThrow("Feedback for issue #99 not found");
512
+ });
513
+ it("既にresolvedに含まれている場合は重複追加しない", async () => {
514
+ const feedback = makeFeedbackEntry({
515
+ githubIssue: 17,
516
+ linkedTo: {
517
+ requirements: ["req-000001"],
518
+ createdRequirements: [],
519
+ specifications: [],
520
+ createdSpecifications: [],
521
+ resolved: {
522
+ requirements: ["req-000001"],
523
+ specifications: [],
524
+ },
525
+ },
526
+ });
527
+ mockFeedbackRepo.loadIndex.mockResolvedValue(makeFeedbackIndex([feedback]));
528
+ await resolveFeedback("/test/cwd", {
529
+ issueNumber: 17,
530
+ artifactId: "req-000001",
531
+ });
532
+ const savedIndex = mockFeedbackRepo.saveIndex.mock.calls[0][1];
533
+ expect(savedIndex.feedbacks[0].linkedTo.resolved?.requirements).toEqual(["req-000001"]);
534
+ });
535
+ });
536
+ describe("createFeedbackIssue", () => {
537
+ beforeEach(() => {
538
+ vi.clearAllMocks();
539
+ });
540
+ it("GitHub Issueを作成してissue番号を返す", async () => {
541
+ mockFeedbackRepo.loadIndex.mockResolvedValue(makeFeedbackIndex([]));
542
+ mockGithubClient.createIssue.mockResolvedValue({ number: 42, url: "https://github.com/owner/repo/issues/42" });
543
+ const result = await createFeedbackIssue("/test/cwd", {
544
+ title: "Login broken",
545
+ description: "Cannot login after update",
546
+ });
547
+ expect(result).toBe(42);
548
+ });
549
+ it("タイトルに[Feedback]プレフィックスを自動付与する", async () => {
550
+ mockFeedbackRepo.loadIndex.mockResolvedValue(makeFeedbackIndex([]));
551
+ mockGithubClient.createIssue.mockResolvedValue({ number: 42, url: "https://github.com/owner/repo/issues/42" });
552
+ await createFeedbackIssue("/test/cwd", {
553
+ title: "Login broken",
554
+ description: "Cannot login after update",
555
+ });
556
+ expect(mockGithubClient.createIssue).toHaveBeenCalledWith(expect.objectContaining({ title: "[Feedback] Login broken" }));
557
+ });
558
+ it("既に[Feedback]プレフィックスがある場合は二重に付与しない", async () => {
559
+ mockFeedbackRepo.loadIndex.mockResolvedValue(makeFeedbackIndex([]));
560
+ mockGithubClient.createIssue.mockResolvedValue({ number: 42, url: "https://github.com/owner/repo/issues/42" });
561
+ await createFeedbackIssue("/test/cwd", {
562
+ title: "[Feedback] Login broken",
563
+ description: "Cannot login after update",
564
+ });
565
+ expect(mockGithubClient.createIssue).toHaveBeenCalledWith(expect.objectContaining({ title: "[Feedback] Login broken" }));
566
+ });
567
+ it("feedbackとreqord-generatedラベルを付与する", async () => {
568
+ mockFeedbackRepo.loadIndex.mockResolvedValue(makeFeedbackIndex([]));
569
+ mockGithubClient.createIssue.mockResolvedValue({ number: 42, url: "https://github.com/owner/repo/issues/42" });
570
+ await createFeedbackIssue("/test/cwd", {
571
+ title: "Bug",
572
+ description: "desc",
573
+ });
574
+ expect(mockGithubClient.createIssue).toHaveBeenCalledWith(expect.objectContaining({ labels: ["feedback", "reqord-generated"] }));
575
+ });
576
+ it("type指定時にtypeラベルも追加する", async () => {
577
+ mockFeedbackRepo.loadIndex.mockResolvedValue(makeFeedbackIndex([]));
578
+ mockGithubClient.createIssue.mockResolvedValue({ number: 42, url: "https://github.com/owner/repo/issues/42" });
579
+ await createFeedbackIssue("/test/cwd", {
580
+ title: "Bug",
581
+ description: "desc",
582
+ type: "bug",
583
+ });
584
+ expect(mockGithubClient.createIssue).toHaveBeenCalledWith(expect.objectContaining({ labels: ["feedback", "reqord-generated", "bug"] }));
585
+ });
586
+ it("index.yamlに新規エントリを追加する", async () => {
587
+ mockFeedbackRepo.loadIndex.mockResolvedValue(makeFeedbackIndex([]));
588
+ mockGithubClient.createIssue.mockResolvedValue({ number: 42, url: "https://github.com/owner/repo/issues/42" });
589
+ await createFeedbackIssue("/test/cwd", {
590
+ title: "Bug",
591
+ description: "desc",
592
+ type: "bug",
593
+ severity: "high",
594
+ });
595
+ const savedIndex = mockFeedbackRepo.saveIndex.mock.calls[0][1];
596
+ expect(savedIndex.feedbacks).toHaveLength(1);
597
+ expect(savedIndex.feedbacks[0]).toMatchObject({
598
+ githubIssue: 42,
599
+ type: "bug",
600
+ severity: "high",
601
+ status: "open",
602
+ });
603
+ });
604
+ it("ISSUE_TEMPLATE準拠のbodyを生成する", async () => {
605
+ mockFeedbackRepo.loadIndex.mockResolvedValue(makeFeedbackIndex([]));
606
+ mockGithubClient.createIssue.mockResolvedValue({ number: 42, url: "https://github.com/owner/repo/issues/42" });
607
+ await createFeedbackIssue("/test/cwd", {
608
+ title: "Bug",
609
+ description: "Something happened",
610
+ type: "bug",
611
+ severity: "high",
612
+ relatedReq: "req-000001",
613
+ relatedSpec: "spec-000001",
614
+ });
615
+ const body = mockGithubClient.createIssue.mock.calls[0][0].body;
616
+ expect(body).toContain("### What happened? / What did you notice?");
617
+ expect(body).toContain("Something happened");
618
+ expect(body).toContain("### Feedback type");
619
+ expect(body).toContain("implementation-bug (implementation bug)");
620
+ expect(body).toContain("### Related requirement (Requirement)");
621
+ expect(body).toContain("req-000001");
622
+ expect(body).toContain("### Related specification (Specification)");
623
+ expect(body).toContain("spec-000001");
624
+ expect(body).toContain("### Severity");
625
+ expect(body).toContain("high (affects many users)");
626
+ });
627
+ });
628
+ describe("unlinkFromRequirement", () => {
629
+ beforeEach(() => {
630
+ vi.clearAllMocks();
631
+ });
632
+ it("linkedTo.requirementsから指定IDを削除する", async () => {
633
+ const feedback = makeFeedbackEntry({
634
+ githubIssue: 17,
635
+ linkedTo: {
636
+ requirements: ["req-000001", "req-000002"],
637
+ createdRequirements: [],
638
+ specifications: [],
639
+ createdSpecifications: [],
640
+ },
641
+ });
642
+ mockFeedbackRepo.loadIndex.mockResolvedValue(makeFeedbackIndex([feedback]));
643
+ mockGithubClient.getIssue.mockResolvedValue(makeGitHubIssue({ number: 17 }));
644
+ await unlinkFromRequirement("/test/cwd", {
645
+ issueNumber: 17,
646
+ requirementId: "req-000001",
647
+ });
648
+ const savedIndex = mockFeedbackRepo.saveIndex.mock.calls[0][1];
649
+ expect(savedIndex.feedbacks[0].linkedTo.requirements).toEqual(["req-000002"]);
650
+ });
651
+ it("GitHub Issue bodyのHTMLコメントを更新する", async () => {
652
+ const feedback = makeFeedbackEntry({
653
+ githubIssue: 17,
654
+ linkedTo: {
655
+ requirements: ["req-000001"],
656
+ createdRequirements: [],
657
+ specifications: [],
658
+ createdSpecifications: [],
659
+ },
660
+ });
661
+ mockFeedbackRepo.loadIndex.mockResolvedValue(makeFeedbackIndex([feedback]));
662
+ mockGithubClient.getIssue.mockResolvedValue(makeGitHubIssue({ number: 17, body: "Issue body" }));
663
+ await unlinkFromRequirement("/test/cwd", {
664
+ issueNumber: 17,
665
+ requirementId: "req-000001",
666
+ });
667
+ expect(mockGithubClient.updateIssueBody).toHaveBeenCalledWith(17, expect.any(String));
668
+ });
669
+ it("紐付けされていないrequirementでエラーを投げる", async () => {
670
+ const feedback = makeFeedbackEntry({
671
+ githubIssue: 17,
672
+ linkedTo: {
673
+ requirements: ["req-000001"],
674
+ createdRequirements: [],
675
+ specifications: [],
676
+ createdSpecifications: [],
677
+ },
678
+ });
679
+ mockFeedbackRepo.loadIndex.mockResolvedValue(makeFeedbackIndex([feedback]));
680
+ await expect(unlinkFromRequirement("/test/cwd", {
681
+ issueNumber: 17,
682
+ requirementId: "req-000099",
683
+ })).rejects.toThrow("req-000099 is not linked to feedback #17");
684
+ });
685
+ it("存在しないfeedbackでエラーを投げる", async () => {
686
+ mockFeedbackRepo.loadIndex.mockResolvedValue(makeFeedbackIndex([]));
687
+ await expect(unlinkFromRequirement("/test/cwd", {
688
+ issueNumber: 99,
689
+ requirementId: "req-000001",
690
+ })).rejects.toThrow("Feedback for issue #99 not found");
691
+ });
692
+ it("resolved.requirementsからも削除する", async () => {
693
+ const feedback = makeFeedbackEntry({
694
+ githubIssue: 17,
695
+ linkedTo: {
696
+ requirements: ["req-000001"],
697
+ createdRequirements: [],
698
+ specifications: [],
699
+ createdSpecifications: [],
700
+ resolved: {
701
+ requirements: ["req-000001"],
702
+ specifications: [],
703
+ },
704
+ },
705
+ });
706
+ mockFeedbackRepo.loadIndex.mockResolvedValue(makeFeedbackIndex([feedback]));
707
+ mockGithubClient.getIssue.mockResolvedValue(makeGitHubIssue({ number: 17 }));
708
+ await unlinkFromRequirement("/test/cwd", {
709
+ issueNumber: 17,
710
+ requirementId: "req-000001",
711
+ });
712
+ const savedIndex = mockFeedbackRepo.saveIndex.mock.calls[0][1];
713
+ expect(savedIndex.feedbacks[0].linkedTo.resolved?.requirements).toEqual([]);
714
+ });
715
+ });
716
+ describe("unlinkFromSpecification", () => {
717
+ beforeEach(() => {
718
+ vi.clearAllMocks();
719
+ });
720
+ it("linkedTo.specificationsから指定IDを削除する", async () => {
721
+ const feedback = makeFeedbackEntry({
722
+ githubIssue: 17,
723
+ linkedTo: {
724
+ requirements: [],
725
+ createdRequirements: [],
726
+ specifications: ["spec-000001", "spec-000002"],
727
+ createdSpecifications: [],
728
+ },
729
+ });
730
+ mockFeedbackRepo.loadIndex.mockResolvedValue(makeFeedbackIndex([feedback]));
731
+ mockGithubClient.getIssue.mockResolvedValue(makeGitHubIssue({ number: 17 }));
732
+ await unlinkFromSpecification("/test/cwd", {
733
+ issueNumber: 17,
734
+ specificationId: "spec-000001",
735
+ });
736
+ const savedIndex = mockFeedbackRepo.saveIndex.mock.calls[0][1];
737
+ expect(savedIndex.feedbacks[0].linkedTo.specifications).toEqual(["spec-000002"]);
738
+ });
739
+ it("GitHub Issue bodyのHTMLコメントを更新する", async () => {
740
+ const feedback = makeFeedbackEntry({
741
+ githubIssue: 17,
742
+ linkedTo: {
743
+ requirements: [],
744
+ createdRequirements: [],
745
+ specifications: ["spec-000001"],
746
+ createdSpecifications: [],
747
+ },
748
+ });
749
+ mockFeedbackRepo.loadIndex.mockResolvedValue(makeFeedbackIndex([feedback]));
750
+ mockGithubClient.getIssue.mockResolvedValue(makeGitHubIssue({ number: 17, body: "Issue body" }));
751
+ await unlinkFromSpecification("/test/cwd", {
752
+ issueNumber: 17,
753
+ specificationId: "spec-000001",
754
+ });
755
+ expect(mockGithubClient.updateIssueBody).toHaveBeenCalledWith(17, expect.any(String));
756
+ });
757
+ it("紐付けされていないspecificationでエラーを投げる", async () => {
758
+ const feedback = makeFeedbackEntry({
759
+ githubIssue: 17,
760
+ linkedTo: {
761
+ requirements: [],
762
+ createdRequirements: [],
763
+ specifications: ["spec-000001"],
764
+ createdSpecifications: [],
765
+ },
766
+ });
767
+ mockFeedbackRepo.loadIndex.mockResolvedValue(makeFeedbackIndex([feedback]));
768
+ await expect(unlinkFromSpecification("/test/cwd", {
769
+ issueNumber: 17,
770
+ specificationId: "spec-000099",
771
+ })).rejects.toThrow("spec-000099 is not linked to feedback #17");
772
+ });
773
+ it("存在しないfeedbackでエラーを投げる", async () => {
774
+ mockFeedbackRepo.loadIndex.mockResolvedValue(makeFeedbackIndex([]));
775
+ await expect(unlinkFromSpecification("/test/cwd", {
776
+ issueNumber: 99,
777
+ specificationId: "spec-000001",
778
+ })).rejects.toThrow("Feedback for issue #99 not found");
779
+ });
780
+ it("resolved.specificationsからも削除する", async () => {
781
+ const feedback = makeFeedbackEntry({
782
+ githubIssue: 17,
783
+ linkedTo: {
784
+ requirements: [],
785
+ createdRequirements: [],
786
+ specifications: ["spec-000001"],
787
+ createdSpecifications: [],
788
+ resolved: {
789
+ requirements: [],
790
+ specifications: ["spec-000001"],
791
+ },
792
+ },
793
+ });
794
+ mockFeedbackRepo.loadIndex.mockResolvedValue(makeFeedbackIndex([feedback]));
795
+ mockGithubClient.getIssue.mockResolvedValue(makeGitHubIssue({ number: 17 }));
796
+ await unlinkFromSpecification("/test/cwd", {
797
+ issueNumber: 17,
798
+ specificationId: "spec-000001",
799
+ });
800
+ const savedIndex = mockFeedbackRepo.saveIndex.mock.calls[0][1];
801
+ expect(savedIndex.feedbacks[0].linkedTo.resolved?.specifications).toEqual([]);
802
+ });
803
+ });
804
+ describe("checkRemainingFlags", () => {
805
+ beforeEach(() => {
806
+ vi.clearAllMocks();
807
+ });
808
+ it("未resolveのrequirementを検出する", async () => {
809
+ const feedback = makeFeedbackEntry({
810
+ githubIssue: 17,
811
+ linkedTo: {
812
+ requirements: ["req-000001"],
813
+ createdRequirements: [],
814
+ specifications: [],
815
+ createdSpecifications: [],
816
+ },
817
+ });
818
+ const result = checkRemainingFlags(feedback);
819
+ expect(result).toEqual([
820
+ {
821
+ artifactId: "req-000001",
822
+ issueNumber: 17,
823
+ severity: "medium",
824
+ },
825
+ ]);
826
+ });
827
+ it("全てresolve済みの場合は空配列を返す", async () => {
828
+ const feedback = makeFeedbackEntry({
829
+ githubIssue: 17,
830
+ linkedTo: {
831
+ requirements: ["req-000001"],
832
+ createdRequirements: [],
833
+ specifications: [],
834
+ createdSpecifications: [],
835
+ resolved: {
836
+ requirements: ["req-000001"],
837
+ specifications: [],
838
+ },
839
+ },
840
+ });
841
+ const result = checkRemainingFlags(feedback);
842
+ expect(result).toEqual([]);
843
+ });
844
+ it("紐付けがない場合は空配列を返す", async () => {
845
+ const feedback = makeFeedbackEntry({
846
+ githubIssue: 17,
847
+ linkedTo: {
848
+ requirements: [],
849
+ createdRequirements: [],
850
+ specifications: [],
851
+ createdSpecifications: [],
852
+ },
853
+ });
854
+ const result = checkRemainingFlags(feedback);
855
+ expect(result).toEqual([]);
856
+ });
857
+ it("複数の未resolveのrequirementを返す", async () => {
858
+ const feedback = makeFeedbackEntry({
859
+ githubIssue: 17,
860
+ linkedTo: {
861
+ requirements: ["req-000001", "req-000002"],
862
+ createdRequirements: [],
863
+ specifications: [],
864
+ createdSpecifications: [],
865
+ },
866
+ });
867
+ const result = checkRemainingFlags(feedback);
868
+ expect(result).toHaveLength(2);
869
+ expect(result[0]).toMatchObject({ artifactId: "req-000001", severity: "medium" });
870
+ expect(result[1]).toMatchObject({ artifactId: "req-000002", severity: "medium" });
871
+ });
872
+ it("未resolveのspecificationを検出する", async () => {
873
+ const feedback = makeFeedbackEntry({
874
+ githubIssue: 17,
875
+ linkedTo: {
876
+ requirements: [],
877
+ createdRequirements: [],
878
+ specifications: ["spec-000001"],
879
+ createdSpecifications: [],
880
+ },
881
+ });
882
+ const result = checkRemainingFlags(feedback);
883
+ expect(result).toEqual([
884
+ {
885
+ artifactId: "spec-000001",
886
+ issueNumber: 17,
887
+ severity: "medium",
888
+ },
889
+ ]);
890
+ });
891
+ it("RequirementとSpecification両方の未resolveを返す", async () => {
892
+ const feedback = makeFeedbackEntry({
893
+ githubIssue: 17,
894
+ severity: "high",
895
+ linkedTo: {
896
+ requirements: ["req-000001"],
897
+ createdRequirements: [],
898
+ specifications: ["spec-000001"],
899
+ createdSpecifications: [],
900
+ },
901
+ });
902
+ const result = checkRemainingFlags(feedback);
903
+ expect(result).toHaveLength(2);
904
+ expect(result[0]).toMatchObject({ artifactId: "req-000001", severity: "high" });
905
+ expect(result[1]).toMatchObject({ artifactId: "spec-000001", severity: "high" });
906
+ });
907
+ it("feedbackのseverityがundefinedの場合はmediumがデフォルト", async () => {
908
+ const feedback = makeFeedbackEntry({
909
+ githubIssue: 17,
910
+ severity: undefined,
911
+ linkedTo: {
912
+ requirements: ["req-000001"],
913
+ createdRequirements: [],
914
+ specifications: [],
915
+ createdSpecifications: [],
916
+ },
917
+ });
918
+ const result = checkRemainingFlags(feedback);
919
+ expect(result[0].severity).toBe("medium");
920
+ });
921
+ it("createdRequirementsの未resolveも検出する", () => {
922
+ const feedback = makeFeedbackEntry({
923
+ githubIssue: 17,
924
+ linkedTo: {
925
+ requirements: [],
926
+ createdRequirements: ["req-000010"],
927
+ specifications: [],
928
+ createdSpecifications: [],
929
+ },
930
+ });
931
+ const result = checkRemainingFlags(feedback);
932
+ expect(result).toEqual([
933
+ {
934
+ artifactId: "req-000010",
935
+ issueNumber: 17,
936
+ severity: "medium",
937
+ },
938
+ ]);
939
+ });
940
+ it("createdSpecificationsの未resolveも検出する", () => {
941
+ const feedback = makeFeedbackEntry({
942
+ githubIssue: 17,
943
+ linkedTo: {
944
+ requirements: [],
945
+ createdRequirements: [],
946
+ specifications: [],
947
+ createdSpecifications: ["spec-000010"],
948
+ },
949
+ });
950
+ const result = checkRemainingFlags(feedback);
951
+ expect(result).toEqual([
952
+ {
953
+ artifactId: "spec-000010",
954
+ issueNumber: 17,
955
+ severity: "medium",
956
+ },
957
+ ]);
958
+ });
959
+ it("createdRequirementsがresolve済みなら含まない", () => {
960
+ const feedback = makeFeedbackEntry({
961
+ githubIssue: 17,
962
+ linkedTo: {
963
+ requirements: [],
964
+ createdRequirements: ["req-000010"],
965
+ specifications: [],
966
+ createdSpecifications: [],
967
+ resolved: {
968
+ requirements: ["req-000010"],
969
+ specifications: [],
970
+ },
971
+ },
972
+ });
973
+ const result = checkRemainingFlags(feedback);
974
+ expect(result).toEqual([]);
975
+ });
976
+ });
977
+ //# sourceMappingURL=feedback-service.test.js.map