@planu/cli 0.89.0 → 0.90.1

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 (446) hide show
  1. package/dist/cli/commands/activate.d.ts +14 -0
  2. package/dist/cli/commands/activate.d.ts.map +1 -0
  3. package/dist/cli/commands/activate.js +174 -0
  4. package/dist/cli/commands/activate.js.map +1 -0
  5. package/dist/cli/commands/doctor.d.ts +16 -0
  6. package/dist/cli/commands/doctor.d.ts.map +1 -0
  7. package/dist/cli/commands/doctor.js +162 -0
  8. package/dist/cli/commands/doctor.js.map +1 -0
  9. package/dist/cli/commands/install.d.ts +48 -0
  10. package/dist/cli/commands/install.d.ts.map +1 -0
  11. package/dist/cli/commands/install.js +348 -0
  12. package/dist/cli/commands/install.js.map +1 -0
  13. package/dist/cli/commands/uninstall.d.ts +10 -0
  14. package/dist/cli/commands/uninstall.d.ts.map +1 -0
  15. package/dist/cli/commands/uninstall.js +133 -0
  16. package/dist/cli/commands/uninstall.js.map +1 -0
  17. package/dist/cli/router.d.ts.map +1 -1
  18. package/dist/cli/router.js +9 -1
  19. package/dist/cli/router.js.map +1 -1
  20. package/dist/config/license-plans.json +2 -1
  21. package/dist/engine/agent-generator.test.d.ts +2 -0
  22. package/dist/engine/agent-generator.test.d.ts.map +1 -0
  23. package/dist/engine/agent-generator.test.js +556 -0
  24. package/dist/engine/agent-generator.test.js.map +1 -0
  25. package/dist/engine/analyzer.test.d.ts +2 -0
  26. package/dist/engine/analyzer.test.d.ts.map +1 -0
  27. package/dist/engine/analyzer.test.js +1461 -0
  28. package/dist/engine/analyzer.test.js.map +1 -0
  29. package/dist/engine/auditor.test.d.ts +2 -0
  30. package/dist/engine/auditor.test.d.ts.map +1 -0
  31. package/dist/engine/auditor.test.js +2075 -0
  32. package/dist/engine/auditor.test.js.map +1 -0
  33. package/dist/engine/doc-generator.test.d.ts +2 -0
  34. package/dist/engine/doc-generator.test.d.ts.map +1 -0
  35. package/dist/engine/doc-generator.test.js +961 -0
  36. package/dist/engine/doc-generator.test.js.map +1 -0
  37. package/dist/engine/estimator.test.d.ts +2 -0
  38. package/dist/engine/estimator.test.d.ts.map +1 -0
  39. package/dist/engine/estimator.test.js +334 -0
  40. package/dist/engine/estimator.test.js.map +1 -0
  41. package/dist/engine/skill-generator.test.d.ts +2 -0
  42. package/dist/engine/skill-generator.test.d.ts.map +1 -0
  43. package/dist/engine/skill-generator.test.js +742 -0
  44. package/dist/engine/skill-generator.test.js.map +1 -0
  45. package/dist/engine/spec-migrator/filesystem-import.d.ts +14 -0
  46. package/dist/engine/spec-migrator/filesystem-import.d.ts.map +1 -0
  47. package/dist/engine/spec-migrator/filesystem-import.js +96 -0
  48. package/dist/engine/spec-migrator/filesystem-import.js.map +1 -0
  49. package/dist/engine/spec-migrator/flatten-specs.d.ts +12 -0
  50. package/dist/engine/spec-migrator/flatten-specs.d.ts.map +1 -0
  51. package/dist/engine/spec-migrator/flatten-specs.js +111 -0
  52. package/dist/engine/spec-migrator/flatten-specs.js.map +1 -0
  53. package/dist/engine/spec-migrator/folder-operations.d.ts +9 -0
  54. package/dist/engine/spec-migrator/folder-operations.d.ts.map +1 -0
  55. package/dist/engine/spec-migrator/folder-operations.js +109 -0
  56. package/dist/engine/spec-migrator/folder-operations.js.map +1 -0
  57. package/dist/engine/spec-migrator/frontmatter-parser.d.ts +11 -0
  58. package/dist/engine/spec-migrator/frontmatter-parser.d.ts.map +1 -0
  59. package/dist/engine/spec-migrator/frontmatter-parser.js +92 -0
  60. package/dist/engine/spec-migrator/frontmatter-parser.js.map +1 -0
  61. package/dist/engine/spec-migrator/index.d.ts +9 -0
  62. package/dist/engine/spec-migrator/index.d.ts.map +1 -0
  63. package/dist/engine/spec-migrator/index.js +18 -0
  64. package/dist/engine/spec-migrator/index.js.map +1 -0
  65. package/dist/engine/spec-migrator/legacy-migration.d.ts +13 -0
  66. package/dist/engine/spec-migrator/legacy-migration.d.ts.map +1 -0
  67. package/dist/engine/spec-migrator/legacy-migration.js +75 -0
  68. package/dist/engine/spec-migrator/legacy-migration.js.map +1 -0
  69. package/dist/engine/spec-migrator/migration-validator.d.ts +20 -0
  70. package/dist/engine/spec-migrator/migration-validator.d.ts.map +1 -0
  71. package/dist/engine/spec-migrator/migration-validator.js +35 -0
  72. package/dist/engine/spec-migrator/migration-validator.js.map +1 -0
  73. package/dist/engine/spec-migrator/path-utils.d.ts +13 -0
  74. package/dist/engine/spec-migrator/path-utils.d.ts.map +1 -0
  75. package/dist/engine/spec-migrator/path-utils.js +40 -0
  76. package/dist/engine/spec-migrator/path-utils.js.map +1 -0
  77. package/dist/engine/spec-migrator/prefix-migration.d.ts +11 -0
  78. package/dist/engine/spec-migrator/prefix-migration.d.ts.map +1 -0
  79. package/dist/engine/spec-migrator/prefix-migration.js +73 -0
  80. package/dist/engine/spec-migrator/prefix-migration.js.map +1 -0
  81. package/dist/engine/spec-migrator/reconcile-paths.d.ts +12 -0
  82. package/dist/engine/spec-migrator/reconcile-paths.d.ts.map +1 -0
  83. package/dist/engine/spec-migrator/reconcile-paths.js +77 -0
  84. package/dist/engine/spec-migrator/reconcile-paths.js.map +1 -0
  85. package/dist/engine/spec-migrator/version-detection.d.ts +5 -0
  86. package/dist/engine/spec-migrator/version-detection.d.ts.map +1 -0
  87. package/dist/engine/spec-migrator/version-detection.js +19 -0
  88. package/dist/engine/spec-migrator/version-detection.js.map +1 -0
  89. package/dist/engine/spec-migrator.d.ts +1 -58
  90. package/dist/engine/spec-migrator.d.ts.map +1 -1
  91. package/dist/engine/spec-migrator.js +2 -658
  92. package/dist/engine/spec-migrator.js.map +1 -1
  93. package/dist/engine/spec-summary-html/dashboard-renderer.d.ts +6 -0
  94. package/dist/engine/spec-summary-html/dashboard-renderer.d.ts.map +1 -0
  95. package/dist/engine/spec-summary-html/dashboard-renderer.js +333 -0
  96. package/dist/engine/spec-summary-html/dashboard-renderer.js.map +1 -0
  97. package/dist/engine/spec-summary-html/hash-utils.d.ts +11 -0
  98. package/dist/engine/spec-summary-html/hash-utils.d.ts.map +1 -0
  99. package/dist/engine/spec-summary-html/hash-utils.js +39 -0
  100. package/dist/engine/spec-summary-html/hash-utils.js.map +1 -0
  101. package/dist/engine/spec-summary-html/index.d.ts +4 -0
  102. package/dist/engine/spec-summary-html/index.d.ts.map +1 -0
  103. package/dist/engine/spec-summary-html/index.js +6 -0
  104. package/dist/engine/spec-summary-html/index.js.map +1 -0
  105. package/dist/engine/spec-summary-html/report-renderer.d.ts +9 -0
  106. package/dist/engine/spec-summary-html/report-renderer.d.ts.map +1 -0
  107. package/dist/engine/spec-summary-html/report-renderer.js +139 -0
  108. package/dist/engine/spec-summary-html/report-renderer.js.map +1 -0
  109. package/dist/engine/spec-summary-html.d.ts +1 -0
  110. package/dist/engine/spec-summary-html.d.ts.map +1 -1
  111. package/dist/engine/spec-summary-html.js +19 -473
  112. package/dist/engine/spec-summary-html.js.map +1 -1
  113. package/dist/engine/update-notifier.d.ts +8 -0
  114. package/dist/engine/update-notifier.d.ts.map +1 -0
  115. package/dist/engine/update-notifier.js +130 -0
  116. package/dist/engine/update-notifier.js.map +1 -0
  117. package/dist/engine/validator/dor-dod.d.ts.map +1 -1
  118. package/dist/engine/validator/dor-dod.js +8 -5
  119. package/dist/engine/validator/dor-dod.js.map +1 -1
  120. package/dist/engine/validator.d.ts.map +1 -1
  121. package/dist/engine/validator.js +4 -3
  122. package/dist/engine/validator.js.map +1 -1
  123. package/dist/engine/validator.test.d.ts +2 -0
  124. package/dist/engine/validator.test.d.ts.map +1 -0
  125. package/dist/engine/validator.test.js +2371 -0
  126. package/dist/engine/validator.test.js.map +1 -0
  127. package/dist/engine/web-fetcher.test.d.ts +2 -0
  128. package/dist/engine/web-fetcher.test.d.ts.map +1 -0
  129. package/dist/engine/web-fetcher.test.js +360 -0
  130. package/dist/engine/web-fetcher.test.js.map +1 -0
  131. package/dist/i18n/index.test.d.ts +2 -0
  132. package/dist/i18n/index.test.d.ts.map +1 -0
  133. package/dist/i18n/index.test.js +375 -0
  134. package/dist/i18n/index.test.js.map +1 -0
  135. package/dist/index.js +8 -0
  136. package/dist/index.js.map +1 -1
  137. package/dist/index.test.d.ts +2 -0
  138. package/dist/index.test.d.ts.map +1 -0
  139. package/dist/index.test.js +124 -0
  140. package/dist/index.test.js.map +1 -0
  141. package/dist/resources/patterns.test.d.ts +2 -0
  142. package/dist/resources/patterns.test.d.ts.map +1 -0
  143. package/dist/resources/patterns.test.js +142 -0
  144. package/dist/resources/patterns.test.js.map +1 -0
  145. package/dist/resources/process.test.d.ts +2 -0
  146. package/dist/resources/process.test.d.ts.map +1 -0
  147. package/dist/resources/process.test.js +48 -0
  148. package/dist/resources/process.test.js.map +1 -0
  149. package/dist/resources/registry.test.d.ts +2 -0
  150. package/dist/resources/registry.test.d.ts.map +1 -0
  151. package/dist/resources/registry.test.js +138 -0
  152. package/dist/resources/registry.test.js.map +1 -0
  153. package/dist/resources/specs.test.d.ts +2 -0
  154. package/dist/resources/specs.test.d.ts.map +1 -0
  155. package/dist/resources/specs.test.js +130 -0
  156. package/dist/resources/specs.test.js.map +1 -0
  157. package/dist/resources/templates.test.d.ts +2 -0
  158. package/dist/resources/templates.test.d.ts.map +1 -0
  159. package/dist/resources/templates.test.js +119 -0
  160. package/dist/resources/templates.test.js.map +1 -0
  161. package/dist/smoke.test.d.ts +2 -0
  162. package/dist/smoke.test.d.ts.map +1 -0
  163. package/dist/smoke.test.js +229 -0
  164. package/dist/smoke.test.js.map +1 -0
  165. package/dist/storage/base-store.test.d.ts +2 -0
  166. package/dist/storage/base-store.test.d.ts.map +1 -0
  167. package/dist/storage/base-store.test.js +180 -0
  168. package/dist/storage/base-store.test.js.map +1 -0
  169. package/dist/storage/global-store.test.d.ts +2 -0
  170. package/dist/storage/global-store.test.d.ts.map +1 -0
  171. package/dist/storage/global-store.test.js +327 -0
  172. package/dist/storage/global-store.test.js.map +1 -0
  173. package/dist/storage/index.test.d.ts +2 -0
  174. package/dist/storage/index.test.d.ts.map +1 -0
  175. package/dist/storage/index.test.js +56 -0
  176. package/dist/storage/index.test.js.map +1 -0
  177. package/dist/storage/knowledge-store.test.d.ts +2 -0
  178. package/dist/storage/knowledge-store.test.d.ts.map +1 -0
  179. package/dist/storage/knowledge-store.test.js +368 -0
  180. package/dist/storage/knowledge-store.test.js.map +1 -0
  181. package/dist/storage/metrics-store.test.d.ts +2 -0
  182. package/dist/storage/metrics-store.test.d.ts.map +1 -0
  183. package/dist/storage/metrics-store.test.js +212 -0
  184. package/dist/storage/metrics-store.test.js.map +1 -0
  185. package/dist/storage/pattern-store.test.d.ts +2 -0
  186. package/dist/storage/pattern-store.test.d.ts.map +1 -0
  187. package/dist/storage/pattern-store.test.js +224 -0
  188. package/dist/storage/pattern-store.test.js.map +1 -0
  189. package/dist/storage/spec-store.test.d.ts +2 -0
  190. package/dist/storage/spec-store.test.d.ts.map +1 -0
  191. package/dist/storage/spec-store.test.js +227 -0
  192. package/dist/storage/spec-store.test.js.map +1 -0
  193. package/dist/tools/audit.test.d.ts +2 -0
  194. package/dist/tools/audit.test.d.ts.map +1 -0
  195. package/dist/tools/audit.test.js +169 -0
  196. package/dist/tools/audit.test.js.map +1 -0
  197. package/dist/tools/challenge-spec.test.d.ts +2 -0
  198. package/dist/tools/challenge-spec.test.d.ts.map +1 -0
  199. package/dist/tools/challenge-spec.test.js +782 -0
  200. package/dist/tools/challenge-spec.test.js.map +1 -0
  201. package/dist/tools/check-versions.test.d.ts +2 -0
  202. package/dist/tools/check-versions.test.d.ts.map +1 -0
  203. package/dist/tools/check-versions.test.js +214 -0
  204. package/dist/tools/check-versions.test.js.map +1 -0
  205. package/dist/tools/clarify-requirements.test.d.ts +2 -0
  206. package/dist/tools/clarify-requirements.test.d.ts.map +1 -0
  207. package/dist/tools/clarify-requirements.test.js +161 -0
  208. package/dist/tools/clarify-requirements.test.js.map +1 -0
  209. package/dist/tools/consult-docs.test.d.ts +2 -0
  210. package/dist/tools/consult-docs.test.d.ts.map +1 -0
  211. package/dist/tools/consult-docs.test.js +140 -0
  212. package/dist/tools/consult-docs.test.js.map +1 -0
  213. package/dist/tools/create-spec.test.d.ts +2 -0
  214. package/dist/tools/create-spec.test.d.ts.map +1 -0
  215. package/dist/tools/create-spec.test.js +233 -0
  216. package/dist/tools/create-spec.test.js.map +1 -0
  217. package/dist/tools/define-ui-contract.test.d.ts +2 -0
  218. package/dist/tools/define-ui-contract.test.d.ts.map +1 -0
  219. package/dist/tools/define-ui-contract.test.js +479 -0
  220. package/dist/tools/define-ui-contract.test.js.map +1 -0
  221. package/dist/tools/design-schema.test.d.ts +2 -0
  222. package/dist/tools/design-schema.test.d.ts.map +1 -0
  223. package/dist/tools/design-schema.test.js +301 -0
  224. package/dist/tools/design-schema.test.js.map +1 -0
  225. package/dist/tools/detect-agent.test.d.ts +2 -0
  226. package/dist/tools/detect-agent.test.d.ts.map +1 -0
  227. package/dist/tools/detect-agent.test.js +133 -0
  228. package/dist/tools/detect-agent.test.js.map +1 -0
  229. package/dist/tools/detect-drift.test.d.ts +2 -0
  230. package/dist/tools/detect-drift.test.d.ts.map +1 -0
  231. package/dist/tools/detect-drift.test.js +312 -0
  232. package/dist/tools/detect-drift.test.js.map +1 -0
  233. package/dist/tools/discover-mcps.test.d.ts +2 -0
  234. package/dist/tools/discover-mcps.test.d.ts.map +1 -0
  235. package/dist/tools/discover-mcps.test.js +345 -0
  236. package/dist/tools/discover-mcps.test.js.map +1 -0
  237. package/dist/tools/estimate.test.d.ts +2 -0
  238. package/dist/tools/estimate.test.d.ts.map +1 -0
  239. package/dist/tools/estimate.test.js +137 -0
  240. package/dist/tools/estimate.test.js.map +1 -0
  241. package/dist/tools/generate-adr.test.d.ts +2 -0
  242. package/dist/tools/generate-adr.test.d.ts.map +1 -0
  243. package/dist/tools/generate-adr.test.js +206 -0
  244. package/dist/tools/generate-adr.test.js.map +1 -0
  245. package/dist/tools/generate-checklist.test.d.ts +2 -0
  246. package/dist/tools/generate-checklist.test.d.ts.map +1 -0
  247. package/dist/tools/generate-checklist.test.js +201 -0
  248. package/dist/tools/generate-checklist.test.js.map +1 -0
  249. package/dist/tools/generate-docs.test.d.ts +2 -0
  250. package/dist/tools/generate-docs.test.d.ts.map +1 -0
  251. package/dist/tools/generate-docs.test.js +183 -0
  252. package/dist/tools/generate-docs.test.js.map +1 -0
  253. package/dist/tools/generate-execution-plan.test.d.ts +2 -0
  254. package/dist/tools/generate-execution-plan.test.d.ts.map +1 -0
  255. package/dist/tools/generate-execution-plan.test.js +643 -0
  256. package/dist/tools/generate-execution-plan.test.js.map +1 -0
  257. package/dist/tools/generate-rules.test.d.ts +2 -0
  258. package/dist/tools/generate-rules.test.d.ts.map +1 -0
  259. package/dist/tools/generate-rules.test.js +148 -0
  260. package/dist/tools/generate-rules.test.js.map +1 -0
  261. package/dist/tools/generate-skill.test.d.ts +2 -0
  262. package/dist/tools/generate-skill.test.d.ts.map +1 -0
  263. package/dist/tools/generate-skill.test.js +138 -0
  264. package/dist/tools/generate-skill.test.js.map +1 -0
  265. package/dist/tools/generate-sub-agent.test.d.ts +2 -0
  266. package/dist/tools/generate-sub-agent.test.d.ts.map +1 -0
  267. package/dist/tools/generate-sub-agent.test.js +162 -0
  268. package/dist/tools/generate-sub-agent.test.js.map +1 -0
  269. package/dist/tools/generate-tests.test.d.ts +2 -0
  270. package/dist/tools/generate-tests.test.d.ts.map +1 -0
  271. package/dist/tools/generate-tests.test.js +222 -0
  272. package/dist/tools/generate-tests.test.js.map +1 -0
  273. package/dist/tools/init-constitution.test.d.ts +2 -0
  274. package/dist/tools/init-constitution.test.d.ts.map +1 -0
  275. package/dist/tools/init-constitution.test.js +398 -0
  276. package/dist/tools/init-constitution.test.js.map +1 -0
  277. package/dist/tools/init-project/config-builder.d.ts +12 -0
  278. package/dist/tools/init-project/config-builder.d.ts.map +1 -0
  279. package/dist/tools/init-project/config-builder.js +31 -0
  280. package/dist/tools/init-project/config-builder.js.map +1 -0
  281. package/dist/tools/init-project/git-setup.d.ts +8 -0
  282. package/dist/tools/init-project/git-setup.d.ts.map +1 -0
  283. package/dist/tools/init-project/git-setup.js +70 -0
  284. package/dist/tools/init-project/git-setup.js.map +1 -0
  285. package/dist/tools/init-project/handler.d.ts.map +1 -1
  286. package/dist/tools/init-project/handler.js +25 -371
  287. package/dist/tools/init-project/handler.js.map +1 -1
  288. package/dist/tools/init-project/lifecycle-helpers.d.ts +32 -0
  289. package/dist/tools/init-project/lifecycle-helpers.d.ts.map +1 -0
  290. package/dist/tools/init-project/lifecycle-helpers.js +153 -0
  291. package/dist/tools/init-project/lifecycle-helpers.js.map +1 -0
  292. package/dist/tools/init-project/migration-runner.d.ts +28 -0
  293. package/dist/tools/init-project/migration-runner.d.ts.map +1 -0
  294. package/dist/tools/init-project/migration-runner.js +57 -0
  295. package/dist/tools/init-project/migration-runner.js.map +1 -0
  296. package/dist/tools/init-project/rules-writer.d.ts +14 -0
  297. package/dist/tools/init-project/rules-writer.d.ts.map +1 -0
  298. package/dist/tools/init-project/rules-writer.js +43 -0
  299. package/dist/tools/init-project/rules-writer.js.map +1 -0
  300. package/dist/tools/init-project/scaffold-writer.d.ts +29 -0
  301. package/dist/tools/init-project/scaffold-writer.d.ts.map +1 -0
  302. package/dist/tools/init-project/scaffold-writer.js +76 -0
  303. package/dist/tools/init-project/scaffold-writer.js.map +1 -0
  304. package/dist/tools/init-project/stack-detector.d.ts +16 -0
  305. package/dist/tools/init-project/stack-detector.d.ts.map +1 -0
  306. package/dist/tools/init-project/stack-detector.js +19 -0
  307. package/dist/tools/init-project/stack-detector.js.map +1 -0
  308. package/dist/tools/init-project.test.d.ts +2 -0
  309. package/dist/tools/init-project.test.d.ts.map +1 -0
  310. package/dist/tools/init-project.test.js +158 -0
  311. package/dist/tools/init-project.test.js.map +1 -0
  312. package/dist/tools/integrate-pm.test.d.ts +2 -0
  313. package/dist/tools/integrate-pm.test.d.ts.map +1 -0
  314. package/dist/tools/integrate-pm.test.js +558 -0
  315. package/dist/tools/integrate-pm.test.js.map +1 -0
  316. package/dist/tools/learn.test.d.ts +2 -0
  317. package/dist/tools/learn.test.d.ts.map +1 -0
  318. package/dist/tools/learn.test.js +123 -0
  319. package/dist/tools/learn.test.js.map +1 -0
  320. package/dist/tools/list-specs.js +1 -1
  321. package/dist/tools/list-specs.js.map +1 -1
  322. package/dist/tools/list-specs.test.d.ts +2 -0
  323. package/dist/tools/list-specs.test.d.ts.map +1 -0
  324. package/dist/tools/list-specs.test.js +110 -0
  325. package/dist/tools/list-specs.test.js.map +1 -0
  326. package/dist/tools/manage-context.test.d.ts +2 -0
  327. package/dist/tools/manage-context.test.d.ts.map +1 -0
  328. package/dist/tools/manage-context.test.js +359 -0
  329. package/dist/tools/manage-context.test.js.map +1 -0
  330. package/dist/tools/manage-git.test.d.ts +2 -0
  331. package/dist/tools/manage-git.test.d.ts.map +1 -0
  332. package/dist/tools/manage-git.test.js +882 -0
  333. package/dist/tools/manage-git.test.js.map +1 -0
  334. package/dist/tools/orchestrate.test.d.ts +2 -0
  335. package/dist/tools/orchestrate.test.d.ts.map +1 -0
  336. package/dist/tools/orchestrate.test.js +1117 -0
  337. package/dist/tools/orchestrate.test.js.map +1 -0
  338. package/dist/tools/reconcile-spec.test.d.ts +2 -0
  339. package/dist/tools/reconcile-spec.test.d.ts.map +1 -0
  340. package/dist/tools/reconcile-spec.test.js +259 -0
  341. package/dist/tools/reconcile-spec.test.js.map +1 -0
  342. package/dist/tools/red-team.d.ts +3 -0
  343. package/dist/tools/red-team.d.ts.map +1 -0
  344. package/dist/tools/red-team.js +302 -0
  345. package/dist/tools/red-team.js.map +1 -0
  346. package/dist/tools/register-platform-tools/design-stack-tools.d.ts.map +1 -1
  347. package/dist/tools/register-platform-tools/design-stack-tools.js +14 -0
  348. package/dist/tools/register-platform-tools/design-stack-tools.js.map +1 -1
  349. package/dist/tools/register-platform-tools.test.d.ts +2 -0
  350. package/dist/tools/register-platform-tools.test.d.ts.map +1 -0
  351. package/dist/tools/register-platform-tools.test.js +404 -0
  352. package/dist/tools/register-platform-tools.test.js.map +1 -0
  353. package/dist/tools/register-spec-tools.test.d.ts +2 -0
  354. package/dist/tools/register-spec-tools.test.d.ts.map +1 -0
  355. package/dist/tools/register-spec-tools.test.js +407 -0
  356. package/dist/tools/register-spec-tools.test.js.map +1 -0
  357. package/dist/tools/reverse-engineer.test.d.ts +2 -0
  358. package/dist/tools/reverse-engineer.test.d.ts.map +1 -0
  359. package/dist/tools/reverse-engineer.test.js +206 -0
  360. package/dist/tools/reverse-engineer.test.js.map +1 -0
  361. package/dist/tools/schemas.d.ts +20 -0
  362. package/dist/tools/schemas.d.ts.map +1 -0
  363. package/dist/tools/schemas.js +133 -0
  364. package/dist/tools/schemas.js.map +1 -0
  365. package/dist/tools/schemas.test.d.ts +2 -0
  366. package/dist/tools/schemas.test.d.ts.map +1 -0
  367. package/dist/tools/schemas.test.js +245 -0
  368. package/dist/tools/schemas.test.js.map +1 -0
  369. package/dist/tools/set-locale.test.d.ts +2 -0
  370. package/dist/tools/set-locale.test.d.ts.map +1 -0
  371. package/dist/tools/set-locale.test.js +74 -0
  372. package/dist/tools/set-locale.test.js.map +1 -0
  373. package/dist/tools/suggest-mcps.test.d.ts +2 -0
  374. package/dist/tools/suggest-mcps.test.d.ts.map +1 -0
  375. package/dist/tools/suggest-mcps.test.js +198 -0
  376. package/dist/tools/suggest-mcps.test.js.map +1 -0
  377. package/dist/tools/suggest-stack.test.d.ts +2 -0
  378. package/dist/tools/suggest-stack.test.d.ts.map +1 -0
  379. package/dist/tools/suggest-stack.test.js +181 -0
  380. package/dist/tools/suggest-stack.test.js.map +1 -0
  381. package/dist/tools/suggest-tooling.test.d.ts +2 -0
  382. package/dist/tools/suggest-tooling.test.d.ts.map +1 -0
  383. package/dist/tools/suggest-tooling.test.js +213 -0
  384. package/dist/tools/suggest-tooling.test.js.map +1 -0
  385. package/dist/tools/summarize-spec.test.d.ts +2 -0
  386. package/dist/tools/summarize-spec.test.d.ts.map +1 -0
  387. package/dist/tools/summarize-spec.test.js +180 -0
  388. package/dist/tools/summarize-spec.test.js.map +1 -0
  389. package/dist/tools/update-status/dod-gates.d.ts +16 -0
  390. package/dist/tools/update-status/dod-gates.d.ts.map +1 -0
  391. package/dist/tools/update-status/dod-gates.js +117 -0
  392. package/dist/tools/update-status/dod-gates.js.map +1 -0
  393. package/dist/tools/update-status/file-sync.d.ts +6 -0
  394. package/dist/tools/update-status/file-sync.d.ts.map +1 -0
  395. package/dist/tools/update-status/file-sync.js +112 -0
  396. package/dist/tools/update-status/file-sync.js.map +1 -0
  397. package/dist/tools/update-status/index.d.ts +3 -0
  398. package/dist/tools/update-status/index.d.ts.map +1 -0
  399. package/dist/tools/update-status/index.js +181 -0
  400. package/dist/tools/update-status/index.js.map +1 -0
  401. package/dist/tools/update-status/response-builder.d.ts +4 -0
  402. package/dist/tools/update-status/response-builder.d.ts.map +1 -0
  403. package/dist/tools/update-status/response-builder.js +69 -0
  404. package/dist/tools/update-status/response-builder.js.map +1 -0
  405. package/dist/tools/update-status/side-effects.d.ts +15 -0
  406. package/dist/tools/update-status/side-effects.d.ts.map +1 -0
  407. package/dist/tools/update-status/side-effects.js +64 -0
  408. package/dist/tools/update-status/side-effects.js.map +1 -0
  409. package/dist/tools/update-status/transition-guard.d.ts +20 -0
  410. package/dist/tools/update-status/transition-guard.d.ts.map +1 -0
  411. package/dist/tools/update-status/transition-guard.js +75 -0
  412. package/dist/tools/update-status/transition-guard.js.map +1 -0
  413. package/dist/tools/update-status.d.ts +1 -2
  414. package/dist/tools/update-status.d.ts.map +1 -1
  415. package/dist/tools/update-status.js +2 -481
  416. package/dist/tools/update-status.js.map +1 -1
  417. package/dist/tools/update-status.test.d.ts +2 -0
  418. package/dist/tools/update-status.test.d.ts.map +1 -0
  419. package/dist/tools/update-status.test.js +142 -0
  420. package/dist/tools/update-status.test.js.map +1 -0
  421. package/dist/tools/validate.d.ts.map +1 -1
  422. package/dist/tools/validate.js +6 -4
  423. package/dist/tools/validate.js.map +1 -1
  424. package/dist/tools/validate.test.d.ts +2 -0
  425. package/dist/tools/validate.test.d.ts.map +1 -0
  426. package/dist/tools/validate.test.js +137 -0
  427. package/dist/tools/validate.test.js.map +1 -0
  428. package/dist/types/analysis.d.ts +2 -1
  429. package/dist/types/analysis.d.ts.map +1 -1
  430. package/dist/types/index.d.ts +2 -0
  431. package/dist/types/index.d.ts.map +1 -1
  432. package/dist/types/index.js +2 -0
  433. package/dist/types/index.js.map +1 -1
  434. package/dist/types/red-team.d.ts +29 -0
  435. package/dist/types/red-team.d.ts.map +1 -0
  436. package/dist/types/red-team.js +3 -0
  437. package/dist/types/red-team.js.map +1 -0
  438. package/dist/types/update-notifier.d.ts +5 -0
  439. package/dist/types/update-notifier.d.ts.map +1 -0
  440. package/dist/types/update-notifier.js +3 -0
  441. package/dist/types/update-notifier.js.map +1 -0
  442. package/package.json +9 -2
  443. package/src/config/license-plans.json +2 -1
  444. package/src/i18n/messages/en.json +5 -0
  445. package/src/i18n/messages/es.json +5 -0
  446. package/src/i18n/messages/pt.json +5 -0
@@ -0,0 +1,782 @@
1
+ // Tests for handleChallengeSpec
2
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
3
+ vi.mock('../i18n/index.js', () => ({
4
+ t: (key) => key,
5
+ ti: (key, vars) => `${key}:${JSON.stringify(vars)}`,
6
+ }));
7
+ vi.mock('../storage/index.js', () => ({
8
+ specStore: { getSpec: vi.fn() },
9
+ knowledgeStore: { getKnowledge: vi.fn() },
10
+ }));
11
+ vi.mock('node:fs/promises', () => ({
12
+ readFile: vi.fn(),
13
+ }));
14
+ import { handleChallengeSpec } from './challenge-spec.js';
15
+ import { specStore, knowledgeStore } from '../storage/index.js';
16
+ import { readFile } from 'node:fs/promises';
17
+ const mockGetSpec = vi.mocked(specStore.getSpec);
18
+ const mockGetKnowledge = vi.mocked(knowledgeStore.getKnowledge);
19
+ const mockReadFile = vi.mocked(readFile);
20
+ const baseSpec = {
21
+ id: 'SPEC-001',
22
+ title: 'Payment Integration',
23
+ type: 'feature',
24
+ scope: 'feature',
25
+ target: 'fullstack',
26
+ tags: ['payment', 'stripe'],
27
+ status: 'approved',
28
+ risk: 'high',
29
+ difficulty: 4,
30
+ estimation: { devHours: 16, reviewHours: 4, totalCostUsd: 400 },
31
+ dependencies: [],
32
+ huPath: null,
33
+ fichaTecnicaPath: null,
34
+ };
35
+ const baseKnowledge = {
36
+ language: 'typescript',
37
+ framework: 'next',
38
+ projectPath: '/test',
39
+ stack: [],
40
+ conventions: {},
41
+ architecture: { primary: 'monolith', secondary: [], layers: [] },
42
+ database: 'postgresql',
43
+ testCommand: null,
44
+ buildCommand: null,
45
+ linting: { detectedLinters: [] },
46
+ apiContracts: [],
47
+ layers: [],
48
+ };
49
+ beforeEach(() => {
50
+ vi.clearAllMocks();
51
+ mockReadFile.mockRejectedValue(new Error('not found'));
52
+ });
53
+ describe('handleChallengeSpec', () => {
54
+ it('should return error when spec not found', async () => {
55
+ mockGetSpec.mockResolvedValue(null);
56
+ const result = await handleChallengeSpec({
57
+ specId: 'SPEC-999',
58
+ projectId: 'proj-1',
59
+ });
60
+ expect(result.isError).toBe(true);
61
+ });
62
+ it('should return error when knowledge not found', async () => {
63
+ mockGetSpec.mockResolvedValue(baseSpec);
64
+ mockGetKnowledge.mockResolvedValue(null);
65
+ const result = await handleChallengeSpec({
66
+ specId: 'SPEC-001',
67
+ projectId: 'proj-1',
68
+ });
69
+ expect(result.isError).toBe(true);
70
+ });
71
+ it('should analyze all focus areas by default', async () => {
72
+ mockGetSpec.mockResolvedValue(baseSpec);
73
+ mockGetKnowledge.mockResolvedValue(baseKnowledge);
74
+ const result = await handleChallengeSpec({
75
+ specId: 'SPEC-001',
76
+ projectId: 'proj-1',
77
+ });
78
+ expect(result.isError).toBeUndefined();
79
+ expect(result.content).toHaveLength(2);
80
+ const data = JSON.parse(result.content[1].text);
81
+ expect(data.failureScenarios.length).toBeGreaterThan(0);
82
+ expect(data.concurrencyAnalysis).toBeDefined();
83
+ expect(data.scalabilityAssessment).toBeDefined();
84
+ expect(data.overallRisk).toBeDefined();
85
+ expect(data.summary.focusAreas).toHaveLength(5);
86
+ });
87
+ it('should filter to specific focus area: failures', async () => {
88
+ mockGetSpec.mockResolvedValue(baseSpec);
89
+ mockGetKnowledge.mockResolvedValue(baseKnowledge);
90
+ const result = await handleChallengeSpec({
91
+ specId: 'SPEC-001',
92
+ projectId: 'proj-1',
93
+ focus: ['failures'],
94
+ });
95
+ const data = JSON.parse(result.content[1].text);
96
+ expect(data.summary.focusAreas).toEqual(['failures']);
97
+ expect(data.failureScenarios.length).toBeGreaterThan(0);
98
+ // No concurrency analysis when not focused
99
+ expect(data.concurrencyAnalysis.hotPaths).toHaveLength(0);
100
+ });
101
+ it('should focus on security scenarios', async () => {
102
+ mockGetSpec.mockResolvedValue({
103
+ ...baseSpec,
104
+ title: 'Auth login user permission role',
105
+ tags: ['auth', 'security'],
106
+ });
107
+ mockGetKnowledge.mockResolvedValue(baseKnowledge);
108
+ const result = await handleChallengeSpec({
109
+ specId: 'SPEC-001',
110
+ projectId: 'proj-1',
111
+ focus: ['security'],
112
+ });
113
+ const data = JSON.parse(result.content[1].text);
114
+ const hasAuthBypass = data.failureScenarios.some((s) => s.scenario.includes('authentication bypass'));
115
+ expect(hasAuthBypass).toBe(true);
116
+ });
117
+ it('should generate scale scenarios', async () => {
118
+ mockGetSpec.mockResolvedValue({
119
+ ...baseSpec, scope: 'architectural',
120
+ });
121
+ mockGetKnowledge.mockResolvedValue(baseKnowledge);
122
+ const result = await handleChallengeSpec({
123
+ specId: 'SPEC-001',
124
+ projectId: 'proj-1',
125
+ focus: ['scale'],
126
+ });
127
+ const data = JSON.parse(result.content[1].text);
128
+ const hasTraffic = data.failureScenarios.some((s) => s.scenario.includes('Traffic spike'));
129
+ expect(hasTraffic).toBe(true);
130
+ });
131
+ it('should generate data-consistency scenarios', async () => {
132
+ mockGetSpec.mockResolvedValue(baseSpec);
133
+ mockGetKnowledge.mockResolvedValue(baseKnowledge);
134
+ const result = await handleChallengeSpec({
135
+ specId: 'SPEC-001',
136
+ projectId: 'proj-1',
137
+ focus: ['data-consistency'],
138
+ });
139
+ const data = JSON.parse(result.content[1].text);
140
+ const hasDuplicate = data.failureScenarios.some((s) => s.scenario.includes('double-clicks'));
141
+ expect(hasDuplicate).toBe(true);
142
+ });
143
+ it('should generate concurrency analysis', async () => {
144
+ mockGetSpec.mockResolvedValue({
145
+ ...baseSpec,
146
+ title: 'Cart counter login submit update status',
147
+ tags: ['session', 'counter'],
148
+ });
149
+ mockGetKnowledge.mockResolvedValue(baseKnowledge);
150
+ const result = await handleChallengeSpec({
151
+ specId: 'SPEC-001',
152
+ projectId: 'proj-1',
153
+ focus: ['concurrency'],
154
+ });
155
+ const data = JSON.parse(result.content[1].text);
156
+ expect(data.concurrencyAnalysis.hotPaths.length).toBeGreaterThan(0);
157
+ expect(data.concurrencyAnalysis.raceConditions.length).toBeGreaterThan(0);
158
+ });
159
+ it('should calculate overall risk correctly', async () => {
160
+ mockGetSpec.mockResolvedValue(baseSpec);
161
+ mockGetKnowledge.mockResolvedValue(baseKnowledge);
162
+ const result = await handleChallengeSpec({
163
+ specId: 'SPEC-001',
164
+ projectId: 'proj-1',
165
+ });
166
+ const data = JSON.parse(result.content[1].text);
167
+ expect(['low', 'medium', 'high', 'critical']).toContain(data.overallRisk);
168
+ });
169
+ it('should handle scalability assessment for cross-module scope', async () => {
170
+ mockGetSpec.mockResolvedValue({
171
+ ...baseSpec, scope: 'cross-module',
172
+ });
173
+ mockGetKnowledge.mockResolvedValue(baseKnowledge);
174
+ const result = await handleChallengeSpec({
175
+ specId: 'SPEC-001',
176
+ projectId: 'proj-1',
177
+ });
178
+ const data = JSON.parse(result.content[1].text);
179
+ expect(data.scalabilityAssessment).toContain('phased rollout');
180
+ });
181
+ // --- Coverage for uncovered lines: readSpecContent catch blocks (lines 566-577) ---
182
+ it('should read huPath file content when available', async () => {
183
+ mockGetSpec.mockResolvedValue({
184
+ ...baseSpec,
185
+ huPath: '/test/hu.md',
186
+ fichaTecnicaPath: null,
187
+ });
188
+ mockGetKnowledge.mockResolvedValue(baseKnowledge);
189
+ mockReadFile.mockImplementation(((path) => {
190
+ if (path === '/test/hu.md') {
191
+ return Promise.resolve('login auth user validation timeout retry');
192
+ }
193
+ return Promise.reject(new Error('not found'));
194
+ }));
195
+ const result = await handleChallengeSpec({
196
+ specId: 'SPEC-001',
197
+ projectId: 'proj-1',
198
+ });
199
+ expect(result.isError).toBeUndefined();
200
+ const data = JSON.parse(result.content[1].text);
201
+ expect(data.failureScenarios.length).toBeGreaterThan(0);
202
+ });
203
+ it('should read fichaTecnicaPath file content when available', async () => {
204
+ mockGetSpec.mockResolvedValue({
205
+ ...baseSpec,
206
+ huPath: null,
207
+ fichaTecnicaPath: '/test/ficha.md',
208
+ });
209
+ mockGetKnowledge.mockResolvedValue(baseKnowledge);
210
+ mockReadFile.mockImplementation(((path) => {
211
+ if (path === '/test/ficha.md') {
212
+ return Promise.resolve('counter increment balance stock vote status transition');
213
+ }
214
+ return Promise.reject(new Error('not found'));
215
+ }));
216
+ const result = await handleChallengeSpec({
217
+ specId: 'SPEC-001',
218
+ projectId: 'proj-1',
219
+ focus: ['concurrency'],
220
+ });
221
+ expect(result.isError).toBeUndefined();
222
+ const data = JSON.parse(result.content[1].text);
223
+ expect(data.concurrencyAnalysis.raceConditions.length).toBeGreaterThan(0);
224
+ });
225
+ it('should handle readFile errors for both huPath and fichaTecnicaPath gracefully', async () => {
226
+ mockGetSpec.mockResolvedValue({
227
+ ...baseSpec,
228
+ huPath: '/test/missing-hu.md',
229
+ fichaTecnicaPath: '/test/missing-ficha.md',
230
+ });
231
+ mockGetKnowledge.mockResolvedValue(baseKnowledge);
232
+ mockReadFile.mockRejectedValue(new Error('ENOENT'));
233
+ const result = await handleChallengeSpec({
234
+ specId: 'SPEC-001',
235
+ projectId: 'proj-1',
236
+ });
237
+ // Should not error out - catch blocks swallow file read errors
238
+ expect(result.isError).toBeUndefined();
239
+ });
240
+ // --- Coverage for generateScaleScenarios (line 324): non-architectural scope ---
241
+ it('should generate scale scenarios with low probability for non-architectural scope', async () => {
242
+ mockGetSpec.mockResolvedValue({
243
+ ...baseSpec,
244
+ scope: 'feature',
245
+ title: 'Database query search list',
246
+ tags: ['database'],
247
+ });
248
+ mockGetKnowledge.mockResolvedValue(baseKnowledge);
249
+ const result = await handleChallengeSpec({
250
+ specId: 'SPEC-001',
251
+ projectId: 'proj-1',
252
+ focus: ['scale'],
253
+ });
254
+ const data = JSON.parse(result.content[1].text);
255
+ const trafficScenario = data.failureScenarios.find((s) => s.scenario.includes('Traffic spike'));
256
+ expect(trafficScenario.probability).toBe('low');
257
+ // Also should have data growth scenario since content has 'database' and 'query' and 'search' and 'list'
258
+ const dataGrowth = data.failureScenarios.find((s) => s.scenario.includes('Database grows'));
259
+ expect(dataGrowth).toBeDefined();
260
+ });
261
+ // --- Coverage for calculateOverallRisk (line 551): critical risk branch ---
262
+ it('should return critical overall risk when >= 3 critical impacts', async () => {
263
+ // Create a spec that triggers many critical-impact scenarios
264
+ mockGetSpec.mockResolvedValue({
265
+ ...baseSpec,
266
+ target: 'fullstack',
267
+ title: 'auth login user permission role input form query search payment stripe webhook upload file stream batch counter increment balance stock vote status update transition session cart draft cache global config',
268
+ tags: ['auth', 'payment', 'security'],
269
+ });
270
+ mockGetKnowledge.mockResolvedValue(baseKnowledge);
271
+ const result = await handleChallengeSpec({
272
+ specId: 'SPEC-001',
273
+ projectId: 'proj-1',
274
+ });
275
+ const data = JSON.parse(result.content[1].text);
276
+ const criticalCount = data.failureScenarios.filter((s) => s.impact === 'critical').length;
277
+ // With all focus areas and auth+payment+injection, we should get multiple critical scenarios
278
+ expect(criticalCount).toBeGreaterThanOrEqual(2);
279
+ });
280
+ // --- Coverage for low risk path (line 559) ---
281
+ it('should return low overall risk for minimal spec with no high-risk scenarios', async () => {
282
+ mockGetSpec.mockResolvedValue({
283
+ ...baseSpec,
284
+ target: 'frontend',
285
+ title: 'Simple page',
286
+ tags: [],
287
+ });
288
+ mockGetKnowledge.mockResolvedValue(baseKnowledge);
289
+ const result = await handleChallengeSpec({
290
+ specId: 'SPEC-001',
291
+ projectId: 'proj-1',
292
+ focus: ['data-consistency'],
293
+ });
294
+ const data = JSON.parse(result.content[1].text);
295
+ // With only data-consistency focus on a minimal frontend spec, should be low-medium risk
296
+ expect(['low', 'medium']).toContain(data.overallRisk);
297
+ });
298
+ // --- Coverage for empty focus array ---
299
+ it('should use all focus areas when focus is an empty array', async () => {
300
+ mockGetSpec.mockResolvedValue(baseSpec);
301
+ mockGetKnowledge.mockResolvedValue(baseKnowledge);
302
+ const result = await handleChallengeSpec({
303
+ specId: 'SPEC-001',
304
+ projectId: 'proj-1',
305
+ focus: [],
306
+ });
307
+ const data = JSON.parse(result.content[1].text);
308
+ expect(data.summary.focusAreas).toHaveLength(5);
309
+ });
310
+ // --- Coverage for scalabilityAssessment with 0 critical scenarios ---
311
+ it('should show no critical concerns when zero critical scenarios', async () => {
312
+ mockGetSpec.mockResolvedValue({
313
+ ...baseSpec,
314
+ target: 'frontend',
315
+ scope: 'trivial',
316
+ title: 'Simple button',
317
+ tags: [],
318
+ });
319
+ mockGetKnowledge.mockResolvedValue(baseKnowledge);
320
+ const result = await handleChallengeSpec({
321
+ specId: 'SPEC-001',
322
+ projectId: 'proj-1',
323
+ focus: ['scale'],
324
+ });
325
+ const data = JSON.parse(result.content[1].text);
326
+ expect(data.scalabilityAssessment).toContain('No critical scalability concerns');
327
+ });
328
+ // --- Coverage for concurrency with file/upload/resource and no race conditions ---
329
+ it('should detect file-related race conditions in concurrency analysis', async () => {
330
+ mockGetSpec.mockResolvedValue({
331
+ ...baseSpec,
332
+ title: 'File upload resource manager',
333
+ tags: ['file', 'upload'],
334
+ });
335
+ mockGetKnowledge.mockResolvedValue(baseKnowledge);
336
+ const result = await handleChallengeSpec({
337
+ specId: 'SPEC-001',
338
+ projectId: 'proj-1',
339
+ focus: ['concurrency'],
340
+ });
341
+ const data = JSON.parse(result.content[1].text);
342
+ const hasFileRace = data.concurrencyAnalysis.raceConditions.some((r) => r.includes('file'));
343
+ expect(hasFileRace).toBe(true);
344
+ });
345
+ // --- Coverage for concurrency: list/search/feed hot paths ---
346
+ it('should detect list/search/feed hot paths', async () => {
347
+ mockGetSpec.mockResolvedValue({
348
+ ...baseSpec,
349
+ title: 'Search feed list endpoint',
350
+ tags: ['search'],
351
+ });
352
+ mockGetKnowledge.mockResolvedValue(baseKnowledge);
353
+ const result = await handleChallengeSpec({
354
+ specId: 'SPEC-001',
355
+ projectId: 'proj-1',
356
+ focus: ['concurrency'],
357
+ });
358
+ const data = JSON.parse(result.content[1].text);
359
+ const hasListPath = data.concurrencyAnalysis.hotPaths.some((p) => p.includes('List/search'));
360
+ expect(hasListPath).toBe(true);
361
+ });
362
+ // --- Coverage for shared state: cache/global/config ---
363
+ it('should detect cache/global shared state', async () => {
364
+ mockGetSpec.mockResolvedValue({
365
+ ...baseSpec,
366
+ title: 'Global cache config manager',
367
+ tags: ['cache'],
368
+ });
369
+ mockGetKnowledge.mockResolvedValue(baseKnowledge);
370
+ const result = await handleChallengeSpec({
371
+ specId: 'SPEC-001',
372
+ projectId: 'proj-1',
373
+ focus: ['concurrency'],
374
+ });
375
+ const data = JSON.parse(result.content[1].text);
376
+ const hasCacheState = data.concurrencyAnalysis.sharedState.some((s) => s.includes('Global cache'));
377
+ expect(hasCacheState).toBe(true);
378
+ });
379
+ // --- Coverage for data-consistency: stale data with cache/real-time ---
380
+ it('should detect stale data scenario for specs mentioning cache', async () => {
381
+ mockGetSpec.mockResolvedValue({
382
+ ...baseSpec,
383
+ title: 'Real-time cache update transaction modify save',
384
+ tags: ['cache', 'real-time'],
385
+ });
386
+ mockGetKnowledge.mockResolvedValue(baseKnowledge);
387
+ const result = await handleChallengeSpec({
388
+ specId: 'SPEC-001',
389
+ projectId: 'proj-1',
390
+ focus: ['data-consistency'],
391
+ });
392
+ const data = JSON.parse(result.content[1].text);
393
+ const hasStale = data.failureScenarios.some((s) => s.scenario.includes('Stale data'));
394
+ expect(hasStale).toBe(true);
395
+ const hasPartialWrite = data.failureScenarios.some((s) => s.scenario.includes('Partial write'));
396
+ expect(hasPartialWrite).toBe(true);
397
+ });
398
+ // --- Coverage for memory/resource exhaustion scenarios in failures ---
399
+ it('should detect memory exhaustion for specs with upload/file/stream', async () => {
400
+ mockGetSpec.mockResolvedValue({
401
+ ...baseSpec,
402
+ title: 'Bulk upload file stream processing',
403
+ target: 'backend',
404
+ tags: ['upload'],
405
+ });
406
+ mockGetKnowledge.mockResolvedValue(baseKnowledge);
407
+ const result = await handleChallengeSpec({
408
+ specId: 'SPEC-001',
409
+ projectId: 'proj-1',
410
+ focus: ['failures'],
411
+ });
412
+ const data = JSON.parse(result.content[1].text);
413
+ const hasMemory = data.failureScenarios.some((s) => s.scenario.includes('Memory exhaustion'));
414
+ expect(hasMemory).toBe(true);
415
+ });
416
+ // --- Coverage for injection scenarios in security ---
417
+ it('should detect injection scenarios for specs with input/form/query', async () => {
418
+ mockGetSpec.mockResolvedValue({
419
+ ...baseSpec,
420
+ title: 'Search input form query processor',
421
+ tags: ['form', 'input'],
422
+ });
423
+ mockGetKnowledge.mockResolvedValue(baseKnowledge);
424
+ const result = await handleChallengeSpec({
425
+ specId: 'SPEC-001',
426
+ projectId: 'proj-1',
427
+ focus: ['security'],
428
+ });
429
+ const data = JSON.parse(result.content[1].text);
430
+ const hasInjection = data.failureScenarios.some((s) => s.scenario.includes('injection'));
431
+ expect(hasInjection).toBe(true);
432
+ });
433
+ // --- Coverage for false branch: database failures block skipped for frontend-only spec ---
434
+ it('should skip database failure scenarios for frontend spec with no DB keywords', async () => {
435
+ mockGetSpec.mockResolvedValue({
436
+ ...baseSpec,
437
+ target: 'frontend',
438
+ title: 'Simple UI component',
439
+ tags: ['ui'],
440
+ });
441
+ mockGetKnowledge.mockResolvedValue(baseKnowledge);
442
+ const result = await handleChallengeSpec({
443
+ specId: 'SPEC-001',
444
+ projectId: 'proj-1',
445
+ focus: ['failures'],
446
+ });
447
+ const data = JSON.parse(result.content[1].text);
448
+ const hasDbPool = data.failureScenarios.some((s) => s.scenario.includes('connection pool'));
449
+ expect(hasDbPool).toBe(false);
450
+ const hasMigration = data.failureScenarios.some((s) => s.scenario.includes('Migration fails'));
451
+ expect(hasMigration).toBe(false);
452
+ // But should still have input validation (always pushed) and network (frontend target matches)
453
+ const hasNetwork = data.failureScenarios.some((s) => s.scenario.includes('network timeout'));
454
+ expect(hasNetwork).toBe(true);
455
+ });
456
+ // --- Coverage for contentMentions true branches in generateFailureScenarios ---
457
+ it('should report "Partially addressed" for network failures when content mentions timeout/retry', async () => {
458
+ mockGetSpec.mockResolvedValue({
459
+ ...baseSpec,
460
+ target: 'fullstack',
461
+ huPath: '/test/hu.md',
462
+ });
463
+ mockGetKnowledge.mockResolvedValue(baseKnowledge);
464
+ mockReadFile.mockImplementation(((path) => {
465
+ if (path === '/test/hu.md') {
466
+ return Promise.resolve('The API uses timeout and retry with fallback logic');
467
+ }
468
+ return Promise.reject(new Error('not found'));
469
+ }));
470
+ const result = await handleChallengeSpec({
471
+ specId: 'SPEC-001',
472
+ projectId: 'proj-1',
473
+ focus: ['failures'],
474
+ });
475
+ const data = JSON.parse(result.content[1].text);
476
+ const networkScenario = data.failureScenarios.find((s) => s.scenario.includes('network timeout'));
477
+ expect(networkScenario).toBeDefined();
478
+ expect(networkScenario.currentHandling).toBe('Partially addressed in spec');
479
+ });
480
+ it('should report "Partially addressed" for migration when content mentions rollback', async () => {
481
+ mockGetSpec.mockResolvedValue({
482
+ ...baseSpec,
483
+ target: 'database',
484
+ huPath: '/test/hu.md',
485
+ });
486
+ mockGetKnowledge.mockResolvedValue(baseKnowledge);
487
+ mockReadFile.mockImplementation(((path) => {
488
+ if (path === '/test/hu.md') {
489
+ return Promise.resolve('migration with rollback for database schema changes');
490
+ }
491
+ return Promise.reject(new Error('not found'));
492
+ }));
493
+ const result = await handleChallengeSpec({
494
+ specId: 'SPEC-001',
495
+ projectId: 'proj-1',
496
+ focus: ['failures'],
497
+ });
498
+ const data = JSON.parse(result.content[1].text);
499
+ const migrationScenario = data.failureScenarios.find((s) => s.scenario.includes('Migration fails'));
500
+ expect(migrationScenario).toBeDefined();
501
+ expect(migrationScenario.currentHandling).toBe('Partially addressed');
502
+ });
503
+ it('should report "Validation mentioned" when content mentions validation keywords', async () => {
504
+ mockGetSpec.mockResolvedValue({
505
+ ...baseSpec,
506
+ target: 'frontend',
507
+ huPath: '/test/hu.md',
508
+ });
509
+ mockGetKnowledge.mockResolvedValue(baseKnowledge);
510
+ mockReadFile.mockImplementation(((path) => {
511
+ if (path === '/test/hu.md') {
512
+ return Promise.resolve('All inputs validated with zod schema validation');
513
+ }
514
+ return Promise.reject(new Error('not found'));
515
+ }));
516
+ const result = await handleChallengeSpec({
517
+ specId: 'SPEC-001',
518
+ projectId: 'proj-1',
519
+ focus: ['failures'],
520
+ });
521
+ const data = JSON.parse(result.content[1].text);
522
+ const inputScenario = data.failureScenarios.find((s) => s.scenario.includes('Malformed or oversized'));
523
+ expect(inputScenario).toBeDefined();
524
+ expect(inputScenario.currentHandling).toBe('Validation mentioned in spec');
525
+ });
526
+ it('should report "Partially addressed" for third-party when content mentions circuit breaker', async () => {
527
+ mockGetSpec.mockResolvedValue({
528
+ ...baseSpec,
529
+ target: 'backend',
530
+ huPath: '/test/hu.md',
531
+ });
532
+ mockGetKnowledge.mockResolvedValue(baseKnowledge);
533
+ mockReadFile.mockImplementation(((path) => {
534
+ if (path === '/test/hu.md') {
535
+ return Promise.resolve('stripe payment webhook with circuit breaker and retry queue fallback');
536
+ }
537
+ return Promise.reject(new Error('not found'));
538
+ }));
539
+ const result = await handleChallengeSpec({
540
+ specId: 'SPEC-001',
541
+ projectId: 'proj-1',
542
+ focus: ['failures'],
543
+ });
544
+ const data = JSON.parse(result.content[1].text);
545
+ const thirdPartyScenario = data.failureScenarios.find((s) => s.scenario.includes('Third-party service'));
546
+ expect(thirdPartyScenario).toBeDefined();
547
+ expect(thirdPartyScenario.currentHandling).toBe('Partially addressed');
548
+ });
549
+ it('should report "Partially addressed" for memory exhaustion when content mentions streaming/pagination', async () => {
550
+ mockGetSpec.mockResolvedValue({
551
+ ...baseSpec,
552
+ target: 'backend',
553
+ huPath: '/test/hu.md',
554
+ });
555
+ mockGetKnowledge.mockResolvedValue(baseKnowledge);
556
+ mockReadFile.mockImplementation(((path) => {
557
+ if (path === '/test/hu.md') {
558
+ return Promise.resolve('bulk upload file with stream chunk pagination limit');
559
+ }
560
+ return Promise.reject(new Error('not found'));
561
+ }));
562
+ const result = await handleChallengeSpec({
563
+ specId: 'SPEC-001',
564
+ projectId: 'proj-1',
565
+ focus: ['failures'],
566
+ });
567
+ const data = JSON.parse(result.content[1].text);
568
+ const memoryScenario = data.failureScenarios.find((s) => s.scenario.includes('Memory exhaustion'));
569
+ expect(memoryScenario).toBeDefined();
570
+ expect(memoryScenario.currentHandling).toBe('Partially addressed');
571
+ });
572
+ // --- Coverage for contentMentions true branches in generateSecurityScenarios ---
573
+ it('should report "Authentication mentioned" when content mentions jwt/session', async () => {
574
+ mockGetSpec.mockResolvedValue({
575
+ ...baseSpec,
576
+ target: 'backend',
577
+ huPath: '/test/hu.md',
578
+ });
579
+ mockGetKnowledge.mockResolvedValue(baseKnowledge);
580
+ mockReadFile.mockImplementation(((path) => {
581
+ if (path === '/test/hu.md') {
582
+ return Promise.resolve('auth login user with jwt session middleware permission role');
583
+ }
584
+ return Promise.reject(new Error('not found'));
585
+ }));
586
+ const result = await handleChallengeSpec({
587
+ specId: 'SPEC-001',
588
+ projectId: 'proj-1',
589
+ focus: ['security'],
590
+ });
591
+ const data = JSON.parse(result.content[1].text);
592
+ const authScenario = data.failureScenarios.find((s) => s.scenario.includes('authentication bypass'));
593
+ expect(authScenario).toBeDefined();
594
+ expect(authScenario.currentHandling).toBe('Authentication mentioned');
595
+ });
596
+ it('should report "Some sanitization mentioned" when content mentions parameterized/escaping', async () => {
597
+ mockGetSpec.mockResolvedValue({
598
+ ...baseSpec,
599
+ target: 'backend',
600
+ huPath: '/test/hu.md',
601
+ });
602
+ mockGetKnowledge.mockResolvedValue(baseKnowledge);
603
+ mockReadFile.mockImplementation(((path) => {
604
+ if (path === '/test/hu.md') {
605
+ return Promise.resolve('input form query search user sanitized escaped parameterized prepared statements');
606
+ }
607
+ return Promise.reject(new Error('not found'));
608
+ }));
609
+ const result = await handleChallengeSpec({
610
+ specId: 'SPEC-001',
611
+ projectId: 'proj-1',
612
+ focus: ['security'],
613
+ });
614
+ const data = JSON.parse(result.content[1].text);
615
+ const injectionScenario = data.failureScenarios.find((s) => s.scenario.includes('injection'));
616
+ expect(injectionScenario).toBeDefined();
617
+ expect(injectionScenario.currentHandling).toBe('Some sanitization mentioned');
618
+ });
619
+ it('should report "Some protection mentioned" for CSRF when content mentions rate limit/csrf', async () => {
620
+ mockGetSpec.mockResolvedValue({
621
+ ...baseSpec,
622
+ target: 'backend',
623
+ huPath: '/test/hu.md',
624
+ });
625
+ mockGetKnowledge.mockResolvedValue(baseKnowledge);
626
+ mockReadFile.mockImplementation(((path) => {
627
+ if (path === '/test/hu.md') {
628
+ return Promise.resolve('csrf token protection with rate limit and throttle captcha');
629
+ }
630
+ return Promise.reject(new Error('not found'));
631
+ }));
632
+ const result = await handleChallengeSpec({
633
+ specId: 'SPEC-001',
634
+ projectId: 'proj-1',
635
+ focus: ['security'],
636
+ });
637
+ const data = JSON.parse(result.content[1].text);
638
+ const csrfScenario = data.failureScenarios.find((s) => s.scenario.includes('CSRF'));
639
+ expect(csrfScenario).toBeDefined();
640
+ expect(csrfScenario.currentHandling).toBe('Some protection mentioned');
641
+ });
642
+ // --- Coverage for memory exhaustion false branch: upload without stream/limit/chunk/pagination ---
643
+ it('should report "Not addressed" for memory exhaustion when content has upload but no streaming keywords', async () => {
644
+ mockGetSpec.mockResolvedValue({
645
+ ...baseSpec,
646
+ target: 'backend',
647
+ title: 'Batch upload processor',
648
+ tags: ['batch'],
649
+ });
650
+ mockGetKnowledge.mockResolvedValue(baseKnowledge);
651
+ const result = await handleChallengeSpec({
652
+ specId: 'SPEC-001',
653
+ projectId: 'proj-1',
654
+ focus: ['failures'],
655
+ });
656
+ const data = JSON.parse(result.content[1].text);
657
+ const memoryScenario = data.failureScenarios.find((s) => s.scenario.includes('Memory exhaustion'));
658
+ expect(memoryScenario).toBeDefined();
659
+ expect(memoryScenario.currentHandling).toBe('Not addressed');
660
+ });
661
+ // --- Coverage for generateScaleScenarios true branch: cache/cdn/queue mentioned ---
662
+ it('should report "Some scaling strategy mentioned" when content mentions cache/scale', async () => {
663
+ mockGetSpec.mockResolvedValue({
664
+ ...baseSpec,
665
+ target: 'backend',
666
+ huPath: '/test/hu.md',
667
+ });
668
+ mockGetKnowledge.mockResolvedValue(baseKnowledge);
669
+ mockReadFile.mockImplementation(((path) => {
670
+ if (path === '/test/hu.md') {
671
+ return Promise.resolve('auto-scale with cache cdn queue for high traffic');
672
+ }
673
+ return Promise.reject(new Error('not found'));
674
+ }));
675
+ const result = await handleChallengeSpec({
676
+ specId: 'SPEC-001',
677
+ projectId: 'proj-1',
678
+ focus: ['scale'],
679
+ });
680
+ const data = JSON.parse(result.content[1].text);
681
+ const trafficScenario = data.failureScenarios.find((s) => s.scenario.includes('Traffic spike'));
682
+ expect(trafficScenario).toBeDefined();
683
+ expect(trafficScenario.currentHandling).toBe('Some scaling strategy mentioned');
684
+ });
685
+ // --- Coverage for contentMentions true branch on line 358 (scale: pagination/index) ---
686
+ it('should report "Some query optimization mentioned" when content mentions pagination/index', async () => {
687
+ mockGetSpec.mockResolvedValue({
688
+ ...baseSpec,
689
+ target: 'backend',
690
+ huPath: '/test/hu.md',
691
+ });
692
+ mockGetKnowledge.mockResolvedValue(baseKnowledge);
693
+ mockReadFile.mockImplementation(((path) => {
694
+ if (path === '/test/hu.md') {
695
+ return Promise.resolve('database table query list search with index pagination cursor partition');
696
+ }
697
+ return Promise.reject(new Error('not found'));
698
+ }));
699
+ const result = await handleChallengeSpec({
700
+ specId: 'SPEC-001',
701
+ projectId: 'proj-1',
702
+ focus: ['scale'],
703
+ });
704
+ const data = JSON.parse(result.content[1].text);
705
+ const dataGrowthScenario = data.failureScenarios.find((s) => s.scenario.includes('Database grows'));
706
+ expect(dataGrowthScenario).toBeDefined();
707
+ expect(dataGrowthScenario.currentHandling).toBe('Some query optimization mentioned');
708
+ });
709
+ // --- Coverage for data-consistency: partial writes with transaction/atomic mentioned ---
710
+ it('should report "Transactions mentioned" for partial writes when content mentions atomic/transaction', async () => {
711
+ mockGetSpec.mockResolvedValue({
712
+ ...baseSpec,
713
+ target: 'backend',
714
+ huPath: '/test/hu.md',
715
+ });
716
+ mockGetKnowledge.mockResolvedValue(baseKnowledge);
717
+ mockReadFile.mockImplementation(((path) => {
718
+ if (path === '/test/hu.md') {
719
+ return Promise.resolve('transaction atomic rollback update create modify save');
720
+ }
721
+ return Promise.reject(new Error('not found'));
722
+ }));
723
+ const result = await handleChallengeSpec({
724
+ specId: 'SPEC-001',
725
+ projectId: 'proj-1',
726
+ focus: ['data-consistency'],
727
+ });
728
+ const data = JSON.parse(result.content[1].text);
729
+ const partialWriteScenario = data.failureScenarios.find((s) => s.scenario.includes('Partial write'));
730
+ expect(partialWriteScenario).toBeDefined();
731
+ expect(partialWriteScenario.currentHandling).toBe('Transactions mentioned');
732
+ });
733
+ // --- Coverage for data-consistency: stale data with invalidation/ttl mentioned ---
734
+ it('should report "Some cache strategy mentioned" when content mentions invalidation/ttl', async () => {
735
+ mockGetSpec.mockResolvedValue({
736
+ ...baseSpec,
737
+ target: 'backend',
738
+ huPath: '/test/hu.md',
739
+ });
740
+ mockGetKnowledge.mockResolvedValue(baseKnowledge);
741
+ mockReadFile.mockImplementation(((path) => {
742
+ if (path === '/test/hu.md') {
743
+ return Promise.resolve('cache invalidation with ttl websocket real-time concurrent updates');
744
+ }
745
+ return Promise.reject(new Error('not found'));
746
+ }));
747
+ const result = await handleChallengeSpec({
748
+ specId: 'SPEC-001',
749
+ projectId: 'proj-1',
750
+ focus: ['data-consistency'],
751
+ });
752
+ const data = JSON.parse(result.content[1].text);
753
+ const staleScenario = data.failureScenarios.find((s) => s.scenario.includes('Stale data'));
754
+ expect(staleScenario).toBeDefined();
755
+ expect(staleScenario.currentHandling).toBe('Some cache strategy mentioned');
756
+ });
757
+ // --- Coverage for contentMentions true branch on line 423 (data-consistency: idempotent/debounce) ---
758
+ it('should report "Some prevention mentioned" for duplicates when content mentions idempotency/debounce', async () => {
759
+ mockGetSpec.mockResolvedValue({
760
+ ...baseSpec,
761
+ target: 'backend',
762
+ huPath: '/test/hu.md',
763
+ });
764
+ mockGetKnowledge.mockResolvedValue(baseKnowledge);
765
+ mockReadFile.mockImplementation(((path) => {
766
+ if (path === '/test/hu.md') {
767
+ return Promise.resolve('idempotent operations with debounce and disable lock on submit');
768
+ }
769
+ return Promise.reject(new Error('not found'));
770
+ }));
771
+ const result = await handleChallengeSpec({
772
+ specId: 'SPEC-001',
773
+ projectId: 'proj-1',
774
+ focus: ['data-consistency'],
775
+ });
776
+ const data = JSON.parse(result.content[1].text);
777
+ const duplicateScenario = data.failureScenarios.find((s) => s.scenario.includes('double-clicks'));
778
+ expect(duplicateScenario).toBeDefined();
779
+ expect(duplicateScenario.currentHandling).toBe('Some prevention mentioned');
780
+ });
781
+ });
782
+ //# sourceMappingURL=challenge-spec.test.js.map