@codeyam/codeyam-cli 0.1.0-staging.a890816 → 0.1.0-staging.ad88eeb

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 (317) hide show
  1. package/analyzer-template/.build-info.json +7 -7
  2. package/analyzer-template/log.txt +3 -3
  3. package/analyzer-template/package.json +9 -9
  4. package/analyzer-template/packages/ai/package.json +1 -1
  5. package/analyzer-template/packages/ai/src/lib/generateExecutionFlows.ts +0 -33
  6. package/analyzer-template/packages/analyze/src/lib/ProjectAnalyzer.ts +13 -7
  7. package/analyzer-template/packages/analyze/src/lib/asts/index.ts +7 -2
  8. package/analyzer-template/packages/analyze/src/lib/files/scenarios/generateExecutionFlows.ts +0 -98
  9. package/analyzer-template/packages/aws/package.json +2 -2
  10. package/analyzer-template/packages/database/package.json +3 -3
  11. package/analyzer-template/packages/database/src/lib/kysely/tables/editorScenariosTable.ts +20 -0
  12. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/editorScenariosTable.d.ts +4 -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 +20 -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/types/src/enums/ProjectFramework.d.ts +2 -0
  17. package/analyzer-template/packages/github/dist/types/src/enums/ProjectFramework.d.ts.map +1 -1
  18. package/analyzer-template/packages/github/dist/types/src/enums/ProjectFramework.js +2 -0
  19. package/analyzer-template/packages/github/dist/types/src/enums/ProjectFramework.js.map +1 -1
  20. package/analyzer-template/packages/github/package.json +1 -1
  21. package/analyzer-template/packages/types/src/enums/ProjectFramework.ts +2 -0
  22. package/analyzer-template/packages/ui-components/package.json +1 -1
  23. package/analyzer-template/packages/utils/dist/types/src/enums/ProjectFramework.d.ts +2 -0
  24. package/analyzer-template/packages/utils/dist/types/src/enums/ProjectFramework.d.ts.map +1 -1
  25. package/analyzer-template/packages/utils/dist/types/src/enums/ProjectFramework.js +2 -0
  26. package/analyzer-template/packages/utils/dist/types/src/enums/ProjectFramework.js.map +1 -1
  27. package/codeyam-cli/src/__tests__/memory-scripts/filter-session.test.js +196 -0
  28. package/codeyam-cli/src/__tests__/memory-scripts/filter-session.test.js.map +1 -0
  29. package/codeyam-cli/src/__tests__/memory-scripts/read-json-field.test.js +114 -0
  30. package/codeyam-cli/src/__tests__/memory-scripts/read-json-field.test.js.map +1 -0
  31. package/codeyam-cli/src/__tests__/memory-scripts/ripgrep-fallback.test.js +149 -0
  32. package/codeyam-cli/src/__tests__/memory-scripts/ripgrep-fallback.test.js.map +1 -0
  33. package/codeyam-cli/src/commands/default.js +3 -46
  34. package/codeyam-cli/src/commands/default.js.map +1 -1
  35. package/codeyam-cli/src/commands/editor.js +1893 -215
  36. package/codeyam-cli/src/commands/editor.js.map +1 -1
  37. package/codeyam-cli/src/commands/init.js +6 -1
  38. package/codeyam-cli/src/commands/init.js.map +1 -1
  39. package/codeyam-cli/src/data/techStacks.js +82 -0
  40. package/codeyam-cli/src/data/techStacks.js.map +1 -0
  41. package/codeyam-cli/src/utils/__tests__/devServerState.test.js +134 -0
  42. package/codeyam-cli/src/utils/__tests__/devServerState.test.js.map +1 -0
  43. package/codeyam-cli/src/utils/__tests__/editorApi.test.js +127 -0
  44. package/codeyam-cli/src/utils/__tests__/editorApi.test.js.map +1 -0
  45. package/codeyam-cli/src/utils/__tests__/editorAudit.test.js +635 -0
  46. package/codeyam-cli/src/utils/__tests__/editorAudit.test.js.map +1 -0
  47. package/codeyam-cli/src/utils/__tests__/editorCapture.test.js +93 -0
  48. package/codeyam-cli/src/utils/__tests__/editorCapture.test.js.map +1 -0
  49. package/codeyam-cli/src/utils/__tests__/editorDevServer.test.js +279 -0
  50. package/codeyam-cli/src/utils/__tests__/editorDevServer.test.js.map +1 -0
  51. package/codeyam-cli/src/utils/__tests__/editorEntityChangeStatus.test.js +121 -0
  52. package/codeyam-cli/src/utils/__tests__/editorEntityChangeStatus.test.js.map +1 -0
  53. package/codeyam-cli/src/utils/__tests__/editorImageVerifier.test.js +294 -0
  54. package/codeyam-cli/src/utils/__tests__/editorImageVerifier.test.js.map +1 -0
  55. package/codeyam-cli/src/utils/__tests__/editorJournal.test.js +542 -0
  56. package/codeyam-cli/src/utils/__tests__/editorJournal.test.js.map +1 -0
  57. package/codeyam-cli/src/utils/__tests__/editorLoaderHelpers.test.js +393 -0
  58. package/codeyam-cli/src/utils/__tests__/editorLoaderHelpers.test.js.map +1 -0
  59. package/codeyam-cli/src/utils/__tests__/editorMockState.test.js +270 -0
  60. package/codeyam-cli/src/utils/__tests__/editorMockState.test.js.map +1 -0
  61. package/codeyam-cli/src/utils/__tests__/editorPreloadHelpers.test.js +217 -0
  62. package/codeyam-cli/src/utils/__tests__/editorPreloadHelpers.test.js.map +1 -0
  63. package/codeyam-cli/src/utils/__tests__/editorPreview.test.js +266 -0
  64. package/codeyam-cli/src/utils/__tests__/editorPreview.test.js.map +1 -0
  65. package/codeyam-cli/src/utils/__tests__/editorProxySession.test.js +107 -0
  66. package/codeyam-cli/src/utils/__tests__/editorProxySession.test.js.map +1 -0
  67. package/codeyam-cli/src/utils/__tests__/editorScenarioLookup.test.js +139 -0
  68. package/codeyam-cli/src/utils/__tests__/editorScenarioLookup.test.js.map +1 -0
  69. package/codeyam-cli/src/utils/__tests__/editorScenarioSwitch.test.js +221 -0
  70. package/codeyam-cli/src/utils/__tests__/editorScenarioSwitch.test.js.map +1 -0
  71. package/codeyam-cli/src/utils/__tests__/editorScenarios.test.js +221 -0
  72. package/codeyam-cli/src/utils/__tests__/editorScenarios.test.js.map +1 -0
  73. package/codeyam-cli/src/utils/__tests__/editorSeedAdapter.test.js +213 -0
  74. package/codeyam-cli/src/utils/__tests__/editorSeedAdapter.test.js.map +1 -0
  75. package/codeyam-cli/src/utils/__tests__/entityChangeStatus.test.js +1737 -0
  76. package/codeyam-cli/src/utils/__tests__/entityChangeStatus.test.js.map +1 -0
  77. package/codeyam-cli/src/utils/__tests__/git.editor.test.js +134 -0
  78. package/codeyam-cli/src/utils/__tests__/git.editor.test.js.map +1 -0
  79. package/codeyam-cli/src/utils/__tests__/journalCaptureStabilization.test.js +107 -0
  80. package/codeyam-cli/src/utils/__tests__/journalCaptureStabilization.test.js.map +1 -0
  81. package/codeyam-cli/src/utils/__tests__/parseRegisterArg.test.js +101 -0
  82. package/codeyam-cli/src/utils/__tests__/parseRegisterArg.test.js.map +1 -0
  83. package/codeyam-cli/src/utils/__tests__/project.test.js +65 -0
  84. package/codeyam-cli/src/utils/__tests__/project.test.js.map +1 -0
  85. package/codeyam-cli/src/utils/__tests__/scenarioMarkers.test.js +121 -0
  86. package/codeyam-cli/src/utils/__tests__/scenarioMarkers.test.js.map +1 -0
  87. package/codeyam-cli/src/utils/__tests__/scenariosManifest.test.js +246 -0
  88. package/codeyam-cli/src/utils/__tests__/scenariosManifest.test.js.map +1 -0
  89. package/codeyam-cli/src/utils/__tests__/setupClaudeCodeSettings.test.js +25 -5
  90. package/codeyam-cli/src/utils/__tests__/setupClaudeCodeSettings.test.js.map +1 -1
  91. package/codeyam-cli/src/utils/__tests__/templateConsistency.test.js +51 -0
  92. package/codeyam-cli/src/utils/__tests__/templateConsistency.test.js.map +1 -0
  93. package/codeyam-cli/src/utils/__tests__/webappDetection.test.js +142 -0
  94. package/codeyam-cli/src/utils/__tests__/webappDetection.test.js.map +1 -0
  95. package/codeyam-cli/src/utils/backgroundServer.js +2 -2
  96. package/codeyam-cli/src/utils/backgroundServer.js.map +1 -1
  97. package/codeyam-cli/src/utils/buildFlags.js +4 -0
  98. package/codeyam-cli/src/utils/buildFlags.js.map +1 -0
  99. package/codeyam-cli/src/utils/devServerState.js +71 -0
  100. package/codeyam-cli/src/utils/devServerState.js.map +1 -0
  101. package/codeyam-cli/src/utils/editorApi.js +73 -0
  102. package/codeyam-cli/src/utils/editorApi.js.map +1 -0
  103. package/codeyam-cli/src/utils/editorAudit.js +159 -0
  104. package/codeyam-cli/src/utils/editorAudit.js.map +1 -0
  105. package/codeyam-cli/src/utils/editorCapture.js +102 -0
  106. package/codeyam-cli/src/utils/editorCapture.js.map +1 -0
  107. package/codeyam-cli/src/utils/editorDevServer.js +193 -0
  108. package/codeyam-cli/src/utils/editorDevServer.js.map +1 -0
  109. package/codeyam-cli/src/utils/editorEntityChangeStatus.js +44 -0
  110. package/codeyam-cli/src/utils/editorEntityChangeStatus.js.map +1 -0
  111. package/codeyam-cli/src/utils/editorImageVerifier.js +155 -0
  112. package/codeyam-cli/src/utils/editorImageVerifier.js.map +1 -0
  113. package/codeyam-cli/src/utils/editorJournal.js +225 -0
  114. package/codeyam-cli/src/utils/editorJournal.js.map +1 -0
  115. package/codeyam-cli/src/utils/editorLoaderHelpers.js +81 -0
  116. package/codeyam-cli/src/utils/editorLoaderHelpers.js.map +1 -0
  117. package/codeyam-cli/src/utils/editorMockState.js +248 -0
  118. package/codeyam-cli/src/utils/editorMockState.js.map +1 -0
  119. package/codeyam-cli/src/utils/editorPreloadHelpers.js +135 -0
  120. package/codeyam-cli/src/utils/editorPreloadHelpers.js.map +1 -0
  121. package/codeyam-cli/src/utils/editorPreview.js +106 -0
  122. package/codeyam-cli/src/utils/editorPreview.js.map +1 -0
  123. package/codeyam-cli/src/utils/editorScenarioSwitch.js +112 -0
  124. package/codeyam-cli/src/utils/editorScenarioSwitch.js.map +1 -0
  125. package/codeyam-cli/src/utils/editorScenarios.js +96 -0
  126. package/codeyam-cli/src/utils/editorScenarios.js.map +1 -0
  127. package/codeyam-cli/src/utils/editorSeedAdapter.js +173 -0
  128. package/codeyam-cli/src/utils/editorSeedAdapter.js.map +1 -0
  129. package/codeyam-cli/src/utils/entityChangeStatus.js +347 -0
  130. package/codeyam-cli/src/utils/entityChangeStatus.js.map +1 -0
  131. package/codeyam-cli/src/utils/entityChangeStatus.server.js +158 -0
  132. package/codeyam-cli/src/utils/entityChangeStatus.server.js.map +1 -0
  133. package/codeyam-cli/src/utils/git.js +51 -0
  134. package/codeyam-cli/src/utils/git.js.map +1 -1
  135. package/codeyam-cli/src/utils/install-skills.js +28 -17
  136. package/codeyam-cli/src/utils/install-skills.js.map +1 -1
  137. package/codeyam-cli/src/utils/parseRegisterArg.js +31 -0
  138. package/codeyam-cli/src/utils/parseRegisterArg.js.map +1 -0
  139. package/codeyam-cli/src/utils/project.js +15 -5
  140. package/codeyam-cli/src/utils/project.js.map +1 -1
  141. package/codeyam-cli/src/utils/scenarioMarkers.js +134 -0
  142. package/codeyam-cli/src/utils/scenarioMarkers.js.map +1 -0
  143. package/codeyam-cli/src/utils/scenariosManifest.js +112 -0
  144. package/codeyam-cli/src/utils/scenariosManifest.js.map +1 -0
  145. package/codeyam-cli/src/utils/setupClaudeCodeSettings.js +46 -16
  146. package/codeyam-cli/src/utils/setupClaudeCodeSettings.js.map +1 -1
  147. package/codeyam-cli/src/utils/testRunner.js +1 -1
  148. package/codeyam-cli/src/utils/testRunner.js.map +1 -1
  149. package/codeyam-cli/src/utils/webappDetection.js +21 -0
  150. package/codeyam-cli/src/utils/webappDetection.js.map +1 -1
  151. package/codeyam-cli/src/webserver/__tests__/editorProxy.test.js +178 -0
  152. package/codeyam-cli/src/webserver/__tests__/editorProxy.test.js.map +1 -0
  153. package/codeyam-cli/src/webserver/app/lib/git.js +396 -0
  154. package/codeyam-cli/src/webserver/app/lib/git.js.map +1 -0
  155. package/codeyam-cli/src/webserver/build/client/assets/{CopyButton-DmJveP3T.js → CopyButton-BPXZwM4t.js} +1 -1
  156. package/codeyam-cli/src/webserver/build/client/assets/{EntityItem-C76mRRiF.js → EntityItem-BcgbViKV.js} +3 -3
  157. package/codeyam-cli/src/webserver/build/client/assets/{EntityTypeIcon-CobE682z.js → EntityTypeIcon-CQIG2qda.js} +9 -9
  158. package/codeyam-cli/src/webserver/build/client/assets/{ReportIssueModal-djPLI-WV.js → ReportIssueModal-BzHcG7SE.js} +3 -3
  159. package/codeyam-cli/src/webserver/build/client/assets/{ScenarioViewer-B76aig_2.js → ScenarioViewer-0DY_NKil.js} +3 -3
  160. package/codeyam-cli/src/webserver/build/client/assets/ViewportInspectBar-oAf2Kqsf.js +1 -0
  161. package/codeyam-cli/src/webserver/build/client/assets/{_index-C96V0n15.js → _index-DLxKhri3.js} +3 -3
  162. package/codeyam-cli/src/webserver/build/client/assets/{activity.(_tab)-BpKzcsJz.js → activity.(_tab)-BcY3q6nt.js} +6 -6
  163. package/codeyam-cli/src/webserver/build/client/assets/addon-canvas-DpzMmAy5.js +1 -0
  164. package/codeyam-cli/src/webserver/build/client/assets/addon-fit-YJmn1quW.js +12 -0
  165. package/codeyam-cli/src/webserver/build/client/assets/addon-webgl-DI8QOUvO.js +58 -0
  166. package/codeyam-cli/src/webserver/build/client/assets/{agent-transcripts-D9hemwl6.js → agent-transcripts-Bni3iiUj.js} +5 -5
  167. package/codeyam-cli/src/webserver/build/client/assets/api.editor-audit-l0sNRNKZ.js +1 -0
  168. package/codeyam-cli/src/webserver/build/client/assets/api.editor-file-diff-l0sNRNKZ.js +1 -0
  169. package/codeyam-cli/src/webserver/build/client/assets/api.editor-file-l0sNRNKZ.js +1 -0
  170. package/codeyam-cli/src/webserver/build/client/assets/api.editor-load-commit-l0sNRNKZ.js +1 -0
  171. package/codeyam-cli/src/webserver/build/client/assets/api.editor-project-info-l0sNRNKZ.js +1 -0
  172. package/codeyam-cli/src/webserver/build/client/assets/{book-open-D_nMCFmP.js → book-open-BYOypzCa.js} +2 -2
  173. package/codeyam-cli/src/webserver/build/client/assets/{chevron-down-BH2h1Ea2.js → chevron-down-C_Pmso5S.js} +2 -2
  174. package/codeyam-cli/src/webserver/build/client/assets/{circle-check-DyIKORY6.js → circle-check-BVMi9VA5.js} +2 -2
  175. package/codeyam-cli/src/webserver/build/client/assets/{copy-NDbZjXao.js → copy-n2FB0_Sw.js} +3 -3
  176. package/codeyam-cli/src/webserver/build/client/assets/createLucideIcon-CC6AbExI.js +41 -0
  177. package/codeyam-cli/src/webserver/build/client/assets/dev.empty-Csi0_PMl.js +1 -0
  178. package/codeyam-cli/src/webserver/build/client/assets/editor-BuT_Huj0.js +10 -0
  179. package/codeyam-cli/src/webserver/build/client/assets/editorPreview-B7ztwLut.js +41 -0
  180. package/codeyam-cli/src/webserver/build/client/assets/{entity._sha._-CrjR3zZW.js → entity._sha._-BF4oLwaE.js} +3 -3
  181. package/codeyam-cli/src/webserver/build/client/assets/entity._sha.scenarios._scenarioId.dev-D5rYBT5x.js +6 -0
  182. package/codeyam-cli/src/webserver/build/client/assets/entity._sha.scenarios._scenarioId.fullscreen-CF164ouH.js +6 -0
  183. package/codeyam-cli/src/webserver/build/client/assets/{files-DO4CZ16O.js → files-BZrlFE1F.js} +1 -1
  184. package/codeyam-cli/src/webserver/build/client/assets/git-DdZcvjGh.js +1 -0
  185. package/codeyam-cli/src/webserver/build/client/assets/globals-BkWJ_UNc.css +1 -0
  186. package/codeyam-cli/src/webserver/build/client/assets/index-yHOVb4rc.js +15 -0
  187. package/codeyam-cli/src/webserver/build/client/assets/{loader-circle-BAXYRVEO.js → loader-circle-DaAZ_H2w.js} +2 -2
  188. package/codeyam-cli/src/webserver/build/client/assets/manifest-b0f1372e.js +1 -0
  189. package/codeyam-cli/src/webserver/build/client/assets/{memory-FweZHj5U.js → memory-Bl2rpw8u.js} +13 -10
  190. package/codeyam-cli/src/webserver/build/client/assets/{pause-DTAcYxBt.js → pause-f5-1lKBt.js} +3 -3
  191. package/codeyam-cli/src/webserver/build/client/assets/{root-DiRdBreB.js → root-B_X8HS1x.js} +18 -18
  192. package/codeyam-cli/src/webserver/build/client/assets/{search-fKo7v0Zo.js → search-Di64LWVb.js} +2 -2
  193. package/codeyam-cli/src/webserver/build/client/assets/{settings-DfuTtcJP.js → settings-0OrEMU6J.js} +1 -1
  194. package/codeyam-cli/src/webserver/build/client/assets/{simulations-B3aOzpCZ.js → simulations-DWT-CvLy.js} +1 -1
  195. package/codeyam-cli/src/webserver/build/client/assets/{terminal-BG4heKCG.js → terminal-Br7MOqts.js} +3 -3
  196. package/codeyam-cli/src/webserver/build/client/assets/{triangle-alert-DtSmdtM4.js → triangle-alert-BLdiCuG-.js} +2 -2
  197. package/codeyam-cli/src/webserver/build/client/assets/useCustomSizes-CrAK28Bc.js +1 -0
  198. package/codeyam-cli/src/webserver/build/client/assets/xterm-BqvuqXEL.js +27 -0
  199. package/codeyam-cli/src/webserver/build/server/assets/{index-BzAbACSx.js → index-CbF6h3dj.js} +1 -1
  200. package/codeyam-cli/src/webserver/build/server/assets/server-build-DRFwTJqO.js +367 -0
  201. package/codeyam-cli/src/webserver/build/server/index.js +1 -1
  202. package/codeyam-cli/src/webserver/build-info.json +5 -5
  203. package/codeyam-cli/src/webserver/editorProxy.js +383 -50
  204. package/codeyam-cli/src/webserver/editorProxy.js.map +1 -1
  205. package/codeyam-cli/src/webserver/scripts/codeyam-preload.mjs +414 -0
  206. package/codeyam-cli/src/webserver/scripts/journalCapture.ts +94 -4
  207. package/codeyam-cli/src/webserver/server.js +93 -12
  208. package/codeyam-cli/src/webserver/server.js.map +1 -1
  209. package/codeyam-cli/src/webserver/terminalServer.js +65 -112
  210. package/codeyam-cli/src/webserver/terminalServer.js.map +1 -1
  211. package/codeyam-cli/templates/chrome-extension-react/EXTENSION_SETUP.md +75 -0
  212. package/codeyam-cli/templates/chrome-extension-react/gitignore +15 -0
  213. package/codeyam-cli/templates/chrome-extension-react/index.html +12 -0
  214. package/codeyam-cli/templates/chrome-extension-react/package.json +26 -0
  215. package/codeyam-cli/templates/chrome-extension-react/popup.html +12 -0
  216. package/codeyam-cli/templates/chrome-extension-react/public/manifest.json +15 -0
  217. package/codeyam-cli/templates/chrome-extension-react/src/background/service-worker.ts +7 -0
  218. package/codeyam-cli/templates/chrome-extension-react/src/globals.css +6 -0
  219. package/codeyam-cli/templates/chrome-extension-react/src/lib/storage.ts +37 -0
  220. package/codeyam-cli/templates/chrome-extension-react/src/popup/App.tsx +12 -0
  221. package/codeyam-cli/templates/chrome-extension-react/src/popup/main.tsx +10 -0
  222. package/codeyam-cli/templates/chrome-extension-react/tsconfig.json +24 -0
  223. package/codeyam-cli/templates/chrome-extension-react/vite.config.ts +35 -0
  224. package/codeyam-cli/templates/editor-step-hook.py +95 -9
  225. package/codeyam-cli/templates/expo-react-native/MOBILE_SETUP.md +89 -0
  226. package/codeyam-cli/templates/expo-react-native/app/(tabs)/_layout.tsx +33 -0
  227. package/codeyam-cli/templates/expo-react-native/app/(tabs)/index.tsx +12 -0
  228. package/codeyam-cli/templates/expo-react-native/app/(tabs)/settings.tsx +12 -0
  229. package/codeyam-cli/templates/expo-react-native/app/_layout.tsx +12 -0
  230. package/codeyam-cli/templates/expo-react-native/app.json +18 -0
  231. package/codeyam-cli/templates/expo-react-native/babel.config.js +9 -0
  232. package/codeyam-cli/templates/expo-react-native/gitignore +12 -0
  233. package/codeyam-cli/templates/expo-react-native/global.css +3 -0
  234. package/codeyam-cli/templates/expo-react-native/lib/storage.ts +32 -0
  235. package/codeyam-cli/templates/expo-react-native/metro.config.js +6 -0
  236. package/codeyam-cli/templates/expo-react-native/nativewind-env.d.ts +1 -0
  237. package/codeyam-cli/templates/expo-react-native/package.json +37 -0
  238. package/codeyam-cli/templates/expo-react-native/tailwind.config.js +10 -0
  239. package/codeyam-cli/templates/expo-react-native/tsconfig.json +10 -0
  240. package/codeyam-cli/templates/nextjs-prisma-sqlite/AUTH_PATTERNS.md +308 -0
  241. package/codeyam-cli/templates/nextjs-prisma-sqlite/AUTH_UPGRADE.md +304 -0
  242. package/codeyam-cli/templates/nextjs-prisma-sqlite/DATABASE.md +112 -0
  243. package/codeyam-cli/templates/nextjs-prisma-sqlite/FEATURE_PATTERNS.md +37 -0
  244. package/codeyam-cli/templates/nextjs-prisma-sqlite/app/codeyam-isolate/layout.tsx +12 -0
  245. package/codeyam-cli/templates/nextjs-prisma-sqlite/app/lib/prisma.ts +9 -4
  246. package/codeyam-cli/templates/nextjs-prisma-sqlite/env +4 -0
  247. package/codeyam-cli/templates/nextjs-prisma-sqlite/gitignore +21 -0
  248. package/codeyam-cli/templates/nextjs-prisma-sqlite/package.json +4 -1
  249. package/codeyam-cli/templates/nextjs-prisma-sqlite/prisma/seed.ts +4 -1
  250. package/codeyam-cli/templates/nextjs-prisma-sqlite/seed-adapter.ts +92 -0
  251. package/codeyam-cli/templates/nextjs-prisma-sqlite/vitest.config.ts +13 -0
  252. package/codeyam-cli/templates/{nextjs-prisma-sqlite/PRISMA_SETUP.md → nextjs-prisma-supabase/SUPABASE_SETUP.md} +37 -17
  253. package/codeyam-cli/templates/nextjs-prisma-supabase/app/api/todos/route.ts +17 -0
  254. package/codeyam-cli/templates/nextjs-prisma-supabase/app/globals.css +26 -0
  255. package/codeyam-cli/templates/nextjs-prisma-supabase/app/layout.tsx +34 -0
  256. package/codeyam-cli/templates/nextjs-prisma-supabase/app/lib/prisma.ts +20 -0
  257. package/codeyam-cli/templates/nextjs-prisma-supabase/app/lib/supabase.ts +12 -0
  258. package/codeyam-cli/templates/nextjs-prisma-supabase/app/page.tsx +10 -0
  259. package/codeyam-cli/templates/nextjs-prisma-supabase/env +9 -0
  260. package/codeyam-cli/templates/nextjs-prisma-supabase/eslint.config.mjs +11 -0
  261. package/codeyam-cli/templates/nextjs-prisma-supabase/gitignore +40 -0
  262. package/codeyam-cli/templates/nextjs-prisma-supabase/next.config.ts +11 -0
  263. package/codeyam-cli/templates/nextjs-prisma-supabase/package.json +36 -0
  264. package/codeyam-cli/templates/nextjs-prisma-supabase/postcss.config.mjs +7 -0
  265. package/codeyam-cli/templates/nextjs-prisma-supabase/prisma/schema.prisma +27 -0
  266. package/codeyam-cli/templates/nextjs-prisma-supabase/prisma/seed.ts +39 -0
  267. package/codeyam-cli/templates/nextjs-prisma-supabase/prisma.config.ts +12 -0
  268. package/codeyam-cli/templates/nextjs-prisma-supabase/tsconfig.json +34 -0
  269. package/codeyam-cli/templates/{codeyam-dev-mode.md → skills/codeyam-dev-mode/SKILL.md} +2 -2
  270. package/codeyam-cli/templates/skills/codeyam-editor/SKILL.md +145 -0
  271. package/codeyam-cli/templates/{codeyam-memory.md → skills/codeyam-memory/SKILL.md} +215 -0
  272. package/codeyam-cli/templates/skills/codeyam-memory/scripts/holistic-analysis/deprecated-prompt.md +100 -0
  273. package/codeyam-cli/templates/skills/codeyam-memory/scripts/holistic-analysis/detect-deprecated-patterns.mjs +139 -0
  274. package/codeyam-cli/templates/skills/codeyam-memory/scripts/holistic-analysis/find-exports.mjs +52 -0
  275. package/codeyam-cli/templates/skills/codeyam-memory/scripts/holistic-analysis/misleading-api-prompt.md +117 -0
  276. package/codeyam-cli/templates/skills/codeyam-memory/scripts/lib/read-json-field.mjs +61 -0
  277. package/codeyam-cli/templates/skills/codeyam-memory/scripts/lib/ripgrep-fallback.mjs +155 -0
  278. package/codeyam-cli/templates/skills/codeyam-memory/scripts/session-mining/analyze-prompt.md +46 -0
  279. package/codeyam-cli/templates/skills/codeyam-memory/scripts/session-mining/cleanup.mjs +13 -0
  280. package/codeyam-cli/templates/skills/codeyam-memory/scripts/session-mining/filter-session.mjs +95 -0
  281. package/codeyam-cli/templates/skills/codeyam-memory/scripts/session-mining/preprocess.mjs +160 -0
  282. package/package.json +15 -10
  283. package/packages/ai/src/lib/generateExecutionFlows.js +0 -11
  284. package/packages/ai/src/lib/generateExecutionFlows.js.map +1 -1
  285. package/packages/analyze/src/lib/ProjectAnalyzer.js +10 -4
  286. package/packages/analyze/src/lib/ProjectAnalyzer.js.map +1 -1
  287. package/packages/analyze/src/lib/asts/index.js +4 -2
  288. package/packages/analyze/src/lib/asts/index.js.map +1 -1
  289. package/packages/analyze/src/lib/files/scenarios/generateExecutionFlows.js +0 -40
  290. package/packages/analyze/src/lib/files/scenarios/generateExecutionFlows.js.map +1 -1
  291. package/packages/database/src/lib/kysely/tables/editorScenariosTable.js +20 -0
  292. package/packages/database/src/lib/kysely/tables/editorScenariosTable.js.map +1 -1
  293. package/packages/types/src/enums/ProjectFramework.js +2 -0
  294. package/packages/types/src/enums/ProjectFramework.js.map +1 -1
  295. package/scripts/npm-post-install.cjs +34 -0
  296. package/codeyam-cli/src/webserver/build/client/assets/Terminal-CcG8YTLx.js +0 -41
  297. package/codeyam-cli/src/webserver/build/client/assets/addon-fit-CUXOrorO.js +0 -1
  298. package/codeyam-cli/src/webserver/build/client/assets/createLucideIcon-CMT1jU2q.js +0 -21
  299. package/codeyam-cli/src/webserver/build/client/assets/dev.empty-BiM6z3Do.js +0 -1
  300. package/codeyam-cli/src/webserver/build/client/assets/editor-W_IGJ2Kd.js +0 -7
  301. package/codeyam-cli/src/webserver/build/client/assets/entity._sha.scenarios._scenarioId.dev-D6SEzMCu.js +0 -6
  302. package/codeyam-cli/src/webserver/build/client/assets/entity._sha.scenarios._scenarioId.fullscreen-C28BiQzt.js +0 -6
  303. package/codeyam-cli/src/webserver/build/client/assets/git-CFCTYk9I.js +0 -15
  304. package/codeyam-cli/src/webserver/build/client/assets/globals-BZB_H1w2.css +0 -1
  305. package/codeyam-cli/src/webserver/build/client/assets/manifest-8daa4147.js +0 -1
  306. package/codeyam-cli/src/webserver/build/client/assets/useCustomSizes-ByhSyh0W.js +0 -1
  307. package/codeyam-cli/src/webserver/build/client/assets/xterm-DMSzMhqy.js +0 -9
  308. package/codeyam-cli/src/webserver/build/server/assets/server-build-OdUocH6P.js +0 -362
  309. package/codeyam-cli/templates/codeyam-editor.md +0 -68
  310. package/scripts/finalize-analyzer.cjs +0 -13
  311. /package/codeyam-cli/templates/{codeyam-diagnose.md → commands/codeyam-diagnose.md} +0 -0
  312. /package/codeyam-cli/templates/{codeyam-debug.md → skills/codeyam-debug/SKILL.md} +0 -0
  313. /package/codeyam-cli/templates/{codeyam-new-rule.md → skills/codeyam-new-rule/SKILL.md} +0 -0
  314. /package/codeyam-cli/templates/{codeyam-setup.md → skills/codeyam-setup/SKILL.md} +0 -0
  315. /package/codeyam-cli/templates/{codeyam-sim.md → skills/codeyam-sim/SKILL.md} +0 -0
  316. /package/codeyam-cli/templates/{codeyam-test.md → skills/codeyam-test/SKILL.md} +0 -0
  317. /package/codeyam-cli/templates/{codeyam-verify.md → skills/codeyam-verify/SKILL.md} +0 -0
@@ -0,0 +1,414 @@
1
+ /**
2
+ * Node.js preload module for CodeYam editor proxy.
3
+ *
4
+ * Loaded via NODE_OPTIONS='--import /path/to/codeyam-preload.mjs' in the
5
+ * dev server process. Patches global fetch and http/https.request to:
6
+ *
7
+ * 1. **Direct mock matching** — reads the active scenario data from disk and
8
+ * returns mock responses for ANY matching URL (internal API routes, external
9
+ * APIs like Stripe/weather, etc.) without a network round-trip.
10
+ *
11
+ * 2. **Proxy redirect** — for dev-server-targeting requests that don't match
12
+ * a mock route, redirects them through the CodeYam proxy.
13
+ *
14
+ * Must be .mjs (native ESM) because --import requires it.
15
+ * No TypeScript, no build step, no dependencies.
16
+ */
17
+
18
+ import http from 'node:http';
19
+ import https from 'node:https';
20
+ import fs from 'node:fs';
21
+ import path from 'node:path';
22
+ import { Readable } from 'node:stream';
23
+ import { EventEmitter } from 'node:events';
24
+
25
+ let proxyConfig = null;
26
+ let configLoaded = false;
27
+
28
+ /**
29
+ * Lazily load the proxy config from .codeyam/proxy-config.json.
30
+ * Returns null if the file doesn't exist yet (proxy still starting).
31
+ */
32
+ function getProxyConfig() {
33
+ if (configLoaded && proxyConfig) return proxyConfig;
34
+
35
+ // Try env var first (most reliable)
36
+ const proxyUrl = process.env.CODEYAM_PROXY_URL;
37
+ const devServerUrl = process.env.CODEYAM_DEV_SERVER_URL;
38
+ if (proxyUrl && devServerUrl) {
39
+ proxyConfig = { proxyUrl, devServerUrl };
40
+ configLoaded = true;
41
+ return proxyConfig;
42
+ }
43
+
44
+ // Fall back to config file
45
+ try {
46
+ const cwd = process.cwd();
47
+ const configPath = path.join(cwd, '.codeyam', 'proxy-config.json');
48
+ if (fs.existsSync(configPath)) {
49
+ const raw = fs.readFileSync(configPath, 'utf-8');
50
+ proxyConfig = JSON.parse(raw);
51
+ configLoaded = true;
52
+ return proxyConfig;
53
+ }
54
+ } catch {
55
+ // File doesn't exist yet or is invalid — that's fine
56
+ }
57
+
58
+ return null;
59
+ }
60
+
61
+ // --- Scenario data for direct mock matching (SSR + external APIs) ---
62
+
63
+ let scenarioCache = { data: null, timestamp: 0 };
64
+ const SCENARIO_CACHE_TTL = 500;
65
+
66
+ /**
67
+ * Read the active scenario's mock data from disk, with brief caching.
68
+ * Returns null if no active scenario or data file is missing.
69
+ *
70
+ * For application/user scenarios (seed-based): only returns externalApis
71
+ * as routes. DB-backed routes are served by the real app from seeded data.
72
+ */
73
+ function readScenarioData() {
74
+ const now = Date.now();
75
+ if (scenarioCache.data !== null && now - scenarioCache.timestamp < SCENARIO_CACHE_TTL) {
76
+ return scenarioCache.data;
77
+ }
78
+
79
+ try {
80
+ const cwd = process.cwd();
81
+ const activePath = path.join(cwd, '.codeyam', 'active-scenario.json');
82
+ if (!fs.existsSync(activePath)) {
83
+ scenarioCache = { data: null, timestamp: now };
84
+ return null;
85
+ }
86
+
87
+ const active = JSON.parse(fs.readFileSync(activePath, 'utf-8'));
88
+ if (!active.scenarioId) {
89
+ scenarioCache = { data: null, timestamp: now };
90
+ return null;
91
+ }
92
+
93
+ const dataPath = path.join(cwd, '.codeyam', 'editor-scenarios', `${active.scenarioId}.json`);
94
+ if (!fs.existsSync(dataPath)) {
95
+ scenarioCache = { data: null, timestamp: now };
96
+ return null;
97
+ }
98
+
99
+ const rawData = JSON.parse(fs.readFileSync(dataPath, 'utf-8'));
100
+
101
+ // Type-aware: for seed-based scenarios, only intercept externalApis
102
+ const scenarioType = active.type || rawData.type || null;
103
+ let mockData;
104
+
105
+ if ((scenarioType === 'application' || scenarioType === 'user') && rawData.seed) {
106
+ if (rawData.externalApis && typeof rawData.externalApis === 'object') {
107
+ mockData = { routes: rawData.externalApis };
108
+ } else {
109
+ mockData = null;
110
+ }
111
+ } else {
112
+ mockData = rawData;
113
+ }
114
+
115
+ scenarioCache = { data: mockData, timestamp: now };
116
+ return mockData;
117
+ } catch {
118
+ scenarioCache = { data: null, timestamp: now };
119
+ return null;
120
+ }
121
+ }
122
+
123
+ /**
124
+ * Match a request URL against scenario mock data routes.
125
+ * Mirrors the logic in editorPreloadHelpers.ts matchScenarioRoute().
126
+ *
127
+ * Supports:
128
+ * - Path-only routes: "/api/drinks"
129
+ * - Full URL routes: "https://api.stripe.com/v1/charges"
130
+ * - Method-prefixed: "POST /api/drinks"
131
+ */
132
+ function matchScenarioRoute(requestUrl, method, scenarioData) {
133
+ const routes = scenarioData.routes;
134
+ if (!routes || typeof routes !== 'object') return null;
135
+
136
+ let pathname;
137
+ try {
138
+ pathname = new URL(requestUrl).pathname;
139
+ } catch {
140
+ pathname = requestUrl.split('?')[0];
141
+ }
142
+
143
+ const upperMethod = method.toUpperCase();
144
+
145
+ for (const [routeKey, routeValue] of Object.entries(routes)) {
146
+ if (!routeValue || typeof routeValue !== 'object') continue;
147
+
148
+ // Method-prefixed: "POST /api/drinks"
149
+ const spaceIdx = routeKey.indexOf(' ');
150
+ if (spaceIdx !== -1) {
151
+ const routeMethod = routeKey.slice(0, spaceIdx).toUpperCase();
152
+ const routePath = routeKey.slice(spaceIdx + 1);
153
+ if (routeMethod === upperMethod && routePath === pathname) {
154
+ return {
155
+ body: routeValue.body ?? routeValue,
156
+ status: typeof routeValue.status === 'number' ? routeValue.status : 200,
157
+ };
158
+ }
159
+ continue;
160
+ }
161
+
162
+ // Full URL: "https://api.stripe.com/v1/charges"
163
+ if (routeKey.startsWith('http://') || routeKey.startsWith('https://')) {
164
+ try {
165
+ const routeParsed = new URL(routeKey);
166
+ const reqParsed = new URL(requestUrl);
167
+ if (
168
+ routeParsed.hostname === reqParsed.hostname &&
169
+ routeParsed.port === reqParsed.port &&
170
+ routeParsed.pathname === reqParsed.pathname
171
+ ) {
172
+ return {
173
+ body: routeValue.body ?? routeValue,
174
+ status: typeof routeValue.status === 'number' ? routeValue.status : 200,
175
+ };
176
+ }
177
+ } catch {
178
+ // Invalid URL in route key — skip
179
+ }
180
+ continue;
181
+ }
182
+
183
+ // Path-only: "/api/drinks"
184
+ if (routeKey === pathname) {
185
+ return {
186
+ body: routeValue.body ?? routeValue,
187
+ status: typeof routeValue.status === 'number' ? routeValue.status : 200,
188
+ };
189
+ }
190
+ }
191
+
192
+ return null;
193
+ }
194
+
195
+ /**
196
+ * Create a mock http.ClientRequest that delivers a mock response.
197
+ * Used to intercept http.request/http.get calls for matched routes.
198
+ */
199
+ function createMockRequest(mockResult, callback) {
200
+ const body = JSON.stringify(mockResult.body);
201
+
202
+ const mockResponse = new Readable({
203
+ read() {
204
+ this.push(body);
205
+ this.push(null);
206
+ },
207
+ });
208
+ mockResponse.statusCode = mockResult.status;
209
+ mockResponse.statusMessage = 'OK';
210
+ mockResponse.headers = { 'content-type': 'application/json', 'x-codeyam-mock': 'preload' };
211
+ mockResponse.rawHeaders = ['content-type', 'application/json', 'x-codeyam-mock', 'preload'];
212
+
213
+ const mockReq = new EventEmitter();
214
+ mockReq.write = () => true;
215
+ mockReq.end = () => {
216
+ process.nextTick(() => {
217
+ if (callback) callback(mockResponse);
218
+ mockReq.emit('response', mockResponse);
219
+ });
220
+ };
221
+ mockReq.abort = () => {};
222
+ mockReq.destroy = () => {};
223
+ mockReq.setTimeout = () => mockReq;
224
+ mockReq.setNoDelay = () => {};
225
+ mockReq.setSocketKeepAlive = () => {};
226
+
227
+ return mockReq;
228
+ }
229
+
230
+ /**
231
+ * Check if a URL string targets the dev server and return the redirected URL.
232
+ */
233
+ function redirectUrl(urlStr, config) {
234
+ try {
235
+ const parsed = new URL(urlStr);
236
+ const dev = new URL(config.devServerUrl);
237
+ const proxy = new URL(config.proxyUrl);
238
+
239
+ if (parsed.hostname === dev.hostname && parsed.port === dev.port) {
240
+ parsed.hostname = proxy.hostname;
241
+ parsed.port = proxy.port;
242
+ parsed.protocol = proxy.protocol;
243
+ return parsed.toString();
244
+ }
245
+ } catch {
246
+ // Invalid URL — pass through
247
+ }
248
+ return urlStr;
249
+ }
250
+
251
+ /**
252
+ * Check if http.request options target the dev server and patch them.
253
+ */
254
+ function redirectOptions(options, config) {
255
+ const dev = new URL(config.devServerUrl);
256
+ const proxy = new URL(config.proxyUrl);
257
+ const devPort = parseInt(dev.port, 10);
258
+ const proxyPort = parseInt(proxy.port, 10);
259
+
260
+ if (options.hostname && parseInt(String(options.port), 10) === devPort && options.hostname === dev.hostname) {
261
+ return {
262
+ ...options,
263
+ hostname: proxy.hostname,
264
+ port: proxyPort,
265
+ headers: options.headers
266
+ ? { ...options.headers, host: `${proxy.hostname}:${proxyPort}` }
267
+ : options.headers,
268
+ };
269
+ }
270
+
271
+ if (options.host) {
272
+ const expectedHost = `${dev.hostname}:${devPort}`;
273
+ if (options.host === expectedHost) {
274
+ return {
275
+ ...options,
276
+ host: `${proxy.hostname}:${proxyPort}`,
277
+ };
278
+ }
279
+ }
280
+
281
+ return options;
282
+ }
283
+
284
+ // --- Patch global fetch ---
285
+
286
+ const originalFetch = globalThis.fetch;
287
+
288
+ if (originalFetch) {
289
+ globalThis.fetch = function patchedFetch(input, init) {
290
+ // Try direct mock matching first (handles both internal and external URLs)
291
+ const scenarioData = readScenarioData();
292
+ if (scenarioData) {
293
+ let url = '';
294
+ let method = (init?.method || 'GET').toUpperCase();
295
+
296
+ if (typeof input === 'string') {
297
+ url = input;
298
+ } else if (input instanceof URL) {
299
+ url = input.toString();
300
+ } else if (input instanceof Request) {
301
+ url = input.url;
302
+ method = input.method || method;
303
+ }
304
+
305
+ if (url) {
306
+ const match = matchScenarioRoute(url, method, scenarioData);
307
+ if (match) {
308
+ return Promise.resolve(
309
+ new Response(JSON.stringify(match.body), {
310
+ status: match.status,
311
+ headers: {
312
+ 'Content-Type': 'application/json',
313
+ 'X-CodeYam-Mock': 'preload',
314
+ },
315
+ }),
316
+ );
317
+ }
318
+ }
319
+ }
320
+
321
+ // Fall back to proxy redirect for dev-server-targeting requests
322
+ const config = getProxyConfig();
323
+ if (!config) return originalFetch.call(this, input, init);
324
+
325
+ if (typeof input === 'string') {
326
+ const redirected = redirectUrl(input, config);
327
+ if (redirected !== input) {
328
+ return originalFetch.call(this, redirected, init);
329
+ }
330
+ } else if (input instanceof URL) {
331
+ const redirected = redirectUrl(input.toString(), config);
332
+ if (redirected !== input.toString()) {
333
+ return originalFetch.call(this, redirected, init);
334
+ }
335
+ } else if (input instanceof Request) {
336
+ const redirected = redirectUrl(input.url, config);
337
+ if (redirected !== input.url) {
338
+ return originalFetch.call(this, new Request(redirected, input), init);
339
+ }
340
+ }
341
+
342
+ return originalFetch.call(this, input, init);
343
+ };
344
+ }
345
+
346
+ // --- Patch http.request and https.request ---
347
+
348
+ function patchModule(mod, protocol) {
349
+ const originalRequest = mod.request;
350
+ const originalGet = mod.get;
351
+
352
+ mod.request = function patchedRequest(urlOrOptions, optionsOrCallback, callback) {
353
+ // Try direct mock matching first (handles external API calls from SSR)
354
+ const scenarioData = readScenarioData();
355
+ if (scenarioData) {
356
+ let urlStr = '';
357
+ let method = 'GET';
358
+ let cb = typeof optionsOrCallback === 'function' ? optionsOrCallback : callback;
359
+
360
+ if (typeof urlOrOptions === 'string' || urlOrOptions instanceof URL) {
361
+ urlStr = typeof urlOrOptions === 'string' ? urlOrOptions : urlOrOptions.toString();
362
+ if (typeof optionsOrCallback === 'object' && optionsOrCallback !== null) {
363
+ method = optionsOrCallback.method || method;
364
+ }
365
+ } else if (urlOrOptions && typeof urlOrOptions === 'object') {
366
+ // Build URL from options
367
+ const hostname = urlOrOptions.hostname || urlOrOptions.host?.split(':')[0] || 'localhost';
368
+ const port = urlOrOptions.port || (protocol === 'https' ? 443 : 80);
369
+ const urlPath = urlOrOptions.path || '/';
370
+ urlStr = `${protocol}://${hostname}:${port}${urlPath}`;
371
+ method = urlOrOptions.method || method;
372
+ cb = typeof optionsOrCallback === 'function' ? optionsOrCallback : callback;
373
+ }
374
+
375
+ if (urlStr) {
376
+ const match = matchScenarioRoute(urlStr, method, scenarioData);
377
+ if (match) {
378
+ return createMockRequest(match, cb);
379
+ }
380
+ }
381
+ }
382
+
383
+ // Fall back to proxy redirect for dev-server-targeting requests
384
+ const config = getProxyConfig();
385
+ if (!config) return originalRequest.call(this, urlOrOptions, optionsOrCallback, callback);
386
+
387
+ // http.request(url, options, callback)
388
+ if (typeof urlOrOptions === 'string' || urlOrOptions instanceof URL) {
389
+ const urlStr = typeof urlOrOptions === 'string' ? urlOrOptions : urlOrOptions.toString();
390
+ const redirected = redirectUrl(urlStr, config);
391
+ if (redirected !== urlStr) {
392
+ // Redirect to proxy — force http since proxy is always http
393
+ return http.request.call(http, redirected, optionsOrCallback, callback);
394
+ }
395
+ return originalRequest.call(this, urlOrOptions, optionsOrCallback, callback);
396
+ }
397
+
398
+ // http.request(options, callback)
399
+ const redirected = redirectOptions(urlOrOptions, config);
400
+ if (redirected !== urlOrOptions) {
401
+ return http.request.call(http, redirected, optionsOrCallback);
402
+ }
403
+ return originalRequest.call(this, urlOrOptions, optionsOrCallback, callback);
404
+ };
405
+
406
+ mod.get = function patchedGet(urlOrOptions, optionsOrCallback, callback) {
407
+ const req = mod.request(urlOrOptions, optionsOrCallback, callback);
408
+ req.end();
409
+ return req;
410
+ };
411
+ }
412
+
413
+ patchModule(http, 'http');
414
+ patchModule(https, 'https');
@@ -7,7 +7,90 @@
7
7
  * Args: { url, outputPath, viewportWidth?, viewportHeight? }
8
8
  */
9
9
 
10
- import { chromium } from 'playwright';
10
+ import { chromium, Page } from 'playwright';
11
+
12
+ /**
13
+ * Wait until DOM mutations stop for `quietMs`, or until `maxWaitMs` elapsed.
14
+ * Uses MutationObserver to detect when React has finished rendering,
15
+ * including data-driven re-renders from useEffect fetches.
16
+ *
17
+ * Same pattern used in takeElementScreenshot.ts (background package).
18
+ *
19
+ * Uses string-based evaluate to avoid tsx/esbuild __name decorator issues
20
+ * when the function is serialized for browser execution.
21
+ */
22
+ async function waitForDomIdle(
23
+ page: Page,
24
+ quietMs: number,
25
+ maxWaitMs: number,
26
+ ): Promise<void> {
27
+ await page.evaluate(`
28
+ new Promise(function(resolve) {
29
+ var timer;
30
+ var startTime = Date.now();
31
+
32
+ function finish() {
33
+ clearTimeout(timer);
34
+ observer.disconnect();
35
+ resolve();
36
+ }
37
+
38
+ function reset() {
39
+ clearTimeout(timer);
40
+ if (Date.now() - startTime >= ${maxWaitMs}) { finish(); return; }
41
+ timer = setTimeout(finish, ${quietMs});
42
+ }
43
+
44
+ var observer = new MutationObserver(reset);
45
+ observer.observe(document, {
46
+ childList: true,
47
+ subtree: true,
48
+ attributes: true
49
+ });
50
+
51
+ setTimeout(finish, ${maxWaitMs});
52
+ reset();
53
+ })
54
+ `);
55
+ }
56
+
57
+ /**
58
+ * Stabilize the page before taking a screenshot.
59
+ *
60
+ * Handles client-side rendered content (React useEffect + fetch pattern):
61
+ * 1. Wait for DOM to settle after initial hydration
62
+ * 2. Wait for any network requests triggered by client JS (useEffect fetches)
63
+ * 3. Wait for DOM to settle again after data-driven re-renders
64
+ * 4. Wait for web fonts to load
65
+ */
66
+ async function stabilizePage(page: Page): Promise<void> {
67
+ // 1. Wait for React hydration / initial client rendering to settle
68
+ await waitForDomIdle(page, DOM_IDLE_QUIET_MS, DOM_IDLE_MAX_WAIT_MS);
69
+
70
+ // 2. Wait for any network requests triggered by client-side JS
71
+ // (e.g. useEffect → fetch('/api/data')). This catches in-flight requests
72
+ // that started during or after hydration.
73
+ try {
74
+ await page.waitForLoadState('networkidle', {
75
+ timeout: POST_LOAD_NETWORK_TIMEOUT_MS,
76
+ });
77
+ } catch {
78
+ // Timeout is OK — some pages have persistent connections (WebSocket, SSE)
79
+ }
80
+
81
+ // 3. Wait for data-driven re-renders to settle
82
+ await waitForDomIdle(page, DOM_IDLE_QUIET_MS, DOM_IDLE_MAX_WAIT_MS);
83
+
84
+ // 4. Wait for web fonts (string-based to avoid tsx __name decorator issues)
85
+ try {
86
+ await page.waitForFunction(
87
+ `document.fonts ? document.fonts.status === 'loaded' : true`,
88
+ { timeout: FONTS_TIMEOUT_MS },
89
+ );
90
+ } catch {
91
+ // Font loading timeout — continue anyway
92
+ }
93
+ }
11
94
 
12
95
  interface CaptureArgs {
13
96
  url: string;
@@ -21,7 +104,10 @@ interface CaptureArgs {
21
104
 
22
105
  const MAX_RETRIES = 2;
23
106
  const GOTO_TIMEOUT_MS = 15_000;
24
- const SETTLE_DELAY_MS = 500;
107
+ const DOM_IDLE_QUIET_MS = 500;
108
+ const DOM_IDLE_MAX_WAIT_MS = 5_000;
109
+ const POST_LOAD_NETWORK_TIMEOUT_MS = 5_000;
110
+ const FONTS_TIMEOUT_MS = 5_000;
25
111
 
26
112
  async function main() {
27
113
  const args = process.argv.slice(2);
@@ -84,8 +170,12 @@ async function main() {
84
170
  );
85
171
  }
86
172
 
87
- // Brief settle time for any client-side rendering/animations
88
- await page.waitForTimeout(SETTLE_DELAY_MS);
173
+ // Wait for client-side rendering to complete (React hydration,
174
+ // useEffect data fetches, font loading, etc.)
175
+ await stabilizePage(page);
176
+
177
+ const pageTitle = await page.title();
178
+ console.log(`[JournalCapture] Page title: ${pageTitle}`);
89
179
 
90
180
  if (selector) {
91
181
  // Element-level screenshot — captures just the wrapper element
@@ -199,11 +199,13 @@ async function checkPreviewHealth(url) {
199
199
  };
200
200
  }
201
201
  }
202
- app.post('/api/dev-mode-refresh', async (_req, res) => {
202
+ // Unified preview control — refresh, navigate, switch scenario, or any combination.
203
+ // Handles log clearing, HMR settle, SSR health check, scenario switching, and navigation.
204
+ app.post('/api/dev-mode-preview', express.json(), async (req, res) => {
205
+ const { scenarioSlug, scenarioId, path: navPath } = req.body || {};
203
206
  let sessionsNotified = 0;
204
207
  let logCleared = false;
205
- let previewUrl = null;
206
- // Read config and resolve log path
208
+ // 1. Read config and resolve log path
207
209
  let logPath = null;
208
210
  try {
209
211
  const configPath = path.join(process.cwd(), '.codeyam', 'config.json');
@@ -215,19 +217,69 @@ app.post('/api/dev-mode-refresh', async (_req, res) => {
215
217
  catch {
216
218
  // Config not available — not critical
217
219
  }
218
- // Extract preview URL from log BEFORE clearing it
220
+ // 2. Extract preview URL from log BEFORE clearing it
221
+ let previewUrl = null;
219
222
  if (logPath && fs.existsSync(logPath)) {
220
223
  previewUrl = getPreviewUrl(logPath);
221
224
  }
222
- // Broadcast WebSocket refresh to browser (iframe starts reloading)
225
+ // Fall back to cached URL if log didn't have it
226
+ if (!previewUrl)
227
+ previewUrl = cachedPreviewUrl;
228
+ // 3. Switch scenario if provided (accepts scenarioId alone or scenarioSlug+scenarioId)
229
+ const effectiveScenarioId = scenarioId || null;
230
+ let effectiveSlug = scenarioSlug || null;
231
+ let scenarioUrl = null;
232
+ // Look up the scenario's URL from the database so we can navigate the preview
233
+ if (effectiveScenarioId && !navPath) {
234
+ try {
235
+ const { getDatabase } = await import('../../../packages/database/index.js');
236
+ const db = getDatabase();
237
+ const row = await db
238
+ .selectFrom('editor_scenarios')
239
+ .select(['url'])
240
+ .where('id', '=', effectiveScenarioId)
241
+ .executeTakeFirst();
242
+ if (row?.url) {
243
+ scenarioUrl = row.url;
244
+ }
245
+ }
246
+ catch {
247
+ // DB not available — non-critical
248
+ }
249
+ }
250
+ // Switch active scenario using the shared logic that handles type detection,
251
+ // active-scenario.json writes, and seed adapter execution for app/user scenarios.
252
+ if (effectiveScenarioId) {
253
+ try {
254
+ const { switchActiveScenario } = await import('../utils/editorScenarioSwitch.js');
255
+ const projectRoot = process.env.CODEYAM_ROOT_PATH || process.cwd();
256
+ const switchResult = await switchActiveScenario({
257
+ scenarioId: effectiveScenarioId,
258
+ scenarioSlug: effectiveSlug || undefined,
259
+ projectRoot,
260
+ });
261
+ effectiveSlug = switchResult.scenarioSlug;
262
+ // Invalidate proxy cache so it picks up new scenario data
263
+ const { invalidateScenarioCache } = await import('./editorProxy.js');
264
+ invalidateScenarioCache();
265
+ }
266
+ catch {
267
+ // Scenario switch failed — not critical, continue with refresh
268
+ }
269
+ }
270
+ // 4. Broadcast WebSocket refresh to browser (iframe starts reloading)
271
+ // Use explicit path, or fall back to scenario URL from DB, so the preview
272
+ // navigates to the correct page (e.g. /drinks/1 for a detail page scenario).
223
273
  try {
224
274
  const { broadcastPreviewRefresh } = await import('./terminalServer.js');
225
- sessionsNotified = broadcastPreviewRefresh();
275
+ const { resolvePreviewNavPath } = await import('../utils/editorScenarios.js');
276
+ const effectivePath = resolvePreviewNavPath(navPath, scenarioUrl);
277
+ sessionsNotified = broadcastPreviewRefresh(effectivePath, effectiveScenarioId);
226
278
  }
227
279
  catch {
228
280
  // Terminal server not loaded yet — ignore
229
281
  }
230
- // Clear the server log so post-refresh log reads only show fresh output
282
+ // 5. Clear the server log so post-refresh log reads only show fresh output
231
283
  if (logPath && fs.existsSync(logPath)) {
232
284
  try {
233
285
  fs.writeFileSync(logPath, '');
@@ -237,12 +289,23 @@ app.post('/api/dev-mode-refresh', async (_req, res) => {
237
289
  // Log file not writable — not critical
238
290
  }
239
291
  }
240
- // Wait for Vite HMR to settle and the page to re-render
292
+ // 6. Wait for HMR to settle and the page to re-render
241
293
  await new Promise((resolve) => setTimeout(resolve, 2000));
242
- // Fetch the preview URL to detect SSR errors
294
+ // 7. Compute the full URL (with navigation path if provided)
295
+ let fullUrl = previewUrl;
296
+ if (navPath && previewUrl) {
297
+ try {
298
+ fullUrl = new URL(navPath, previewUrl).href;
299
+ }
300
+ catch {
301
+ fullUrl = previewUrl;
302
+ }
303
+ }
304
+ // 8. Fetch the preview URL to detect SSR errors
243
305
  let preview = null;
244
- if (previewUrl) {
245
- preview = await checkPreviewHealth(previewUrl);
306
+ const healthCheckUrl = fullUrl || previewUrl;
307
+ if (healthCheckUrl) {
308
+ preview = await checkPreviewHealth(healthCheckUrl);
246
309
  // If unhealthy, write error to log so Claude can see it via tail
247
310
  if (!preview.healthy && preview.error && logPath) {
248
311
  try {
@@ -257,7 +320,25 @@ app.post('/api/dev-mode-refresh', async (_req, res) => {
257
320
  }
258
321
  }
259
322
  }
260
- res.json({ success: true, sessionsNotified, logCleared, preview });
323
+ res.json({
324
+ success: true,
325
+ sessionsNotified,
326
+ logCleared,
327
+ url: fullUrl || null,
328
+ preview,
329
+ });
330
+ });
331
+ // Show results panel in the editor Build tab — triggered by Claude at end of step 12.
332
+ app.post('/api/editor-show-results', async (_req, res) => {
333
+ const { broadcastShowResults } = await import('./terminalServer.js');
334
+ const sessionsNotified = broadcastShowResults();
335
+ res.json({ success: true, sessionsNotified });
336
+ });
337
+ // Hide results panel — triggered by Claude before making changes.
338
+ app.post('/api/editor-hide-results', async (_req, res) => {
339
+ const { broadcastHideResults } = await import('./terminalServer.js');
340
+ const sessionsNotified = broadcastHideResults();
341
+ res.json({ success: true, sessionsNotified });
261
342
  });
262
343
  // Handle Remix routes (API routes, page routes, etc.)
263
344
  if (process.env.NODE_ENV === 'development') {