@codeyam/codeyam-cli 0.1.8 → 0.1.10

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 (343) hide show
  1. package/analyzer-template/.build-info.json +8 -8
  2. package/analyzer-template/log.txt +3 -3
  3. package/analyzer-template/package.json +4 -4
  4. package/analyzer-template/packages/ai/src/lib/generateExecutionFlows.ts +0 -33
  5. package/analyzer-template/packages/analyze/src/lib/ProjectAnalyzer.ts +13 -7
  6. package/analyzer-template/packages/analyze/src/lib/asts/index.ts +7 -2
  7. package/analyzer-template/packages/analyze/src/lib/files/scenarios/generateExecutionFlows.ts +0 -98
  8. package/analyzer-template/packages/aws/package.json +1 -1
  9. package/analyzer-template/packages/database/src/lib/kysely/tables/editorScenariosTable.ts +76 -0
  10. package/analyzer-template/packages/database/src/lib/loadEntities.ts +0 -6
  11. package/analyzer-template/packages/database/src/lib/updateCommitMetadata.ts +0 -65
  12. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/editorScenariosTable.d.ts +7 -0
  13. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/editorScenariosTable.d.ts.map +1 -1
  14. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/editorScenariosTable.js +76 -0
  15. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/editorScenariosTable.js.map +1 -1
  16. package/analyzer-template/packages/github/dist/database/src/lib/loadEntities.d.ts.map +1 -1
  17. package/analyzer-template/packages/github/dist/database/src/lib/loadEntities.js +0 -6
  18. package/analyzer-template/packages/github/dist/database/src/lib/loadEntities.js.map +1 -1
  19. package/analyzer-template/packages/github/dist/database/src/lib/updateCommitMetadata.d.ts.map +1 -1
  20. package/analyzer-template/packages/github/dist/database/src/lib/updateCommitMetadata.js +0 -25
  21. package/analyzer-template/packages/github/dist/database/src/lib/updateCommitMetadata.js.map +1 -1
  22. package/analyzer-template/packages/github/dist/types/src/enums/ProjectFramework.d.ts +2 -0
  23. package/analyzer-template/packages/github/dist/types/src/enums/ProjectFramework.d.ts.map +1 -1
  24. package/analyzer-template/packages/github/dist/types/src/enums/ProjectFramework.js +2 -0
  25. package/analyzer-template/packages/github/dist/types/src/enums/ProjectFramework.js.map +1 -1
  26. package/analyzer-template/packages/types/src/enums/ProjectFramework.ts +2 -0
  27. package/analyzer-template/packages/ui-components/package.json +1 -1
  28. package/analyzer-template/packages/utils/dist/types/src/enums/ProjectFramework.d.ts +2 -0
  29. package/analyzer-template/packages/utils/dist/types/src/enums/ProjectFramework.d.ts.map +1 -1
  30. package/analyzer-template/packages/utils/dist/types/src/enums/ProjectFramework.js +2 -0
  31. package/analyzer-template/packages/utils/dist/types/src/enums/ProjectFramework.js.map +1 -1
  32. package/codeyam-cli/src/__tests__/memory-scripts/filter-session.test.js +196 -0
  33. package/codeyam-cli/src/__tests__/memory-scripts/filter-session.test.js.map +1 -0
  34. package/codeyam-cli/src/__tests__/memory-scripts/read-json-field.test.js +114 -0
  35. package/codeyam-cli/src/__tests__/memory-scripts/read-json-field.test.js.map +1 -0
  36. package/codeyam-cli/src/__tests__/memory-scripts/ripgrep-fallback.test.js +149 -0
  37. package/codeyam-cli/src/__tests__/memory-scripts/ripgrep-fallback.test.js.map +1 -0
  38. package/codeyam-cli/src/commands/__tests__/editor.stepDispatch.test.js +45 -0
  39. package/codeyam-cli/src/commands/__tests__/editor.stepDispatch.test.js.map +1 -0
  40. package/codeyam-cli/src/commands/__tests__/init.gitignore.test.js +101 -47
  41. package/codeyam-cli/src/commands/__tests__/init.gitignore.test.js.map +1 -1
  42. package/codeyam-cli/src/commands/default.js +3 -46
  43. package/codeyam-cli/src/commands/default.js.map +1 -1
  44. package/codeyam-cli/src/commands/editor.js +1793 -257
  45. package/codeyam-cli/src/commands/editor.js.map +1 -1
  46. package/codeyam-cli/src/commands/init.js +67 -34
  47. package/codeyam-cli/src/commands/init.js.map +1 -1
  48. package/codeyam-cli/src/data/techStacks.js +77 -0
  49. package/codeyam-cli/src/data/techStacks.js.map +1 -0
  50. package/codeyam-cli/src/utils/__tests__/analyzerFinalization.test.js +173 -0
  51. package/codeyam-cli/src/utils/__tests__/analyzerFinalization.test.js.map +1 -0
  52. package/codeyam-cli/src/utils/__tests__/backgroundServer.test.js +46 -0
  53. package/codeyam-cli/src/utils/__tests__/backgroundServer.test.js.map +1 -0
  54. package/codeyam-cli/src/utils/__tests__/devServerState.test.js +134 -0
  55. package/codeyam-cli/src/utils/__tests__/devServerState.test.js.map +1 -0
  56. package/codeyam-cli/src/utils/__tests__/editorApi.test.js +137 -0
  57. package/codeyam-cli/src/utils/__tests__/editorApi.test.js.map +1 -0
  58. package/codeyam-cli/src/utils/__tests__/editorAudit.test.js +742 -1
  59. package/codeyam-cli/src/utils/__tests__/editorAudit.test.js.map +1 -1
  60. package/codeyam-cli/src/utils/__tests__/editorCapture.test.js +93 -0
  61. package/codeyam-cli/src/utils/__tests__/editorCapture.test.js.map +1 -0
  62. package/codeyam-cli/src/utils/__tests__/editorDevServer.test.js +181 -3
  63. package/codeyam-cli/src/utils/__tests__/editorDevServer.test.js.map +1 -1
  64. package/codeyam-cli/src/utils/__tests__/editorEntityChangeStatus.test.js +121 -0
  65. package/codeyam-cli/src/utils/__tests__/editorEntityChangeStatus.test.js.map +1 -0
  66. package/codeyam-cli/src/utils/__tests__/editorImageVerifier.test.js +294 -0
  67. package/codeyam-cli/src/utils/__tests__/editorImageVerifier.test.js.map +1 -0
  68. package/codeyam-cli/src/utils/__tests__/editorJournal.test.js +249 -2
  69. package/codeyam-cli/src/utils/__tests__/editorJournal.test.js.map +1 -1
  70. package/codeyam-cli/src/utils/__tests__/editorLoaderHelpers.test.js +520 -0
  71. package/codeyam-cli/src/utils/__tests__/editorLoaderHelpers.test.js.map +1 -0
  72. package/codeyam-cli/src/utils/__tests__/editorPreloadHelpers.test.js +118 -1
  73. package/codeyam-cli/src/utils/__tests__/editorPreloadHelpers.test.js.map +1 -1
  74. package/codeyam-cli/src/utils/__tests__/editorPreview.test.js +209 -3
  75. package/codeyam-cli/src/utils/__tests__/editorPreview.test.js.map +1 -1
  76. package/codeyam-cli/src/utils/__tests__/editorProxySession.test.js +153 -0
  77. package/codeyam-cli/src/utils/__tests__/editorProxySession.test.js.map +1 -0
  78. package/codeyam-cli/src/utils/__tests__/editorScenarioLookup.test.js +139 -0
  79. package/codeyam-cli/src/utils/__tests__/editorScenarioLookup.test.js.map +1 -0
  80. package/codeyam-cli/src/utils/__tests__/editorScenarioSwitch.test.js +221 -0
  81. package/codeyam-cli/src/utils/__tests__/editorScenarioSwitch.test.js.map +1 -0
  82. package/codeyam-cli/src/utils/__tests__/editorScenarios.test.js +985 -2
  83. package/codeyam-cli/src/utils/__tests__/editorScenarios.test.js.map +1 -1
  84. package/codeyam-cli/src/utils/__tests__/editorSeedAdapter.test.js +213 -0
  85. package/codeyam-cli/src/utils/__tests__/editorSeedAdapter.test.js.map +1 -0
  86. package/codeyam-cli/src/utils/__tests__/entityChangeStatus.test.js +1742 -0
  87. package/codeyam-cli/src/utils/__tests__/entityChangeStatus.test.js.map +1 -0
  88. package/codeyam-cli/src/utils/__tests__/journalCaptureStabilization.test.js +107 -0
  89. package/codeyam-cli/src/utils/__tests__/journalCaptureStabilization.test.js.map +1 -0
  90. package/codeyam-cli/src/utils/__tests__/parseRegisterArg.test.js +129 -0
  91. package/codeyam-cli/src/utils/__tests__/parseRegisterArg.test.js.map +1 -0
  92. package/codeyam-cli/src/utils/__tests__/scenarioCoverage.test.js +227 -0
  93. package/codeyam-cli/src/utils/__tests__/scenarioCoverage.test.js.map +1 -0
  94. package/codeyam-cli/src/utils/__tests__/scenariosManifest.test.js +454 -0
  95. package/codeyam-cli/src/utils/__tests__/scenariosManifest.test.js.map +1 -0
  96. package/codeyam-cli/src/utils/__tests__/setupClaudeCodeSettings.test.js +25 -5
  97. package/codeyam-cli/src/utils/__tests__/setupClaudeCodeSettings.test.js.map +1 -1
  98. package/codeyam-cli/src/utils/__tests__/templateConsistency.test.js +51 -0
  99. package/codeyam-cli/src/utils/__tests__/templateConsistency.test.js.map +1 -0
  100. package/codeyam-cli/src/utils/__tests__/webappDetection.test.js +142 -0
  101. package/codeyam-cli/src/utils/__tests__/webappDetection.test.js.map +1 -0
  102. package/codeyam-cli/src/utils/analyzer.js +9 -0
  103. package/codeyam-cli/src/utils/analyzer.js.map +1 -1
  104. package/codeyam-cli/src/utils/analyzerFinalization.js +100 -0
  105. package/codeyam-cli/src/utils/analyzerFinalization.js.map +1 -0
  106. package/codeyam-cli/src/utils/backgroundServer.js +94 -18
  107. package/codeyam-cli/src/utils/backgroundServer.js.map +1 -1
  108. package/codeyam-cli/src/utils/database.js +37 -2
  109. package/codeyam-cli/src/utils/database.js.map +1 -1
  110. package/codeyam-cli/src/utils/devServerState.js +71 -0
  111. package/codeyam-cli/src/utils/devServerState.js.map +1 -0
  112. package/codeyam-cli/src/utils/editorApi.js +79 -0
  113. package/codeyam-cli/src/utils/editorApi.js.map +1 -0
  114. package/codeyam-cli/src/utils/editorAudit.js +135 -7
  115. package/codeyam-cli/src/utils/editorAudit.js.map +1 -1
  116. package/codeyam-cli/src/utils/editorCapture.js +102 -0
  117. package/codeyam-cli/src/utils/editorCapture.js.map +1 -0
  118. package/codeyam-cli/src/utils/editorDevServer.js +100 -1
  119. package/codeyam-cli/src/utils/editorDevServer.js.map +1 -1
  120. package/codeyam-cli/src/utils/editorEntityChangeStatus.js +44 -0
  121. package/codeyam-cli/src/utils/editorEntityChangeStatus.js.map +1 -0
  122. package/codeyam-cli/src/utils/editorImageVerifier.js +155 -0
  123. package/codeyam-cli/src/utils/editorImageVerifier.js.map +1 -0
  124. package/codeyam-cli/src/utils/editorJournal.js +92 -4
  125. package/codeyam-cli/src/utils/editorJournal.js.map +1 -1
  126. package/codeyam-cli/src/utils/editorLoaderHelpers.js +113 -0
  127. package/codeyam-cli/src/utils/editorLoaderHelpers.js.map +1 -0
  128. package/codeyam-cli/src/utils/editorMockState.js +1 -1
  129. package/codeyam-cli/src/utils/editorPreloadHelpers.js +72 -1
  130. package/codeyam-cli/src/utils/editorPreloadHelpers.js.map +1 -1
  131. package/codeyam-cli/src/utils/editorPreview.js +72 -1
  132. package/codeyam-cli/src/utils/editorPreview.js.map +1 -1
  133. package/codeyam-cli/src/utils/editorScenarioSwitch.js +112 -0
  134. package/codeyam-cli/src/utils/editorScenarioSwitch.js.map +1 -0
  135. package/codeyam-cli/src/utils/editorScenarios.js +331 -0
  136. package/codeyam-cli/src/utils/editorScenarios.js.map +1 -1
  137. package/codeyam-cli/src/utils/editorSeedAdapter.js +173 -0
  138. package/codeyam-cli/src/utils/editorSeedAdapter.js.map +1 -0
  139. package/codeyam-cli/src/utils/entityChangeStatus.js +349 -0
  140. package/codeyam-cli/src/utils/entityChangeStatus.js.map +1 -0
  141. package/codeyam-cli/src/utils/entityChangeStatus.server.js +158 -0
  142. package/codeyam-cli/src/utils/entityChangeStatus.server.js.map +1 -0
  143. package/codeyam-cli/src/utils/install-skills.js +1 -1
  144. package/codeyam-cli/src/utils/install-skills.js.map +1 -1
  145. package/codeyam-cli/src/utils/parseRegisterArg.js +31 -0
  146. package/codeyam-cli/src/utils/parseRegisterArg.js.map +1 -0
  147. package/codeyam-cli/src/utils/progress.js +2 -2
  148. package/codeyam-cli/src/utils/progress.js.map +1 -1
  149. package/codeyam-cli/src/utils/scenarioCoverage.js +75 -0
  150. package/codeyam-cli/src/utils/scenarioCoverage.js.map +1 -0
  151. package/codeyam-cli/src/utils/scenariosManifest.js +241 -0
  152. package/codeyam-cli/src/utils/scenariosManifest.js.map +1 -0
  153. package/codeyam-cli/src/utils/serverState.js +30 -0
  154. package/codeyam-cli/src/utils/serverState.js.map +1 -1
  155. package/codeyam-cli/src/utils/setupClaudeCodeSettings.js +46 -16
  156. package/codeyam-cli/src/utils/setupClaudeCodeSettings.js.map +1 -1
  157. package/codeyam-cli/src/utils/simulationGateMiddleware.js +8 -1
  158. package/codeyam-cli/src/utils/simulationGateMiddleware.js.map +1 -1
  159. package/codeyam-cli/src/utils/slugUtils.js +25 -0
  160. package/codeyam-cli/src/utils/slugUtils.js.map +1 -0
  161. package/codeyam-cli/src/utils/syncMocksMiddleware.js +2 -2
  162. package/codeyam-cli/src/utils/syncMocksMiddleware.js.map +1 -1
  163. package/codeyam-cli/src/utils/webappDetection.js +21 -0
  164. package/codeyam-cli/src/utils/webappDetection.js.map +1 -1
  165. package/codeyam-cli/src/webserver/__tests__/clientErrors.test.js +40 -0
  166. package/codeyam-cli/src/webserver/__tests__/clientErrors.test.js.map +1 -0
  167. package/codeyam-cli/src/webserver/__tests__/editorProxy.test.js +567 -0
  168. package/codeyam-cli/src/webserver/__tests__/editorProxy.test.js.map +1 -0
  169. package/codeyam-cli/src/webserver/__tests__/idleDetector.test.js +146 -0
  170. package/codeyam-cli/src/webserver/__tests__/idleDetector.test.js.map +1 -0
  171. package/codeyam-cli/src/webserver/app/lib/clientErrors.js +65 -0
  172. package/codeyam-cli/src/webserver/app/lib/clientErrors.js.map +1 -0
  173. package/codeyam-cli/src/webserver/app/lib/git.js +397 -0
  174. package/codeyam-cli/src/webserver/app/lib/git.js.map +1 -0
  175. package/codeyam-cli/src/webserver/build/client/assets/{CopyButton-DmJveP3T.js → CopyButton-BPXZwM4t.js} +1 -1
  176. package/codeyam-cli/src/webserver/build/client/assets/{EntityItem-C76mRRiF.js → EntityItem-BcgbViKV.js} +3 -3
  177. package/codeyam-cli/src/webserver/build/client/assets/{EntityTypeIcon-CobE682z.js → EntityTypeIcon-CQIG2qda.js} +9 -9
  178. package/codeyam-cli/src/webserver/build/client/assets/{ReportIssueModal-djPLI-WV.js → ReportIssueModal-BzHcG7SE.js} +3 -3
  179. package/codeyam-cli/src/webserver/build/client/assets/{ScenarioViewer-B76aig_2.js → ScenarioViewer-TSD3C211.js} +3 -3
  180. package/codeyam-cli/src/webserver/build/client/assets/ViewportInspectBar-oAf2Kqsf.js +1 -0
  181. package/codeyam-cli/src/webserver/build/client/assets/{_index-C96V0n15.js → _index-DLxKhri3.js} +3 -3
  182. package/codeyam-cli/src/webserver/build/client/assets/{activity.(_tab)-BpKzcsJz.js → activity.(_tab)-BcY3q6nt.js} +6 -6
  183. package/codeyam-cli/src/webserver/build/client/assets/addon-canvas-DpzMmAy5.js +1 -0
  184. package/codeyam-cli/src/webserver/build/client/assets/addon-fit-YJmn1quW.js +12 -0
  185. package/codeyam-cli/src/webserver/build/client/assets/addon-webgl-DI8QOUvO.js +58 -0
  186. package/codeyam-cli/src/webserver/build/client/assets/{agent-transcripts-D9hemwl6.js → agent-transcripts-Bni3iiUj.js} +5 -5
  187. package/codeyam-cli/src/webserver/build/client/assets/api.editor-file-diff-l0sNRNKZ.js +1 -0
  188. package/codeyam-cli/src/webserver/build/client/assets/api.editor-file-l0sNRNKZ.js +1 -0
  189. package/codeyam-cli/src/webserver/build/client/assets/api.editor-project-info-l0sNRNKZ.js +1 -0
  190. package/codeyam-cli/src/webserver/build/client/assets/api.editor-scenario-coverage-l0sNRNKZ.js +1 -0
  191. package/codeyam-cli/src/webserver/build/client/assets/{book-open-D_nMCFmP.js → book-open-BYOypzCa.js} +2 -2
  192. package/codeyam-cli/src/webserver/build/client/assets/{chevron-down-BH2h1Ea2.js → chevron-down-C_Pmso5S.js} +2 -2
  193. package/codeyam-cli/src/webserver/build/client/assets/{circle-check-DyIKORY6.js → circle-check-BVMi9VA5.js} +2 -2
  194. package/codeyam-cli/src/webserver/build/client/assets/{copy-NDbZjXao.js → copy-n2FB0_Sw.js} +3 -3
  195. package/codeyam-cli/src/webserver/build/client/assets/createLucideIcon-CC6AbExI.js +41 -0
  196. package/codeyam-cli/src/webserver/build/client/assets/dev.empty-Ii3inc0_.js +1 -0
  197. package/codeyam-cli/src/webserver/build/client/assets/editor-COWCNVyV.js +10 -0
  198. package/codeyam-cli/src/webserver/build/client/assets/editorPreview-CNB06EIa.js +41 -0
  199. package/codeyam-cli/src/webserver/build/client/assets/{entity._sha._-CrjR3zZW.js → entity._sha._-DwCV5__E.js} +3 -3
  200. package/codeyam-cli/src/webserver/build/client/assets/entity._sha.scenarios._scenarioId.dev-CXSi2aeZ.js +6 -0
  201. package/codeyam-cli/src/webserver/build/client/assets/entity._sha.scenarios._scenarioId.fullscreen-CHMiAog3.js +6 -0
  202. package/codeyam-cli/src/webserver/build/client/assets/{files-DO4CZ16O.js → files-BZrlFE1F.js} +1 -1
  203. package/codeyam-cli/src/webserver/build/client/assets/git-DdZcvjGh.js +1 -0
  204. package/codeyam-cli/src/webserver/build/client/assets/globals-phvmGvat.css +1 -0
  205. package/codeyam-cli/src/webserver/build/client/assets/index-yHOVb4rc.js +15 -0
  206. package/codeyam-cli/src/webserver/build/client/assets/{loader-circle-BAXYRVEO.js → loader-circle-DaAZ_H2w.js} +2 -2
  207. package/codeyam-cli/src/webserver/build/client/assets/manifest-6134dc40.js +1 -0
  208. package/codeyam-cli/src/webserver/build/client/assets/memory-9gnxSZlb.js +101 -0
  209. package/codeyam-cli/src/webserver/build/client/assets/{pause-DTAcYxBt.js → pause-f5-1lKBt.js} +3 -3
  210. package/codeyam-cli/src/webserver/build/client/assets/root-BWAyuj0r.js +67 -0
  211. package/codeyam-cli/src/webserver/build/client/assets/{search-fKo7v0Zo.js → search-Di64LWVb.js} +2 -2
  212. package/codeyam-cli/src/webserver/build/client/assets/{settings-DfuTtcJP.js → settings-0OrEMU6J.js} +1 -1
  213. package/codeyam-cli/src/webserver/build/client/assets/{simulations-B3aOzpCZ.js → simulations-DWT-CvLy.js} +1 -1
  214. package/codeyam-cli/src/webserver/build/client/assets/{terminal-BG4heKCG.js → terminal-Br7MOqts.js} +3 -3
  215. package/codeyam-cli/src/webserver/build/client/assets/{triangle-alert-DtSmdtM4.js → triangle-alert-BLdiCuG-.js} +2 -2
  216. package/codeyam-cli/src/webserver/build/client/assets/useCustomSizes-C-_hOl_g.js +1 -0
  217. package/codeyam-cli/src/webserver/build/client/sound-test.html +98 -0
  218. package/codeyam-cli/src/webserver/build/server/assets/index-ChX0hPcu.js +1 -0
  219. package/codeyam-cli/src/webserver/build/server/assets/init-kSNsMjj8.js +10 -0
  220. package/codeyam-cli/src/webserver/build/server/assets/server-build-Bm2xIhmh.js +439 -0
  221. package/codeyam-cli/src/webserver/build/server/index.js +1 -1
  222. package/codeyam-cli/src/webserver/build-info.json +5 -5
  223. package/codeyam-cli/src/webserver/editorProxy.js +487 -50
  224. package/codeyam-cli/src/webserver/editorProxy.js.map +1 -1
  225. package/codeyam-cli/src/webserver/idleDetector.js +73 -0
  226. package/codeyam-cli/src/webserver/idleDetector.js.map +1 -0
  227. package/codeyam-cli/src/webserver/public/sound-test.html +98 -0
  228. package/codeyam-cli/src/webserver/scripts/codeyam-preload.mjs +242 -3
  229. package/codeyam-cli/src/webserver/scripts/journalCapture.ts +94 -4
  230. package/codeyam-cli/src/webserver/server.js +90 -16
  231. package/codeyam-cli/src/webserver/server.js.map +1 -1
  232. package/codeyam-cli/src/webserver/terminalServer.js +71 -34
  233. package/codeyam-cli/src/webserver/terminalServer.js.map +1 -1
  234. package/codeyam-cli/templates/chrome-extension-react/EXTENSION_SETUP.md +75 -0
  235. package/codeyam-cli/templates/chrome-extension-react/README.md +46 -0
  236. package/codeyam-cli/templates/chrome-extension-react/gitignore +15 -0
  237. package/codeyam-cli/templates/chrome-extension-react/index.html +12 -0
  238. package/codeyam-cli/templates/chrome-extension-react/package.json +27 -0
  239. package/codeyam-cli/templates/chrome-extension-react/popup.html +12 -0
  240. package/codeyam-cli/templates/chrome-extension-react/public/manifest.json +15 -0
  241. package/codeyam-cli/templates/chrome-extension-react/src/background/service-worker.ts +7 -0
  242. package/codeyam-cli/templates/chrome-extension-react/src/globals.css +6 -0
  243. package/codeyam-cli/templates/chrome-extension-react/src/lib/storage.ts +37 -0
  244. package/codeyam-cli/templates/chrome-extension-react/src/popup/App.tsx +12 -0
  245. package/codeyam-cli/templates/chrome-extension-react/src/popup/main.tsx +10 -0
  246. package/codeyam-cli/templates/chrome-extension-react/tsconfig.json +24 -0
  247. package/codeyam-cli/templates/chrome-extension-react/vite.config.ts +41 -0
  248. package/codeyam-cli/templates/codeyam-editor-claude.md +84 -5
  249. package/codeyam-cli/templates/editor-step-hook.py +98 -8
  250. package/codeyam-cli/templates/expo-react-native/MOBILE_SETUP.md +89 -0
  251. package/codeyam-cli/templates/expo-react-native/README.md +41 -0
  252. package/codeyam-cli/templates/expo-react-native/app/(tabs)/_layout.tsx +33 -0
  253. package/codeyam-cli/templates/expo-react-native/app/(tabs)/index.tsx +12 -0
  254. package/codeyam-cli/templates/expo-react-native/app/(tabs)/settings.tsx +12 -0
  255. package/codeyam-cli/templates/expo-react-native/app/_layout.tsx +12 -0
  256. package/codeyam-cli/templates/expo-react-native/app.json +18 -0
  257. package/codeyam-cli/templates/expo-react-native/babel.config.js +9 -0
  258. package/codeyam-cli/templates/expo-react-native/gitignore +12 -0
  259. package/codeyam-cli/templates/expo-react-native/global.css +3 -0
  260. package/codeyam-cli/templates/expo-react-native/lib/storage.ts +32 -0
  261. package/codeyam-cli/templates/expo-react-native/metro.config.js +6 -0
  262. package/codeyam-cli/templates/expo-react-native/nativewind-env.d.ts +1 -0
  263. package/codeyam-cli/templates/expo-react-native/package.json +38 -0
  264. package/codeyam-cli/templates/expo-react-native/tailwind.config.js +10 -0
  265. package/codeyam-cli/templates/expo-react-native/tsconfig.json +10 -0
  266. package/codeyam-cli/templates/nextjs-prisma-sqlite/AUTH_PATTERNS.md +308 -0
  267. package/codeyam-cli/templates/nextjs-prisma-sqlite/AUTH_UPGRADE.md +304 -0
  268. package/codeyam-cli/templates/nextjs-prisma-sqlite/DATABASE.md +126 -0
  269. package/codeyam-cli/templates/nextjs-prisma-sqlite/FEATURE_PATTERNS.md +37 -0
  270. package/codeyam-cli/templates/nextjs-prisma-sqlite/README.md +53 -0
  271. package/codeyam-cli/templates/nextjs-prisma-sqlite/app/codeyam-isolate/layout.tsx +12 -0
  272. package/codeyam-cli/templates/nextjs-prisma-sqlite/app/lib/prisma.ts +9 -4
  273. package/codeyam-cli/templates/nextjs-prisma-sqlite/env +4 -0
  274. package/codeyam-cli/templates/nextjs-prisma-sqlite/gitignore +21 -0
  275. package/codeyam-cli/templates/nextjs-prisma-sqlite/package.json +5 -1
  276. package/codeyam-cli/templates/nextjs-prisma-sqlite/prisma/seed.ts +4 -1
  277. package/codeyam-cli/templates/nextjs-prisma-sqlite/seed-adapter.ts +92 -0
  278. package/codeyam-cli/templates/nextjs-prisma-sqlite/vitest.config.ts +13 -0
  279. package/codeyam-cli/templates/nextjs-prisma-supabase/README.md +52 -0
  280. package/codeyam-cli/templates/{nextjs-prisma-sqlite/PRISMA_SETUP.md → nextjs-prisma-supabase/SUPABASE_SETUP.md} +37 -17
  281. package/codeyam-cli/templates/nextjs-prisma-supabase/app/api/todos/route.ts +17 -0
  282. package/codeyam-cli/templates/nextjs-prisma-supabase/app/globals.css +26 -0
  283. package/codeyam-cli/templates/nextjs-prisma-supabase/app/layout.tsx +34 -0
  284. package/codeyam-cli/templates/nextjs-prisma-supabase/app/lib/prisma.ts +20 -0
  285. package/codeyam-cli/templates/nextjs-prisma-supabase/app/lib/supabase.ts +12 -0
  286. package/codeyam-cli/templates/nextjs-prisma-supabase/app/page.tsx +10 -0
  287. package/codeyam-cli/templates/nextjs-prisma-supabase/env +9 -0
  288. package/codeyam-cli/templates/nextjs-prisma-supabase/eslint.config.mjs +11 -0
  289. package/codeyam-cli/templates/nextjs-prisma-supabase/gitignore +40 -0
  290. package/codeyam-cli/templates/nextjs-prisma-supabase/next.config.ts +11 -0
  291. package/codeyam-cli/templates/nextjs-prisma-supabase/package.json +37 -0
  292. package/codeyam-cli/templates/nextjs-prisma-supabase/postcss.config.mjs +7 -0
  293. package/codeyam-cli/templates/nextjs-prisma-supabase/prisma/schema.prisma +27 -0
  294. package/codeyam-cli/templates/nextjs-prisma-supabase/prisma/seed.ts +39 -0
  295. package/codeyam-cli/templates/nextjs-prisma-supabase/prisma.config.ts +12 -0
  296. package/codeyam-cli/templates/nextjs-prisma-supabase/tsconfig.json +34 -0
  297. package/codeyam-cli/templates/skills/codeyam-dev-mode/SKILL.md +2 -2
  298. package/codeyam-cli/templates/skills/codeyam-editor/SKILL.md +97 -17
  299. package/codeyam-cli/templates/skills/codeyam-memory/SKILL.md +10 -10
  300. package/codeyam-cli/templates/skills/codeyam-memory/scripts/holistic-analysis/detect-deprecated-patterns.mjs +139 -0
  301. package/codeyam-cli/templates/skills/codeyam-memory/scripts/holistic-analysis/find-exports.mjs +52 -0
  302. package/codeyam-cli/templates/skills/codeyam-memory/scripts/lib/read-json-field.mjs +61 -0
  303. package/codeyam-cli/templates/skills/codeyam-memory/scripts/lib/ripgrep-fallback.mjs +155 -0
  304. package/codeyam-cli/templates/skills/codeyam-memory/scripts/session-mining/cleanup.mjs +13 -0
  305. package/codeyam-cli/templates/skills/codeyam-memory/scripts/session-mining/filter-session.mjs +95 -0
  306. package/codeyam-cli/templates/skills/codeyam-memory/scripts/session-mining/preprocess.mjs +160 -0
  307. package/package.json +14 -9
  308. package/packages/ai/src/lib/generateExecutionFlows.js +0 -11
  309. package/packages/ai/src/lib/generateExecutionFlows.js.map +1 -1
  310. package/packages/analyze/src/lib/ProjectAnalyzer.js +10 -4
  311. package/packages/analyze/src/lib/ProjectAnalyzer.js.map +1 -1
  312. package/packages/analyze/src/lib/asts/index.js +4 -2
  313. package/packages/analyze/src/lib/asts/index.js.map +1 -1
  314. package/packages/analyze/src/lib/files/scenarios/generateExecutionFlows.js +0 -40
  315. package/packages/analyze/src/lib/files/scenarios/generateExecutionFlows.js.map +1 -1
  316. package/packages/database/src/lib/kysely/tables/editorScenariosTable.js +76 -0
  317. package/packages/database/src/lib/kysely/tables/editorScenariosTable.js.map +1 -1
  318. package/packages/database/src/lib/loadEntities.js +0 -6
  319. package/packages/database/src/lib/loadEntities.js.map +1 -1
  320. package/packages/database/src/lib/updateCommitMetadata.js +0 -25
  321. package/packages/database/src/lib/updateCommitMetadata.js.map +1 -1
  322. package/packages/types/src/enums/ProjectFramework.js +2 -0
  323. package/packages/types/src/enums/ProjectFramework.js.map +1 -1
  324. package/codeyam-cli/src/webserver/build/client/assets/Terminal-Dnj5CY9R.js +0 -41
  325. package/codeyam-cli/src/webserver/build/client/assets/addon-fit-CUXOrorO.js +0 -1
  326. package/codeyam-cli/src/webserver/build/client/assets/createLucideIcon-CMT1jU2q.js +0 -21
  327. package/codeyam-cli/src/webserver/build/client/assets/dev.empty-BiM6z3Do.js +0 -1
  328. package/codeyam-cli/src/webserver/build/client/assets/editor-D1DAKXtT.js +0 -8
  329. package/codeyam-cli/src/webserver/build/client/assets/entity._sha.scenarios._scenarioId.dev-DkzqFzFj.js +0 -6
  330. package/codeyam-cli/src/webserver/build/client/assets/entity._sha.scenarios._scenarioId.fullscreen-C28BiQzt.js +0 -6
  331. package/codeyam-cli/src/webserver/build/client/assets/git-CFCTYk9I.js +0 -15
  332. package/codeyam-cli/src/webserver/build/client/assets/globals-B17TBSS6.css +0 -1
  333. package/codeyam-cli/src/webserver/build/client/assets/manifest-a632de18.js +0 -1
  334. package/codeyam-cli/src/webserver/build/client/assets/memory-Dg0mvYrI.js +0 -96
  335. package/codeyam-cli/src/webserver/build/client/assets/root-DUKqhFlb.js +0 -67
  336. package/codeyam-cli/src/webserver/build/client/assets/useCustomSizes-ByhSyh0W.js +0 -1
  337. package/codeyam-cli/src/webserver/build/server/assets/index-HfLydfDq.js +0 -1
  338. package/codeyam-cli/src/webserver/build/server/assets/server-build-CUu_F-oo.js +0 -366
  339. package/codeyam-cli/templates/skills/codeyam-memory/scripts/holistic-analysis/detect-deprecated-patterns.sh +0 -108
  340. package/codeyam-cli/templates/skills/codeyam-memory/scripts/holistic-analysis/find-exports.sh +0 -69
  341. package/codeyam-cli/templates/skills/codeyam-memory/scripts/session-mining/cleanup.sh +0 -12
  342. package/codeyam-cli/templates/skills/codeyam-memory/scripts/session-mining/filter.jq +0 -45
  343. package/codeyam-cli/templates/skills/codeyam-memory/scripts/session-mining/preprocess.sh +0 -139
@@ -1,4 +1,6 @@
1
- import { isComponent, classifyGlossaryEntries, computeAudit, } from "../editorAudit.js";
1
+ import Database from 'better-sqlite3';
2
+ import { Kysely, SqliteDialect } from 'kysely';
3
+ import { isComponent, classifyGlossaryEntries, computeAudit, filterGlossaryByChangeStatus, resolveAuditSessionScope, queryScenarioCounts, } from "../editorAudit.js";
2
4
  describe('editorAudit', () => {
3
5
  describe('isComponent', () => {
4
6
  it('should return true for JSX.Element return type', () => {
@@ -241,6 +243,745 @@ describe('editorAudit', () => {
241
243
  expect(result.summary.functionsMissing).toBe(1);
242
244
  expect(result.summary.allPassing).toBe(false);
243
245
  });
246
+ // ── Test results integration ────────────────────────────────────
247
+ it('should mark function as ok when tests pass and describe matches entity name', () => {
248
+ const result = computeAudit({
249
+ components: [],
250
+ functions: [
251
+ {
252
+ name: 'calculatePrice',
253
+ filePath: 'app/lib/pricing.ts',
254
+ testFile: 'app/lib/pricing.test.ts',
255
+ },
256
+ ],
257
+ scenarioCounts: {},
258
+ testFileExistence: { 'app/lib/pricing.test.ts': true },
259
+ testResults: {
260
+ 'app/lib/pricing.test.ts': {
261
+ passing: true,
262
+ hasEntityNameDescribe: true,
263
+ },
264
+ },
265
+ });
266
+ expect(result.functions[0].status).toBe('ok');
267
+ expect(result.functions[0].testsPassing).toBe(true);
268
+ expect(result.functions[0].testsVisibleInUi).toBe(true);
269
+ });
270
+ it('should mark function as failing when tests fail', () => {
271
+ const result = computeAudit({
272
+ components: [],
273
+ functions: [
274
+ {
275
+ name: 'calculatePrice',
276
+ filePath: 'app/lib/pricing.ts',
277
+ testFile: 'app/lib/pricing.test.ts',
278
+ },
279
+ ],
280
+ scenarioCounts: {},
281
+ testFileExistence: { 'app/lib/pricing.test.ts': true },
282
+ testResults: {
283
+ 'app/lib/pricing.test.ts': {
284
+ passing: false,
285
+ hasEntityNameDescribe: true,
286
+ },
287
+ },
288
+ });
289
+ expect(result.functions[0].status).toBe('failing');
290
+ expect(result.functions[0].testsPassing).toBe(false);
291
+ expect(result.functions[0].testsVisibleInUi).toBe(true);
292
+ });
293
+ it('should mark function as name_mismatch when tests pass but no describe matches', () => {
294
+ const result = computeAudit({
295
+ components: [],
296
+ functions: [
297
+ {
298
+ name: 'useDrinks',
299
+ filePath: 'app/hooks/useDrinks.ts',
300
+ testFile: 'app/hooks/useDrinks.test.ts',
301
+ },
302
+ ],
303
+ scenarioCounts: {},
304
+ testFileExistence: { 'app/hooks/useDrinks.test.ts': true },
305
+ testResults: {
306
+ 'app/hooks/useDrinks.test.ts': {
307
+ passing: true,
308
+ hasEntityNameDescribe: false,
309
+ },
310
+ },
311
+ });
312
+ expect(result.functions[0].status).toBe('name_mismatch');
313
+ expect(result.functions[0].testsPassing).toBe(true);
314
+ expect(result.functions[0].testsVisibleInUi).toBe(false);
315
+ });
316
+ it('should still mark function as missing when test file does not exist even with testResults', () => {
317
+ const result = computeAudit({
318
+ components: [],
319
+ functions: [
320
+ {
321
+ name: 'calculatePrice',
322
+ filePath: 'app/lib/pricing.ts',
323
+ testFile: 'app/lib/pricing.test.ts',
324
+ },
325
+ ],
326
+ scenarioCounts: {},
327
+ testFileExistence: { 'app/lib/pricing.test.ts': false },
328
+ testResults: {},
329
+ });
330
+ expect(result.functions[0].status).toBe('missing');
331
+ expect(result.functions[0].testsPassing).toBeUndefined();
332
+ expect(result.functions[0].testsVisibleInUi).toBeUndefined();
333
+ });
334
+ it('should include functionsFailing and functionsNameMismatch in summary', () => {
335
+ const result = computeAudit({
336
+ components: [],
337
+ functions: [
338
+ {
339
+ name: 'fnOk',
340
+ filePath: 'a.ts',
341
+ testFile: 'a.test.ts',
342
+ },
343
+ {
344
+ name: 'fnFailing',
345
+ filePath: 'b.ts',
346
+ testFile: 'b.test.ts',
347
+ },
348
+ {
349
+ name: 'fnMismatch',
350
+ filePath: 'c.ts',
351
+ testFile: 'c.test.ts',
352
+ },
353
+ {
354
+ name: 'fnMissing',
355
+ filePath: 'd.ts',
356
+ testFile: 'd.test.ts',
357
+ },
358
+ ],
359
+ scenarioCounts: {},
360
+ testFileExistence: {
361
+ 'a.test.ts': true,
362
+ 'b.test.ts': true,
363
+ 'c.test.ts': true,
364
+ 'd.test.ts': false,
365
+ },
366
+ testResults: {
367
+ 'a.test.ts': { passing: true, hasEntityNameDescribe: true },
368
+ 'b.test.ts': { passing: false, hasEntityNameDescribe: true },
369
+ 'c.test.ts': { passing: true, hasEntityNameDescribe: false },
370
+ },
371
+ });
372
+ expect(result.summary.functionsOk).toBe(1);
373
+ expect(result.summary.functionsFailing).toBe(1);
374
+ expect(result.summary.functionsNameMismatch).toBe(1);
375
+ expect(result.summary.functionsMissing).toBe(1);
376
+ expect(result.summary.allPassing).toBe(false);
377
+ });
378
+ it('should set allPassing to true only when all functions are ok', () => {
379
+ const result = computeAudit({
380
+ components: [
381
+ { name: 'DrinkCard', filePath: 'app/components/DrinkCard.tsx' },
382
+ ],
383
+ functions: [
384
+ {
385
+ name: 'calculatePrice',
386
+ filePath: 'app/lib/pricing.ts',
387
+ testFile: 'app/lib/pricing.test.ts',
388
+ },
389
+ ],
390
+ scenarioCounts: { DrinkCard: 1 },
391
+ testFileExistence: { 'app/lib/pricing.test.ts': true },
392
+ testResults: {
393
+ 'app/lib/pricing.test.ts': {
394
+ passing: true,
395
+ hasEntityNameDescribe: true,
396
+ },
397
+ },
398
+ });
399
+ expect(result.summary.allPassing).toBe(true);
400
+ });
401
+ it('should set allPassing to false when any function is failing', () => {
402
+ const result = computeAudit({
403
+ components: [],
404
+ functions: [
405
+ {
406
+ name: 'calculatePrice',
407
+ filePath: 'app/lib/pricing.ts',
408
+ testFile: 'app/lib/pricing.test.ts',
409
+ },
410
+ ],
411
+ scenarioCounts: {},
412
+ testFileExistence: { 'app/lib/pricing.test.ts': true },
413
+ testResults: {
414
+ 'app/lib/pricing.test.ts': {
415
+ passing: false,
416
+ hasEntityNameDescribe: true,
417
+ },
418
+ },
419
+ });
420
+ expect(result.summary.allPassing).toBe(false);
421
+ });
422
+ it('should set allPassing to false when any function has name_mismatch', () => {
423
+ const result = computeAudit({
424
+ components: [],
425
+ functions: [
426
+ {
427
+ name: 'useDrinks',
428
+ filePath: 'app/hooks/useDrinks.ts',
429
+ testFile: 'app/hooks/useDrinks.test.ts',
430
+ },
431
+ ],
432
+ scenarioCounts: {},
433
+ testFileExistence: { 'app/hooks/useDrinks.test.ts': true },
434
+ testResults: {
435
+ 'app/hooks/useDrinks.test.ts': {
436
+ passing: true,
437
+ hasEntityNameDescribe: false,
438
+ },
439
+ },
440
+ });
441
+ expect(result.summary.allPassing).toBe(false);
442
+ });
443
+ it('should fall back to file-existence-only behavior when testResults is not provided', () => {
444
+ // Backward compat: no testResults → existing behavior
445
+ const result = computeAudit({
446
+ components: [],
447
+ functions: [
448
+ {
449
+ name: 'calculatePrice',
450
+ filePath: 'app/lib/pricing.ts',
451
+ testFile: 'app/lib/pricing.test.ts',
452
+ },
453
+ ],
454
+ scenarioCounts: {},
455
+ testFileExistence: { 'app/lib/pricing.test.ts': true },
456
+ });
457
+ expect(result.functions[0].status).toBe('ok');
458
+ expect(result.functions[0].testsPassing).toBeUndefined();
459
+ expect(result.functions[0].testsVisibleInUi).toBeUndefined();
460
+ });
461
+ it('should fall back to file-existence-only when testResults is empty for a given file', () => {
462
+ const result = computeAudit({
463
+ components: [],
464
+ functions: [
465
+ {
466
+ name: 'calculatePrice',
467
+ filePath: 'app/lib/pricing.ts',
468
+ testFile: 'app/lib/pricing.test.ts',
469
+ },
470
+ ],
471
+ scenarioCounts: {},
472
+ testFileExistence: { 'app/lib/pricing.test.ts': true },
473
+ testResults: {},
474
+ });
475
+ // No test result for this file → fall back to existence check
476
+ expect(result.functions[0].status).toBe('ok');
477
+ expect(result.functions[0].testsPassing).toBeUndefined();
478
+ expect(result.functions[0].testsVisibleInUi).toBeUndefined();
479
+ });
480
+ // ── Client errors integration ─────────────────────────────────────
481
+ it('should mark component as has_errors when clientErrors reports errors', () => {
482
+ const result = computeAudit({
483
+ components: [
484
+ { name: 'DrinkInfo', filePath: 'app/components/DrinkInfo.tsx' },
485
+ ],
486
+ functions: [],
487
+ scenarioCounts: { DrinkInfo: 3 },
488
+ testFileExistence: {},
489
+ clientErrors: {
490
+ DrinkInfo: ['Cannot read properties of undefined'],
491
+ },
492
+ });
493
+ expect(result.components[0].status).toBe('has_errors');
494
+ expect(result.components[0].clientErrors).toEqual([
495
+ 'Cannot read properties of undefined',
496
+ ]);
497
+ expect(result.summary.componentsWithErrors).toBe(1);
498
+ expect(result.summary.allPassing).toBe(false);
499
+ });
500
+ it('should not count client errors for components with no scenarios', () => {
501
+ // If a component has no scenarios AND errors, it's still "missing"
502
+ // (errors come from scenarios, so if there are none, errors are stale)
503
+ const result = computeAudit({
504
+ components: [
505
+ { name: 'DrinkInfo', filePath: 'app/components/DrinkInfo.tsx' },
506
+ ],
507
+ functions: [],
508
+ scenarioCounts: {},
509
+ testFileExistence: {},
510
+ clientErrors: {
511
+ DrinkInfo: ['Cannot read properties of undefined'],
512
+ },
513
+ });
514
+ expect(result.components[0].status).toBe('missing');
515
+ });
516
+ it('should set allPassing false when any component has errors', () => {
517
+ const result = computeAudit({
518
+ components: [
519
+ { name: 'DrinkCard', filePath: 'app/components/DrinkCard.tsx' },
520
+ { name: 'DrinkInfo', filePath: 'app/components/DrinkInfo.tsx' },
521
+ ],
522
+ functions: [],
523
+ scenarioCounts: { DrinkCard: 2, DrinkInfo: 3 },
524
+ testFileExistence: {},
525
+ clientErrors: {
526
+ DrinkInfo: ['TypeError: something broke'],
527
+ },
528
+ });
529
+ expect(result.summary.allPassing).toBe(false);
530
+ expect(result.summary.componentsOk).toBe(1);
531
+ expect(result.summary.componentsWithErrors).toBe(1);
532
+ });
533
+ });
534
+ // ── filterGlossaryByChangeStatus ──────────────────────────────────
535
+ describe('filterGlossaryByChangeStatus', () => {
536
+ const allEntries = [
537
+ // Feature 1 components (unchanged)
538
+ {
539
+ name: 'StarRating',
540
+ filePath: 'app/components/StarRating.tsx',
541
+ returnType: 'JSX.Element',
542
+ },
543
+ {
544
+ name: 'CategoryBadge',
545
+ filePath: 'app/components/CategoryBadge.tsx',
546
+ returnType: 'JSX.Element',
547
+ },
548
+ {
549
+ name: 'DrinkCard',
550
+ filePath: 'app/components/DrinkCard.tsx',
551
+ returnType: 'JSX.Element',
552
+ },
553
+ // Feature 2 components (new)
554
+ {
555
+ name: 'HeroImage',
556
+ filePath: 'app/components/HeroImage.tsx',
557
+ returnType: 'JSX.Element',
558
+ },
559
+ {
560
+ name: 'ReviewCard',
561
+ filePath: 'app/components/ReviewCard.tsx',
562
+ returnType: 'JSX.Element',
563
+ },
564
+ // Feature 1 function (unchanged)
565
+ {
566
+ name: 'computeAvgRating',
567
+ filePath: 'app/lib/ratings.ts',
568
+ returnType: 'number',
569
+ testFile: 'app/lib/ratings.test.ts',
570
+ },
571
+ // Feature 2 function (new)
572
+ {
573
+ name: 'formatReviewCount',
574
+ filePath: 'app/lib/formatting.ts',
575
+ returnType: 'string',
576
+ testFile: 'app/lib/formatting.test.ts',
577
+ },
578
+ ];
579
+ it('should only include entries whose files are new, edited, or impacted', () => {
580
+ const entityChangeStatus = {
581
+ HeroImage: { status: 'new' },
582
+ ReviewCard: { status: 'new' },
583
+ formatReviewCount: { status: 'new' },
584
+ // DrinkCard edited because it now links to detail page
585
+ DrinkCard: { status: 'edited' },
586
+ // StarRating impacted because DrinkInfo uses it
587
+ StarRating: {
588
+ status: 'impacted',
589
+ impactedBy: [
590
+ {
591
+ name: 'DrinkInfo',
592
+ filePath: 'app/components/DrinkInfo.tsx',
593
+ changeType: 'new',
594
+ },
595
+ ],
596
+ },
597
+ };
598
+ const filtered = filterGlossaryByChangeStatus(allEntries, entityChangeStatus);
599
+ const names = filtered.map((e) => e.name).sort();
600
+ expect(names).toEqual([
601
+ 'DrinkCard',
602
+ 'HeroImage',
603
+ 'ReviewCard',
604
+ 'StarRating',
605
+ 'formatReviewCount',
606
+ ]);
607
+ });
608
+ it('should return all entries when entityChangeStatus is empty', () => {
609
+ // When there's no change status data (e.g., no git changes), fall back to auditing everything
610
+ const filtered = filterGlossaryByChangeStatus(allEntries, {});
611
+ expect(filtered).toEqual(allEntries);
612
+ });
613
+ it('should return all entries when entityChangeStatus is undefined', () => {
614
+ const filtered = filterGlossaryByChangeStatus(allEntries, undefined);
615
+ expect(filtered).toEqual(allEntries);
616
+ });
617
+ it('should exclude unchanged entries that have no status', () => {
618
+ const entityChangeStatus = {
619
+ HeroImage: { status: 'new' },
620
+ };
621
+ const filtered = filterGlossaryByChangeStatus(allEntries, entityChangeStatus);
622
+ expect(filtered).toHaveLength(1);
623
+ expect(filtered[0].name).toBe('HeroImage');
624
+ });
625
+ it('should match entries by filePath when name does not match any status key', () => {
626
+ // Sometimes entity names in entityChangeStatus are derived from file paths
627
+ // and may not exactly match glossary names. Fall back to filePath matching.
628
+ const entityChangeStatus = {
629
+ // Entity name derived differently, but filePath matches
630
+ 'app/components/DrinkCard.tsx': { status: 'edited' },
631
+ };
632
+ const filtered = filterGlossaryByChangeStatus(allEntries, entityChangeStatus);
633
+ expect(filtered.map((e) => e.name)).toContain('DrinkCard');
634
+ });
635
+ });
636
+ // ── resolveAuditSessionScope ──────────────────────────────────────
637
+ describe('resolveAuditSessionScope', () => {
638
+ it('should scope to session when entityChangeStatus has entries and featureStartedAt exists', () => {
639
+ const result = resolveAuditSessionScope({
640
+ featureStartedAt: '2026-03-12T14:01:31.291Z',
641
+ entityChangeStatus: {
642
+ ArticleCard: { status: 'new' },
643
+ LibraryHeader: { status: 'new' },
644
+ },
645
+ });
646
+ expect(result.featureStartedAt).toBe('2026-03-12T14:01:31.291Z');
647
+ expect(result.entityChangeStatus).toEqual({
648
+ ArticleCard: { status: 'new' },
649
+ LibraryHeader: { status: 'new' },
650
+ });
651
+ });
652
+ it('should NOT scope scenario counts to session when entityChangeStatus is empty', () => {
653
+ // This is the testapp bug: entityChangeStatus computation returned empty,
654
+ // so the glossary filter falls back to "audit all components", but the
655
+ // scenario count query still filters by featureStartedAt — causing
656
+ // Feature 1 components to appear as "no scenarios" even though they have them.
657
+ const result = resolveAuditSessionScope({
658
+ featureStartedAt: '2026-03-12T14:01:31.291Z',
659
+ entityChangeStatus: undefined,
660
+ });
661
+ // When we can't scope the glossary, we shouldn't scope scenario counts either
662
+ expect(result.featureStartedAt).toBeNull();
663
+ });
664
+ it('should NOT scope scenario counts to session when entityChangeStatus is an empty object', () => {
665
+ const result = resolveAuditSessionScope({
666
+ featureStartedAt: '2026-03-12T14:01:31.291Z',
667
+ entityChangeStatus: {},
668
+ });
669
+ expect(result.featureStartedAt).toBeNull();
670
+ });
671
+ it('should return null featureStartedAt when none was provided', () => {
672
+ const result = resolveAuditSessionScope({
673
+ featureStartedAt: null,
674
+ entityChangeStatus: { Header: { status: 'new' } },
675
+ });
676
+ expect(result.featureStartedAt).toBeNull();
677
+ });
678
+ it('should pass through entityChangeStatus unchanged when it has entries', () => {
679
+ const ecs = {
680
+ ArticleCard: { status: 'new' },
681
+ Header: { status: 'edited' },
682
+ };
683
+ const result = resolveAuditSessionScope({
684
+ featureStartedAt: '2026-03-12T14:01:31.291Z',
685
+ entityChangeStatus: ecs,
686
+ });
687
+ expect(result.entityChangeStatus).toBe(ecs);
688
+ });
689
+ describe('multi-feature audit scenario (testapp reproduction)', () => {
690
+ // Reproduces the exact testapp bug:
691
+ // - Feature 1 built 8 components with scenarios at 13:28-13:30
692
+ // - Feature 2 starts at 14:01, builds 4 new components with scenarios at 14:14-14:16
693
+ // - entityChangeStatus computation returns empty (fails/returns {})
694
+ // - Glossary includes ALL 12 components
695
+ // - Scenario counts only include Feature 2 scenarios (after 14:01)
696
+ // - Result: Feature 1's 8 components reported as "no scenarios"
697
+ const allComponents = [
698
+ // Feature 1 components
699
+ {
700
+ name: 'Header',
701
+ filePath: 'src/components/Header.tsx',
702
+ returnType: 'JSX.Element',
703
+ },
704
+ {
705
+ name: 'Logo',
706
+ filePath: 'src/components/Logo.tsx',
707
+ returnType: 'JSX.Element',
708
+ },
709
+ {
710
+ name: 'TabBar',
711
+ filePath: 'src/components/TabBar.tsx',
712
+ returnType: 'JSX.Element',
713
+ },
714
+ {
715
+ name: 'ArticlePreview',
716
+ filePath: 'src/components/ArticlePreview.tsx',
717
+ returnType: 'JSX.Element',
718
+ },
719
+ {
720
+ name: 'SaveButton',
721
+ filePath: 'src/components/SaveButton.tsx',
722
+ returnType: 'JSX.Element',
723
+ },
724
+ {
725
+ name: 'StatusBanner',
726
+ filePath: 'src/components/StatusBanner.tsx',
727
+ returnType: 'JSX.Element',
728
+ },
729
+ {
730
+ name: 'EmptyState',
731
+ filePath: 'src/components/EmptyState.tsx',
732
+ returnType: 'JSX.Element',
733
+ },
734
+ {
735
+ name: 'ArticleRow',
736
+ filePath: 'src/components/ArticleRow.tsx',
737
+ returnType: 'JSX.Element',
738
+ },
739
+ // Feature 2 components
740
+ {
741
+ name: 'ArticleCard',
742
+ filePath: 'src/components/ArticleCard.tsx',
743
+ returnType: 'JSX.Element',
744
+ },
745
+ {
746
+ name: 'LibraryHeader',
747
+ filePath: 'src/components/LibraryHeader.tsx',
748
+ returnType: 'JSX.Element',
749
+ },
750
+ {
751
+ name: 'ArticleCardGrid',
752
+ filePath: 'src/components/ArticleCardGrid.tsx',
753
+ returnType: 'JSX.Element',
754
+ },
755
+ {
756
+ name: 'OpenLibraryButton',
757
+ filePath: 'src/components/OpenLibraryButton.tsx',
758
+ returnType: 'JSX.Element',
759
+ },
760
+ ];
761
+ // All scenarios that exist in the DB (both features)
762
+ const allScenarioCounts = {
763
+ Header: 2,
764
+ Logo: 1,
765
+ TabBar: 3,
766
+ ArticlePreview: 4,
767
+ SaveButton: 2,
768
+ StatusBanner: 2,
769
+ EmptyState: 2,
770
+ ArticleRow: 3,
771
+ ArticleCard: 4,
772
+ LibraryHeader: 3,
773
+ ArticleCardGrid: 2,
774
+ OpenLibraryButton: 1,
775
+ };
776
+ // Only Feature 2 scenarios (created after featureStartedAt)
777
+ const sessionScopedCounts = {
778
+ ArticleCard: 4,
779
+ LibraryHeader: 3,
780
+ ArticleCardGrid: 2,
781
+ OpenLibraryButton: 1,
782
+ };
783
+ it('should pass audit when entityChangeStatus is empty and all scenarios are counted', () => {
784
+ // With the fix: resolveAuditSessionScope nullifies featureStartedAt
785
+ // when entityChangeStatus is empty, so ALL scenarios are counted
786
+ const scope = resolveAuditSessionScope({
787
+ featureStartedAt: '2026-03-12T14:01:31.291Z',
788
+ entityChangeStatus: undefined,
789
+ });
790
+ // Glossary filter: returns all (no change status to filter by)
791
+ const filtered = filterGlossaryByChangeStatus(allComponents, scope.entityChangeStatus);
792
+ expect(filtered).toHaveLength(12);
793
+ // Since featureStartedAt is now null, the route would query ALL scenarios
794
+ // (not session-scoped), giving us allScenarioCounts
795
+ const countsToUse = scope.featureStartedAt
796
+ ? sessionScopedCounts
797
+ : allScenarioCounts;
798
+ const { components } = classifyGlossaryEntries(filtered);
799
+ const result = computeAudit({
800
+ components,
801
+ functions: [],
802
+ scenarioCounts: countsToUse,
803
+ testFileExistence: {},
804
+ });
805
+ // Every component should have scenarios
806
+ expect(result.summary.componentsMissing).toBe(0);
807
+ expect(result.summary.componentsOk).toBe(12);
808
+ expect(result.summary.allPassing).toBe(true);
809
+ });
810
+ it('demonstrates the bug: session-scoped counts with unscoped glossary fails Feature 1', () => {
811
+ // WITHOUT the fix: entityChangeStatus is empty so all 12 components are audited,
812
+ // but scenario counts are session-scoped so Feature 1 components get 0
813
+ const filtered = filterGlossaryByChangeStatus(allComponents, undefined);
814
+ expect(filtered).toHaveLength(12);
815
+ const { components } = classifyGlossaryEntries(filtered);
816
+ const result = computeAudit({
817
+ components,
818
+ functions: [],
819
+ scenarioCounts: sessionScopedCounts, // BUG: only Feature 2 scenarios
820
+ testFileExistence: {},
821
+ });
822
+ // This is the broken behavior — 8 components incorrectly flagged
823
+ expect(result.summary.componentsMissing).toBe(8);
824
+ expect(result.summary.allPassing).toBe(false);
825
+ });
826
+ it('should correctly scope audit when entityChangeStatus is available', () => {
827
+ // When entityChangeStatus works, only Feature 2 components are audited
828
+ // and only Feature 2 scenarios are counted — both filters agree
829
+ const ecs = {
830
+ ArticleCard: { status: 'new' },
831
+ LibraryHeader: { status: 'new' },
832
+ ArticleCardGrid: { status: 'new' },
833
+ OpenLibraryButton: { status: 'new' },
834
+ };
835
+ const scope = resolveAuditSessionScope({
836
+ featureStartedAt: '2026-03-12T14:01:31.291Z',
837
+ entityChangeStatus: ecs,
838
+ });
839
+ // featureStartedAt preserved — session scoping is valid
840
+ expect(scope.featureStartedAt).toBe('2026-03-12T14:01:31.291Z');
841
+ const filtered = filterGlossaryByChangeStatus(allComponents, scope.entityChangeStatus);
842
+ expect(filtered).toHaveLength(4); // Only Feature 2 components
843
+ const { components } = classifyGlossaryEntries(filtered);
844
+ const result = computeAudit({
845
+ components,
846
+ functions: [],
847
+ scenarioCounts: sessionScopedCounts,
848
+ testFileExistence: {},
849
+ });
850
+ expect(result.summary.componentsMissing).toBe(0);
851
+ expect(result.summary.componentsOk).toBe(4);
852
+ expect(result.summary.allPassing).toBe(true);
853
+ });
854
+ });
855
+ });
856
+ // ── queryScenarioCounts ─────────────────────────────────────────────
857
+ describe('queryScenarioCounts', () => {
858
+ let db;
859
+ let rawDb;
860
+ const projectId = 'test-project-id';
861
+ beforeEach(async () => {
862
+ rawDb = new Database(':memory:');
863
+ db = new Kysely({ dialect: new SqliteDialect({ database: rawDb }) });
864
+ await db.schema
865
+ .createTable('editor_scenarios')
866
+ .addColumn('id', 'varchar', (col) => col.primaryKey())
867
+ .addColumn('project_id', 'varchar', (col) => col.notNull())
868
+ .addColumn('name', 'varchar', (col) => col.notNull())
869
+ .addColumn('description', 'text')
870
+ .addColumn('component_name', 'varchar')
871
+ .addColumn('component_path', 'varchar')
872
+ .addColumn('url', 'varchar')
873
+ .addColumn('type', 'varchar')
874
+ .addColumn('screenshot_path', 'varchar')
875
+ .addColumn('viewport_width', 'integer')
876
+ .addColumn('viewport_height', 'integer')
877
+ .addColumn('dimension', 'varchar')
878
+ .addColumn('created_at', 'datetime')
879
+ .addColumn('updated_at', 'datetime')
880
+ .execute();
881
+ });
882
+ afterEach(async () => {
883
+ await db.destroy();
884
+ });
885
+ it('should count all scenarios when featureStartedAt is null', async () => {
886
+ await db
887
+ .insertInto('editor_scenarios')
888
+ .values({
889
+ id: 'sc-1',
890
+ project_id: projectId,
891
+ name: 'ArticleRow - Default',
892
+ component_name: 'ArticleRow',
893
+ viewport_width: 1280,
894
+ viewport_height: 720,
895
+ created_at: '2026-03-12 13:00:00',
896
+ })
897
+ .execute();
898
+ const counts = await queryScenarioCounts(db, projectId, null);
899
+ expect(counts).toEqual({ ArticleRow: 1 });
900
+ });
901
+ it('should count scenarios created after featureStartedAt', async () => {
902
+ await db
903
+ .insertInto('editor_scenarios')
904
+ .values({
905
+ id: 'sc-1',
906
+ project_id: projectId,
907
+ name: 'ArticleRow - Default',
908
+ component_name: 'ArticleRow',
909
+ viewport_width: 1280,
910
+ viewport_height: 720,
911
+ created_at: '2026-03-12 14:30:00',
912
+ })
913
+ .execute();
914
+ const counts = await queryScenarioCounts(db, projectId, '2026-03-12T14:01:31.291Z');
915
+ expect(counts).toEqual({ ArticleRow: 1 });
916
+ });
917
+ it('should exclude scenarios created before featureStartedAt', async () => {
918
+ await db
919
+ .insertInto('editor_scenarios')
920
+ .values({
921
+ id: 'sc-1',
922
+ project_id: projectId,
923
+ name: 'ArticleRow - Default',
924
+ component_name: 'ArticleRow',
925
+ viewport_width: 1280,
926
+ viewport_height: 720,
927
+ created_at: '2026-03-12 13:00:00',
928
+ })
929
+ .execute();
930
+ const counts = await queryScenarioCounts(db, projectId, '2026-03-12T14:01:31.291Z');
931
+ expect(counts).toEqual({});
932
+ });
933
+ it('should count re-registered scenarios whose updated_at is after featureStartedAt', async () => {
934
+ // This is the bug: a scenario from Feature 1 (created_at before featureStartedAt)
935
+ // is re-registered in Feature 2 (updated_at after featureStartedAt).
936
+ // The audit should count it because it was actively re-registered in this session.
937
+ await db
938
+ .insertInto('editor_scenarios')
939
+ .values({
940
+ id: 'sc-1',
941
+ project_id: projectId,
942
+ name: 'ArticleRow - Default',
943
+ component_name: 'ArticleRow',
944
+ viewport_width: 400,
945
+ viewport_height: 600,
946
+ created_at: '2026-03-12 13:28:00', // Feature 1
947
+ updated_at: '2026-03-12 14:32:00', // Re-registered in Feature 2
948
+ })
949
+ .execute();
950
+ const counts = await queryScenarioCounts(db, projectId, '2026-03-12T14:01:31.291Z');
951
+ // Should count because updated_at is after featureStartedAt
952
+ expect(counts).toEqual({ ArticleRow: 1 });
953
+ });
954
+ it('should handle mixed scenarios: some new, some re-registered', async () => {
955
+ // ArticleCard: new in Feature 2 (created_at after featureStartedAt)
956
+ await db
957
+ .insertInto('editor_scenarios')
958
+ .values({
959
+ id: 'sc-1',
960
+ project_id: projectId,
961
+ name: 'ArticleCard - Default',
962
+ component_name: 'ArticleCard',
963
+ viewport_width: 1280,
964
+ viewport_height: 720,
965
+ created_at: '2026-03-12 14:14:00',
966
+ })
967
+ .execute();
968
+ // ArticleRow: from Feature 1, re-registered in Feature 2
969
+ await db
970
+ .insertInto('editor_scenarios')
971
+ .values({
972
+ id: 'sc-2',
973
+ project_id: projectId,
974
+ name: 'ArticleRow - Default',
975
+ component_name: 'ArticleRow',
976
+ viewport_width: 400,
977
+ viewport_height: 600,
978
+ created_at: '2026-03-12 13:28:00', // Feature 1
979
+ updated_at: '2026-03-12 14:32:00', // Re-registered in Feature 2
980
+ })
981
+ .execute();
982
+ const counts = await queryScenarioCounts(db, projectId, '2026-03-12T14:01:31.291Z');
983
+ expect(counts).toEqual({ ArticleCard: 1, ArticleRow: 1 });
984
+ });
244
985
  });
245
986
  });
246
987
  //# sourceMappingURL=editorAudit.test.js.map