@codeyam/codeyam-cli 0.1.0-staging.2ea44f6 → 0.1.0-staging.30dc541

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 (410) 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 +3 -3
  4. package/analyzer-template/packages/ai/package.json +1 -1
  5. package/analyzer-template/packages/aws/package.json +1 -1
  6. package/analyzer-template/packages/database/package.json +1 -1
  7. package/analyzer-template/packages/database/src/lib/kysely/tables/editorScenariosTable.ts +99 -0
  8. package/analyzer-template/packages/database/src/lib/loadEntities.ts +0 -6
  9. package/analyzer-template/packages/database/src/lib/updateCommitMetadata.ts +0 -65
  10. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/editorScenariosTable.d.ts +8 -0
  11. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/editorScenariosTable.d.ts.map +1 -1
  12. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/editorScenariosTable.js +101 -0
  13. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/editorScenariosTable.js.map +1 -1
  14. package/analyzer-template/packages/github/dist/database/src/lib/loadEntities.d.ts.map +1 -1
  15. package/analyzer-template/packages/github/dist/database/src/lib/loadEntities.js +0 -6
  16. package/analyzer-template/packages/github/dist/database/src/lib/loadEntities.js.map +1 -1
  17. package/analyzer-template/packages/github/dist/database/src/lib/updateCommitMetadata.d.ts.map +1 -1
  18. package/analyzer-template/packages/github/dist/database/src/lib/updateCommitMetadata.js +0 -25
  19. package/analyzer-template/packages/github/dist/database/src/lib/updateCommitMetadata.js.map +1 -1
  20. package/analyzer-template/packages/github/dist/types/src/enums/ProjectFramework.d.ts +2 -0
  21. package/analyzer-template/packages/github/dist/types/src/enums/ProjectFramework.d.ts.map +1 -1
  22. package/analyzer-template/packages/github/dist/types/src/enums/ProjectFramework.js +2 -0
  23. package/analyzer-template/packages/github/dist/types/src/enums/ProjectFramework.js.map +1 -1
  24. package/analyzer-template/packages/types/src/enums/ProjectFramework.ts +2 -0
  25. package/analyzer-template/packages/ui-components/package.json +1 -1
  26. package/analyzer-template/packages/utils/dist/types/src/enums/ProjectFramework.d.ts +2 -0
  27. package/analyzer-template/packages/utils/dist/types/src/enums/ProjectFramework.d.ts.map +1 -1
  28. package/analyzer-template/packages/utils/dist/types/src/enums/ProjectFramework.js +2 -0
  29. package/analyzer-template/packages/utils/dist/types/src/enums/ProjectFramework.js.map +1 -1
  30. package/codeyam-cli/src/cli.js +24 -0
  31. package/codeyam-cli/src/cli.js.map +1 -1
  32. package/codeyam-cli/src/commands/__tests__/editor.isolateArgs.test.js +51 -0
  33. package/codeyam-cli/src/commands/__tests__/editor.isolateArgs.test.js.map +1 -0
  34. package/codeyam-cli/src/commands/__tests__/editor.stepDispatch.test.js +56 -0
  35. package/codeyam-cli/src/commands/__tests__/editor.stepDispatch.test.js.map +1 -0
  36. package/codeyam-cli/src/commands/__tests__/init.gitignore.test.js +101 -47
  37. package/codeyam-cli/src/commands/__tests__/init.gitignore.test.js.map +1 -1
  38. package/codeyam-cli/src/commands/editor.js +3077 -509
  39. package/codeyam-cli/src/commands/editor.js.map +1 -1
  40. package/codeyam-cli/src/commands/editorIsolateArgs.js +25 -0
  41. package/codeyam-cli/src/commands/editorIsolateArgs.js.map +1 -0
  42. package/codeyam-cli/src/commands/init.js +69 -34
  43. package/codeyam-cli/src/commands/init.js.map +1 -1
  44. package/codeyam-cli/src/commands/telemetry.js +37 -0
  45. package/codeyam-cli/src/commands/telemetry.js.map +1 -0
  46. package/codeyam-cli/src/data/techStacks.js +77 -0
  47. package/codeyam-cli/src/data/techStacks.js.map +1 -0
  48. package/codeyam-cli/src/utils/__tests__/analyzerFinalization.test.js +173 -0
  49. package/codeyam-cli/src/utils/__tests__/analyzerFinalization.test.js.map +1 -0
  50. package/codeyam-cli/src/utils/__tests__/backgroundServer.test.js +46 -0
  51. package/codeyam-cli/src/utils/__tests__/backgroundServer.test.js.map +1 -0
  52. package/codeyam-cli/src/utils/__tests__/editorApi.test.js +18 -8
  53. package/codeyam-cli/src/utils/__tests__/editorApi.test.js.map +1 -1
  54. package/codeyam-cli/src/utils/__tests__/editorAudit.test.js +2201 -1
  55. package/codeyam-cli/src/utils/__tests__/editorAudit.test.js.map +1 -1
  56. package/codeyam-cli/src/utils/__tests__/editorBroadcastViewport.test.js +76 -0
  57. package/codeyam-cli/src/utils/__tests__/editorBroadcastViewport.test.js.map +1 -0
  58. package/codeyam-cli/src/utils/__tests__/editorCaptureScenarioSeeding.test.js +137 -0
  59. package/codeyam-cli/src/utils/__tests__/editorCaptureScenarioSeeding.test.js.map +1 -0
  60. package/codeyam-cli/src/utils/__tests__/editorDeleteScenario.test.js +100 -0
  61. package/codeyam-cli/src/utils/__tests__/editorDeleteScenario.test.js.map +1 -0
  62. package/codeyam-cli/src/utils/__tests__/editorDevServer.test.js +152 -3
  63. package/codeyam-cli/src/utils/__tests__/editorDevServer.test.js.map +1 -1
  64. package/codeyam-cli/src/utils/__tests__/editorEntityChangeStatus.test.js +76 -3
  65. package/codeyam-cli/src/utils/__tests__/editorEntityChangeStatus.test.js.map +1 -1
  66. package/codeyam-cli/src/utils/__tests__/editorEntityHelpers.test.js +381 -0
  67. package/codeyam-cli/src/utils/__tests__/editorEntityHelpers.test.js.map +1 -0
  68. package/codeyam-cli/src/utils/__tests__/editorGuardMiddleware.test.js +67 -0
  69. package/codeyam-cli/src/utils/__tests__/editorGuardMiddleware.test.js.map +1 -0
  70. package/codeyam-cli/src/utils/__tests__/editorImageVerifier.test.js +140 -12
  71. package/codeyam-cli/src/utils/__tests__/editorImageVerifier.test.js.map +1 -1
  72. package/codeyam-cli/src/utils/__tests__/editorJournal.test.js +238 -2
  73. package/codeyam-cli/src/utils/__tests__/editorJournal.test.js.map +1 -1
  74. package/codeyam-cli/src/utils/__tests__/editorLoaderHelpers.test.js +202 -1
  75. package/codeyam-cli/src/utils/__tests__/editorLoaderHelpers.test.js.map +1 -1
  76. package/codeyam-cli/src/utils/__tests__/editorMigration.test.js +435 -0
  77. package/codeyam-cli/src/utils/__tests__/editorMigration.test.js.map +1 -0
  78. package/codeyam-cli/src/utils/__tests__/editorPreview.test.js +191 -5
  79. package/codeyam-cli/src/utils/__tests__/editorPreview.test.js.map +1 -1
  80. package/codeyam-cli/src/utils/__tests__/editorProxySession.test.js +153 -0
  81. package/codeyam-cli/src/utils/__tests__/editorProxySession.test.js.map +1 -0
  82. package/codeyam-cli/src/utils/__tests__/editorScenarioLookup.test.js +139 -0
  83. package/codeyam-cli/src/utils/__tests__/editorScenarioLookup.test.js.map +1 -0
  84. package/codeyam-cli/src/utils/__tests__/editorScenarioSwitch.test.js +291 -0
  85. package/codeyam-cli/src/utils/__tests__/editorScenarioSwitch.test.js.map +1 -0
  86. package/codeyam-cli/src/utils/__tests__/editorScenarios.test.js +1437 -2
  87. package/codeyam-cli/src/utils/__tests__/editorScenarios.test.js.map +1 -1
  88. package/codeyam-cli/src/utils/__tests__/editorSeedAdapter.test.js +280 -0
  89. package/codeyam-cli/src/utils/__tests__/editorSeedAdapter.test.js.map +1 -0
  90. package/codeyam-cli/src/utils/__tests__/editorSeedAdapterPrismaValidation.test.js +143 -0
  91. package/codeyam-cli/src/utils/__tests__/editorSeedAdapterPrismaValidation.test.js.map +1 -0
  92. package/codeyam-cli/src/utils/__tests__/editorSessionFilter.test.js +66 -0
  93. package/codeyam-cli/src/utils/__tests__/editorSessionFilter.test.js.map +1 -0
  94. package/codeyam-cli/src/utils/__tests__/editorShouldRevalidate.test.js +53 -0
  95. package/codeyam-cli/src/utils/__tests__/editorShouldRevalidate.test.js.map +1 -0
  96. package/codeyam-cli/src/utils/__tests__/entityChangeStatus.test.js +641 -45
  97. package/codeyam-cli/src/utils/__tests__/entityChangeStatus.test.js.map +1 -1
  98. package/codeyam-cli/src/utils/__tests__/glossaryAdd.test.js +177 -0
  99. package/codeyam-cli/src/utils/__tests__/glossaryAdd.test.js.map +1 -0
  100. package/codeyam-cli/src/utils/__tests__/journalCaptureStabilization.test.js +122 -0
  101. package/codeyam-cli/src/utils/__tests__/journalCaptureStabilization.test.js.map +1 -0
  102. package/codeyam-cli/src/utils/__tests__/parseRegisterArg.test.js +129 -0
  103. package/codeyam-cli/src/utils/__tests__/parseRegisterArg.test.js.map +1 -0
  104. package/codeyam-cli/src/utils/__tests__/routePatternMatching.test.js +118 -0
  105. package/codeyam-cli/src/utils/__tests__/routePatternMatching.test.js.map +1 -0
  106. package/codeyam-cli/src/utils/__tests__/scenarioCoverage.test.js +284 -0
  107. package/codeyam-cli/src/utils/__tests__/scenarioCoverage.test.js.map +1 -0
  108. package/codeyam-cli/src/utils/__tests__/scenariosManifest.test.js +649 -223
  109. package/codeyam-cli/src/utils/__tests__/scenariosManifest.test.js.map +1 -1
  110. package/codeyam-cli/src/utils/__tests__/setupClaudeCodeSettings.test.js +14 -5
  111. package/codeyam-cli/src/utils/__tests__/setupClaudeCodeSettings.test.js.map +1 -1
  112. package/codeyam-cli/src/utils/__tests__/telemetry.test.js +159 -0
  113. package/codeyam-cli/src/utils/__tests__/telemetry.test.js.map +1 -0
  114. package/codeyam-cli/src/utils/__tests__/templateConsistency.test.js +51 -0
  115. package/codeyam-cli/src/utils/__tests__/templateConsistency.test.js.map +1 -0
  116. package/codeyam-cli/src/utils/__tests__/webappDetection.test.js +142 -0
  117. package/codeyam-cli/src/utils/__tests__/webappDetection.test.js.map +1 -0
  118. package/codeyam-cli/src/utils/analysisRunner.js +3 -1
  119. package/codeyam-cli/src/utils/analysisRunner.js.map +1 -1
  120. package/codeyam-cli/src/utils/analyzer.js +9 -0
  121. package/codeyam-cli/src/utils/analyzer.js.map +1 -1
  122. package/codeyam-cli/src/utils/analyzerFinalization.js +100 -0
  123. package/codeyam-cli/src/utils/analyzerFinalization.js.map +1 -0
  124. package/codeyam-cli/src/utils/backgroundServer.js +93 -17
  125. package/codeyam-cli/src/utils/backgroundServer.js.map +1 -1
  126. package/codeyam-cli/src/utils/database.js +37 -2
  127. package/codeyam-cli/src/utils/database.js.map +1 -1
  128. package/codeyam-cli/src/utils/editorApi.js +11 -5
  129. package/codeyam-cli/src/utils/editorApi.js.map +1 -1
  130. package/codeyam-cli/src/utils/editorAudit.js +410 -6
  131. package/codeyam-cli/src/utils/editorAudit.js.map +1 -1
  132. package/codeyam-cli/src/utils/editorBroadcastViewport.js +26 -0
  133. package/codeyam-cli/src/utils/editorBroadcastViewport.js.map +1 -0
  134. package/codeyam-cli/src/utils/editorDeleteScenario.js +67 -0
  135. package/codeyam-cli/src/utils/editorDeleteScenario.js.map +1 -0
  136. package/codeyam-cli/src/utils/editorDevServer.js +89 -1
  137. package/codeyam-cli/src/utils/editorDevServer.js.map +1 -1
  138. package/codeyam-cli/src/utils/editorEntityChangeStatus.js +13 -7
  139. package/codeyam-cli/src/utils/editorEntityChangeStatus.js.map +1 -1
  140. package/codeyam-cli/src/utils/editorEntityHelpers.js +144 -0
  141. package/codeyam-cli/src/utils/editorEntityHelpers.js.map +1 -0
  142. package/codeyam-cli/src/utils/editorGuard.js +36 -0
  143. package/codeyam-cli/src/utils/editorGuard.js.map +1 -0
  144. package/codeyam-cli/src/utils/editorImageVerifier.js +45 -10
  145. package/codeyam-cli/src/utils/editorImageVerifier.js.map +1 -1
  146. package/codeyam-cli/src/utils/editorJournal.js +78 -3
  147. package/codeyam-cli/src/utils/editorJournal.js.map +1 -1
  148. package/codeyam-cli/src/utils/editorLoaderHelpers.js +72 -1
  149. package/codeyam-cli/src/utils/editorLoaderHelpers.js.map +1 -1
  150. package/codeyam-cli/src/utils/editorMigration.js +224 -0
  151. package/codeyam-cli/src/utils/editorMigration.js.map +1 -0
  152. package/codeyam-cli/src/utils/editorPreview.js +43 -2
  153. package/codeyam-cli/src/utils/editorPreview.js.map +1 -1
  154. package/codeyam-cli/src/utils/editorRecapture.js +109 -0
  155. package/codeyam-cli/src/utils/editorRecapture.js.map +1 -0
  156. package/codeyam-cli/src/utils/editorScenarioSwitch.js +134 -0
  157. package/codeyam-cli/src/utils/editorScenarioSwitch.js.map +1 -0
  158. package/codeyam-cli/src/utils/editorScenarios.js +488 -0
  159. package/codeyam-cli/src/utils/editorScenarios.js.map +1 -1
  160. package/codeyam-cli/src/utils/editorSeedAdapter.js +422 -0
  161. package/codeyam-cli/src/utils/editorSeedAdapter.js.map +1 -0
  162. package/codeyam-cli/src/utils/editorShouldRevalidate.js +21 -0
  163. package/codeyam-cli/src/utils/editorShouldRevalidate.js.map +1 -0
  164. package/codeyam-cli/src/utils/entityChangeStatus.js +89 -21
  165. package/codeyam-cli/src/utils/entityChangeStatus.js.map +1 -1
  166. package/codeyam-cli/src/utils/entityChangeStatus.server.js +97 -8
  167. package/codeyam-cli/src/utils/entityChangeStatus.server.js.map +1 -1
  168. package/codeyam-cli/src/utils/fileWatcher.js +38 -0
  169. package/codeyam-cli/src/utils/fileWatcher.js.map +1 -1
  170. package/codeyam-cli/src/utils/glossaryAdd.js +74 -0
  171. package/codeyam-cli/src/utils/glossaryAdd.js.map +1 -0
  172. package/codeyam-cli/src/utils/install-skills.js +14 -0
  173. package/codeyam-cli/src/utils/install-skills.js.map +1 -1
  174. package/codeyam-cli/src/utils/parseRegisterArg.js +31 -0
  175. package/codeyam-cli/src/utils/parseRegisterArg.js.map +1 -0
  176. package/codeyam-cli/src/utils/progress.js +2 -2
  177. package/codeyam-cli/src/utils/progress.js.map +1 -1
  178. package/codeyam-cli/src/utils/routePatternMatching.js +129 -0
  179. package/codeyam-cli/src/utils/routePatternMatching.js.map +1 -0
  180. package/codeyam-cli/src/utils/scenarioCoverage.js +77 -0
  181. package/codeyam-cli/src/utils/scenarioCoverage.js.map +1 -0
  182. package/codeyam-cli/src/utils/scenariosManifest.js +269 -74
  183. package/codeyam-cli/src/utils/scenariosManifest.js.map +1 -1
  184. package/codeyam-cli/src/utils/serverState.js +30 -0
  185. package/codeyam-cli/src/utils/serverState.js.map +1 -1
  186. package/codeyam-cli/src/utils/setupClaudeCodeSettings.js +14 -5
  187. package/codeyam-cli/src/utils/setupClaudeCodeSettings.js.map +1 -1
  188. package/codeyam-cli/src/utils/simulationGateMiddleware.js +17 -1
  189. package/codeyam-cli/src/utils/simulationGateMiddleware.js.map +1 -1
  190. package/codeyam-cli/src/utils/slugUtils.js +25 -0
  191. package/codeyam-cli/src/utils/slugUtils.js.map +1 -0
  192. package/codeyam-cli/src/utils/syncMocksMiddleware.js +2 -2
  193. package/codeyam-cli/src/utils/syncMocksMiddleware.js.map +1 -1
  194. package/codeyam-cli/src/utils/telemetry.js +106 -0
  195. package/codeyam-cli/src/utils/telemetry.js.map +1 -0
  196. package/codeyam-cli/src/utils/telemetryMiddleware.js +22 -0
  197. package/codeyam-cli/src/utils/telemetryMiddleware.js.map +1 -0
  198. package/codeyam-cli/src/utils/webappDetection.js +21 -0
  199. package/codeyam-cli/src/utils/webappDetection.js.map +1 -1
  200. package/codeyam-cli/src/webserver/__tests__/buildPtyEnv.test.js +35 -0
  201. package/codeyam-cli/src/webserver/__tests__/buildPtyEnv.test.js.map +1 -0
  202. package/codeyam-cli/src/webserver/__tests__/clientErrors.test.js +80 -0
  203. package/codeyam-cli/src/webserver/__tests__/clientErrors.test.js.map +1 -0
  204. package/codeyam-cli/src/webserver/__tests__/editorProxy.test.js +628 -0
  205. package/codeyam-cli/src/webserver/__tests__/editorProxy.test.js.map +1 -0
  206. package/codeyam-cli/src/webserver/__tests__/idleDetector.test.js +228 -0
  207. package/codeyam-cli/src/webserver/__tests__/idleDetector.test.js.map +1 -0
  208. package/codeyam-cli/src/webserver/__tests__/stripClaudeCommand.test.js +79 -0
  209. package/codeyam-cli/src/webserver/__tests__/stripClaudeCommand.test.js.map +1 -0
  210. package/codeyam-cli/src/webserver/app/lib/clientErrors.js +71 -0
  211. package/codeyam-cli/src/webserver/app/lib/clientErrors.js.map +1 -0
  212. package/codeyam-cli/src/webserver/app/lib/git.js +3 -2
  213. package/codeyam-cli/src/webserver/app/lib/git.js.map +1 -1
  214. package/codeyam-cli/src/webserver/app/types/editor.js +8 -0
  215. package/codeyam-cli/src/webserver/app/types/editor.js.map +1 -0
  216. package/codeyam-cli/src/webserver/backgroundServer.js +60 -61
  217. package/codeyam-cli/src/webserver/backgroundServer.js.map +1 -1
  218. package/codeyam-cli/src/webserver/build/client/assets/CopyButton-CLe80MMu.js +1 -0
  219. package/codeyam-cli/src/webserver/build/client/assets/{EntityItem-C76mRRiF.js → EntityItem-Crt_KN_U.js} +5 -5
  220. package/codeyam-cli/src/webserver/build/client/assets/EntityTypeBadge-CQgyEGV-.js +1 -0
  221. package/codeyam-cli/src/webserver/build/client/assets/{EntityTypeIcon-CobE682z.js → EntityTypeIcon-CD7lGABo.js} +9 -9
  222. package/codeyam-cli/src/webserver/build/client/assets/InlineSpinner-CgTNOhnu.js +1 -0
  223. package/codeyam-cli/src/webserver/build/client/assets/InteractivePreview-CKeQT5Ty.js +25 -0
  224. package/codeyam-cli/src/webserver/build/client/assets/LibraryFunctionPreview-D3s1MFkb.js +3 -0
  225. package/codeyam-cli/src/webserver/build/client/assets/{LoadingDots-BU_OAEMP.js → LoadingDots-By5zI316.js} +1 -1
  226. package/codeyam-cli/src/webserver/build/client/assets/{LogViewer-ceAyBX-H.js → LogViewer-CM5zg40N.js} +3 -3
  227. package/codeyam-cli/src/webserver/build/client/assets/{ReportIssueModal-djPLI-WV.js → ReportIssueModal-C2PLkej3.js} +4 -4
  228. package/codeyam-cli/src/webserver/build/client/assets/SafeScreenshot-DanvyBPb.js +1 -0
  229. package/codeyam-cli/src/webserver/build/client/assets/{ScenarioViewer-ZlRKbhrq.js → ScenarioViewer-DUMfcNVK.js} +3 -3
  230. package/codeyam-cli/src/webserver/build/client/assets/Spinner-D0LgAaSa.js +34 -0
  231. package/codeyam-cli/src/webserver/build/client/assets/TruncatedFilePath-CK7-NaPZ.js +1 -0
  232. package/codeyam-cli/src/webserver/build/client/assets/ViewportInspectBar-BA_Ry-rs.js +1 -0
  233. package/codeyam-cli/src/webserver/build/client/assets/{_index-C96V0n15.js → _index-BAWd-Xjf.js} +4 -4
  234. package/codeyam-cli/src/webserver/build/client/assets/{activity.(_tab)-BpKzcsJz.js → activity.(_tab)-BOARiB-g.js} +8 -8
  235. package/codeyam-cli/src/webserver/build/client/assets/{addon-web-links-Duc5hnl7.js → addon-web-links-CHx25PAe.js} +1 -1
  236. package/codeyam-cli/src/webserver/build/client/assets/{agent-transcripts-D9hemwl6.js → agent-transcripts-Bg3e7q4S.js} +7 -7
  237. package/codeyam-cli/src/webserver/build/client/assets/api.editor-project-info-l0sNRNKZ.js +1 -0
  238. package/codeyam-cli/src/webserver/build/client/assets/api.editor-recapture-stale-l0sNRNKZ.js +1 -0
  239. package/codeyam-cli/src/webserver/build/client/assets/api.editor-rename-scenario-l0sNRNKZ.js +1 -0
  240. package/codeyam-cli/src/webserver/build/client/assets/api.editor-save-seed-state-l0sNRNKZ.js +1 -0
  241. package/codeyam-cli/src/webserver/build/client/assets/api.editor-scenario-coverage-l0sNRNKZ.js +1 -0
  242. package/codeyam-cli/src/webserver/build/client/assets/api.editor-scenario-prompt-l0sNRNKZ.js +1 -0
  243. package/codeyam-cli/src/webserver/build/client/assets/api.editor-session-l0sNRNKZ.js +1 -0
  244. package/codeyam-cli/src/webserver/build/client/assets/{book-open-D_nMCFmP.js → book-open-CL-lMgHh.js} +2 -2
  245. package/codeyam-cli/src/webserver/build/client/assets/{chevron-down-BH2h1Ea2.js → chevron-down-GmAjGS9-.js} +2 -2
  246. package/codeyam-cli/src/webserver/build/client/assets/chunk-JZWAC4HX-BAdwhyCx.js +43 -0
  247. package/codeyam-cli/src/webserver/build/client/assets/{circle-check-DyIKORY6.js → circle-check-DFcQkN5j.js} +2 -2
  248. package/codeyam-cli/src/webserver/build/client/assets/{copy-NDbZjXao.js → copy-C6iF61Xs.js} +3 -3
  249. package/codeyam-cli/src/webserver/build/client/assets/createLucideIcon-4ImjHTVC.js +41 -0
  250. package/codeyam-cli/src/webserver/build/client/assets/dev.empty-C8y4mmyv.js +1 -0
  251. package/codeyam-cli/src/webserver/build/client/assets/editor._tab-Gbk_i5Js.js +1 -0
  252. package/codeyam-cli/src/webserver/build/client/assets/editor.entity.(_sha)-CGzKlIHg.js +58 -0
  253. package/codeyam-cli/src/webserver/build/client/assets/editorPreview-oepecPae.js +41 -0
  254. package/codeyam-cli/src/webserver/build/client/assets/{entity._sha._-DItJnD8s.js → entity._sha._-Blfy9UlN.js} +3 -3
  255. package/codeyam-cli/src/webserver/build/client/assets/entity._sha.scenarios._scenarioId.dev-KTQuL0aj.js +6 -0
  256. package/codeyam-cli/src/webserver/build/client/assets/entity._sha.scenarios._scenarioId.fullscreen-C6eeL24i.js +6 -0
  257. package/codeyam-cli/src/webserver/build/client/assets/entity._sha_.create-scenario-DQM8E7L4.js +6 -0
  258. package/codeyam-cli/src/webserver/build/client/assets/{entity._sha_.edit._scenarioId-BMvVHNXU.js → entity._sha_.edit._scenarioId-CAoXLsQr.js} +2 -2
  259. package/codeyam-cli/src/webserver/build/client/assets/{entry.client-DTvKq3TY.js → entry.client-SuW9syRS.js} +6 -6
  260. package/codeyam-cli/src/webserver/build/client/assets/fileTableUtils-Daa96Fr1.js +1 -0
  261. package/codeyam-cli/src/webserver/build/client/assets/files-D-xGrg29.js +1 -0
  262. package/codeyam-cli/src/webserver/build/client/assets/git-Bq_fbXP5.js +1 -0
  263. package/codeyam-cli/src/webserver/build/client/assets/globals-Yn9W3zp3.css +1 -0
  264. package/codeyam-cli/src/webserver/build/client/assets/{index-BcvgDzbZ.js → index-Bp1l4hSv.js} +1 -1
  265. package/codeyam-cli/src/webserver/build/client/assets/{index-10oVnAAH.js → index-CWV9XZiG.js} +1 -1
  266. package/codeyam-cli/src/webserver/build/client/assets/{index-yHOVb4rc.js → index-DE3jI_dv.js} +1 -1
  267. package/codeyam-cli/src/webserver/build/client/assets/jsx-runtime-D_zvdyIk.js +9 -0
  268. package/codeyam-cli/src/webserver/build/client/assets/labs-B_IX45ih.js +1 -0
  269. package/codeyam-cli/src/webserver/build/client/assets/{loader-circle-BAXYRVEO.js → loader-circle-De-7qQ2u.js} +2 -2
  270. package/codeyam-cli/src/webserver/build/client/assets/manifest-2ef99f38.js +1 -0
  271. package/codeyam-cli/src/webserver/build/client/assets/memory-Cx2xEx7s.js +101 -0
  272. package/codeyam-cli/src/webserver/build/client/assets/{pause-DTAcYxBt.js → pause-CFxEKL1u.js} +3 -3
  273. package/codeyam-cli/src/webserver/build/client/assets/root-BxUQigda.js +67 -0
  274. package/codeyam-cli/src/webserver/build/client/assets/{search-fKo7v0Zo.js → search-BdBb5aqc.js} +2 -2
  275. package/codeyam-cli/src/webserver/build/client/assets/settings-DdE-Untf.js +1 -0
  276. package/codeyam-cli/src/webserver/build/client/assets/simulations-DSCdE99u.js +1 -0
  277. package/codeyam-cli/src/webserver/build/client/assets/{terminal-BG4heKCG.js → terminal-CrplD4b1.js} +3 -3
  278. package/codeyam-cli/src/webserver/build/client/assets/{triangle-alert-DtSmdtM4.js → triangle-alert-DqJ0j69l.js} +2 -2
  279. package/codeyam-cli/src/webserver/build/client/assets/useCustomSizes-DhXHbEjP.js +1 -0
  280. package/codeyam-cli/src/webserver/build/client/assets/{useLastLogLine-C14nCb1q.js → useLastLogLine-BNd5hYuW.js} +1 -1
  281. package/codeyam-cli/src/webserver/build/client/assets/useReportContext-Cy5Qg_UR.js +1 -0
  282. package/codeyam-cli/src/webserver/build/client/assets/useToast-5HR2j9ZE.js +1 -0
  283. package/codeyam-cli/src/webserver/build/client/sound-test.html +98 -0
  284. package/codeyam-cli/src/webserver/build/server/assets/analysisRunner-BPmOG9bE.js +13 -0
  285. package/codeyam-cli/src/webserver/build/server/assets/index-Cd-ufawF.js +1 -0
  286. package/codeyam-cli/src/webserver/build/server/assets/init-CzeBGOto.js +10 -0
  287. package/codeyam-cli/src/webserver/build/server/assets/progress-CHTtrxFG.js +1 -0
  288. package/codeyam-cli/src/webserver/build/server/assets/server-build-Dht7CKXY.js +552 -0
  289. package/codeyam-cli/src/webserver/build/server/index.js +1 -1
  290. package/codeyam-cli/src/webserver/build-info.json +5 -5
  291. package/codeyam-cli/src/webserver/editorProxy.js +586 -17
  292. package/codeyam-cli/src/webserver/editorProxy.js.map +1 -1
  293. package/codeyam-cli/src/webserver/idleDetector.js +106 -0
  294. package/codeyam-cli/src/webserver/idleDetector.js.map +1 -0
  295. package/codeyam-cli/src/webserver/mockStateEvents.js +28 -0
  296. package/codeyam-cli/src/webserver/mockStateEvents.js.map +1 -0
  297. package/codeyam-cli/src/webserver/public/sound-test.html +98 -0
  298. package/codeyam-cli/src/webserver/scripts/codeyam-preload.mjs +21 -3
  299. package/codeyam-cli/src/webserver/scripts/journalCapture.ts +130 -4
  300. package/codeyam-cli/src/webserver/server.js +100 -34
  301. package/codeyam-cli/src/webserver/server.js.map +1 -1
  302. package/codeyam-cli/src/webserver/terminalServer.js +242 -48
  303. package/codeyam-cli/src/webserver/terminalServer.js.map +1 -1
  304. package/codeyam-cli/templates/__tests__/editor-step-hook.prompt-capture.test.ts +118 -0
  305. package/codeyam-cli/templates/chrome-extension-react/EXTENSION_SETUP.md +75 -0
  306. package/codeyam-cli/templates/chrome-extension-react/README.md +46 -0
  307. package/codeyam-cli/templates/chrome-extension-react/gitignore +15 -0
  308. package/codeyam-cli/templates/chrome-extension-react/index.html +12 -0
  309. package/codeyam-cli/templates/chrome-extension-react/package.json +27 -0
  310. package/codeyam-cli/templates/chrome-extension-react/popup.html +12 -0
  311. package/codeyam-cli/templates/chrome-extension-react/public/manifest.json +15 -0
  312. package/codeyam-cli/templates/chrome-extension-react/src/background/service-worker.ts +7 -0
  313. package/codeyam-cli/templates/chrome-extension-react/src/globals.css +6 -0
  314. package/codeyam-cli/templates/chrome-extension-react/src/lib/storage.ts +37 -0
  315. package/codeyam-cli/templates/chrome-extension-react/src/popup/App.tsx +12 -0
  316. package/codeyam-cli/templates/chrome-extension-react/src/popup/main.tsx +10 -0
  317. package/codeyam-cli/templates/chrome-extension-react/tsconfig.json +24 -0
  318. package/codeyam-cli/templates/chrome-extension-react/vite.config.ts +41 -0
  319. package/codeyam-cli/templates/codeyam-editor-claude.md +86 -5
  320. package/codeyam-cli/templates/codeyam-editor-reference.md +214 -0
  321. package/codeyam-cli/templates/editor-step-hook.py +193 -54
  322. package/codeyam-cli/templates/expo-react-native/MOBILE_SETUP.md +89 -0
  323. package/codeyam-cli/templates/expo-react-native/README.md +41 -0
  324. package/codeyam-cli/templates/expo-react-native/app/(tabs)/_layout.tsx +33 -0
  325. package/codeyam-cli/templates/expo-react-native/app/(tabs)/index.tsx +12 -0
  326. package/codeyam-cli/templates/expo-react-native/app/(tabs)/settings.tsx +12 -0
  327. package/codeyam-cli/templates/expo-react-native/app/_layout.tsx +12 -0
  328. package/codeyam-cli/templates/expo-react-native/app.json +18 -0
  329. package/codeyam-cli/templates/expo-react-native/babel.config.js +9 -0
  330. package/codeyam-cli/templates/expo-react-native/gitignore +12 -0
  331. package/codeyam-cli/templates/expo-react-native/global.css +3 -0
  332. package/codeyam-cli/templates/expo-react-native/lib/storage.ts +32 -0
  333. package/codeyam-cli/templates/expo-react-native/metro.config.js +6 -0
  334. package/codeyam-cli/templates/expo-react-native/nativewind-env.d.ts +1 -0
  335. package/codeyam-cli/templates/expo-react-native/package.json +38 -0
  336. package/codeyam-cli/templates/expo-react-native/tailwind.config.js +10 -0
  337. package/codeyam-cli/templates/expo-react-native/tsconfig.json +10 -0
  338. package/codeyam-cli/templates/nextjs-prisma-sqlite/AUTH_PATTERNS.md +308 -0
  339. package/codeyam-cli/templates/nextjs-prisma-sqlite/AUTH_UPGRADE.md +304 -0
  340. package/codeyam-cli/templates/nextjs-prisma-sqlite/DATABASE.md +126 -0
  341. package/codeyam-cli/templates/nextjs-prisma-sqlite/FEATURE_PATTERNS.md +37 -0
  342. package/codeyam-cli/templates/nextjs-prisma-sqlite/README.md +53 -0
  343. package/codeyam-cli/templates/nextjs-prisma-sqlite/app/lib/prisma.ts +9 -4
  344. package/codeyam-cli/templates/nextjs-prisma-sqlite/env +4 -0
  345. package/codeyam-cli/templates/nextjs-prisma-sqlite/gitignore +1 -0
  346. package/codeyam-cli/templates/nextjs-prisma-sqlite/package.json +2 -1
  347. package/codeyam-cli/templates/nextjs-prisma-sqlite/prisma/seed.ts +4 -1
  348. package/codeyam-cli/templates/nextjs-prisma-sqlite/seed-adapter.ts +127 -0
  349. package/codeyam-cli/templates/nextjs-prisma-supabase/README.md +52 -0
  350. package/codeyam-cli/templates/{nextjs-prisma-sqlite/PRISMA_SETUP.md → nextjs-prisma-supabase/SUPABASE_SETUP.md} +37 -17
  351. package/codeyam-cli/templates/nextjs-prisma-supabase/app/api/todos/route.ts +17 -0
  352. package/codeyam-cli/templates/nextjs-prisma-supabase/app/globals.css +26 -0
  353. package/codeyam-cli/templates/nextjs-prisma-supabase/app/layout.tsx +34 -0
  354. package/codeyam-cli/templates/nextjs-prisma-supabase/app/lib/prisma.ts +20 -0
  355. package/codeyam-cli/templates/nextjs-prisma-supabase/app/lib/supabase.ts +12 -0
  356. package/codeyam-cli/templates/nextjs-prisma-supabase/app/page.tsx +10 -0
  357. package/codeyam-cli/templates/nextjs-prisma-supabase/env +9 -0
  358. package/codeyam-cli/templates/nextjs-prisma-supabase/eslint.config.mjs +11 -0
  359. package/codeyam-cli/templates/nextjs-prisma-supabase/gitignore +40 -0
  360. package/codeyam-cli/templates/nextjs-prisma-supabase/next.config.ts +11 -0
  361. package/codeyam-cli/templates/nextjs-prisma-supabase/package.json +37 -0
  362. package/codeyam-cli/templates/nextjs-prisma-supabase/postcss.config.mjs +7 -0
  363. package/codeyam-cli/templates/nextjs-prisma-supabase/prisma/schema.prisma +27 -0
  364. package/codeyam-cli/templates/nextjs-prisma-supabase/prisma/seed.ts +39 -0
  365. package/codeyam-cli/templates/nextjs-prisma-supabase/prisma.config.ts +12 -0
  366. package/codeyam-cli/templates/nextjs-prisma-supabase/tsconfig.json +34 -0
  367. package/codeyam-cli/templates/seed-adapters/supabase.ts +282 -0
  368. package/codeyam-cli/templates/skills/codeyam-dev-mode/SKILL.md +1 -1
  369. package/codeyam-cli/templates/skills/codeyam-editor/SKILL.md +90 -9
  370. package/package.json +2 -1
  371. package/packages/database/src/lib/kysely/tables/editorScenariosTable.js +101 -0
  372. package/packages/database/src/lib/kysely/tables/editorScenariosTable.js.map +1 -1
  373. package/packages/database/src/lib/loadEntities.js +0 -6
  374. package/packages/database/src/lib/loadEntities.js.map +1 -1
  375. package/packages/database/src/lib/updateCommitMetadata.js +0 -25
  376. package/packages/database/src/lib/updateCommitMetadata.js.map +1 -1
  377. package/packages/types/src/enums/ProjectFramework.js +2 -0
  378. package/packages/types/src/enums/ProjectFramework.js.map +1 -1
  379. package/codeyam-cli/src/webserver/build/client/assets/CopyButton-DmJveP3T.js +0 -1
  380. package/codeyam-cli/src/webserver/build/client/assets/EntityTypeBadge-g3saevPb.js +0 -1
  381. package/codeyam-cli/src/webserver/build/client/assets/InlineSpinner-Bu6c6aDe.js +0 -1
  382. package/codeyam-cli/src/webserver/build/client/assets/InteractivePreview-DYFW3lDD.js +0 -25
  383. package/codeyam-cli/src/webserver/build/client/assets/LibraryFunctionPreview-DLeucoVX.js +0 -3
  384. package/codeyam-cli/src/webserver/build/client/assets/SafeScreenshot-BED4B6sP.js +0 -1
  385. package/codeyam-cli/src/webserver/build/client/assets/Spinner-Bb5uFQ5V.js +0 -34
  386. package/codeyam-cli/src/webserver/build/client/assets/TruncatedFilePath-C8OKAR5x.js +0 -1
  387. package/codeyam-cli/src/webserver/build/client/assets/ViewportInspectBar-oAf2Kqsf.js +0 -1
  388. package/codeyam-cli/src/webserver/build/client/assets/chunk-JZWAC4HX-C4pqxYJB.js +0 -51
  389. package/codeyam-cli/src/webserver/build/client/assets/createLucideIcon-CMT1jU2q.js +0 -21
  390. package/codeyam-cli/src/webserver/build/client/assets/dev.empty-CltMNppm.js +0 -1
  391. package/codeyam-cli/src/webserver/build/client/assets/editor-Rfq_y0VR.js +0 -10
  392. package/codeyam-cli/src/webserver/build/client/assets/editorPreview-GNwaLSmC.js +0 -41
  393. package/codeyam-cli/src/webserver/build/client/assets/entity._sha.scenarios._scenarioId.dev-CCa2trIL.js +0 -6
  394. package/codeyam-cli/src/webserver/build/client/assets/entity._sha.scenarios._scenarioId.fullscreen-CF164ouH.js +0 -6
  395. package/codeyam-cli/src/webserver/build/client/assets/entity._sha_.create-scenario-p9hhkjJM.js +0 -6
  396. package/codeyam-cli/src/webserver/build/client/assets/fileTableUtils-cPo8LiG3.js +0 -1
  397. package/codeyam-cli/src/webserver/build/client/assets/files-DO4CZ16O.js +0 -1
  398. package/codeyam-cli/src/webserver/build/client/assets/git-CdN8sCqs.js +0 -1
  399. package/codeyam-cli/src/webserver/build/client/assets/globals-Bd0cs8vw.css +0 -1
  400. package/codeyam-cli/src/webserver/build/client/assets/labs-Zk7ryIM1.js +0 -1
  401. package/codeyam-cli/src/webserver/build/client/assets/manifest-9ab0aba3.js +0 -1
  402. package/codeyam-cli/src/webserver/build/client/assets/memory-Dg0mvYrI.js +0 -96
  403. package/codeyam-cli/src/webserver/build/client/assets/root-3ciuWk-c.js +0 -67
  404. package/codeyam-cli/src/webserver/build/client/assets/settings-DfuTtcJP.js +0 -1
  405. package/codeyam-cli/src/webserver/build/client/assets/simulations-B3aOzpCZ.js +0 -1
  406. package/codeyam-cli/src/webserver/build/client/assets/useCustomSizes-CrAK28Bc.js +0 -1
  407. package/codeyam-cli/src/webserver/build/client/assets/useReportContext-O-jkvSPx.js +0 -1
  408. package/codeyam-cli/src/webserver/build/client/assets/useToast-9FIWuYfK.js +0 -1
  409. package/codeyam-cli/src/webserver/build/server/assets/index-DCxIbVvl.js +0 -1
  410. package/codeyam-cli/src/webserver/build/server/assets/server-build-E-peu3XZ.js +0 -367
@@ -4,10 +4,149 @@ import fs from 'fs';
4
4
  import path from 'path';
5
5
  import { getProjectRoot } from "../state.js";
6
6
  import { createMockStateManager, } from "../utils/editorMockState.js";
7
+ import { computeEditorPorts } from "../utils/editorDevServer.js";
8
+ import { mockStateEventEmitter } from "./mockStateEvents.js";
9
+ /**
10
+ * Normalize a target URL by stripping trailing slashes for consistency.
11
+ *
12
+ * Previously this also replaced `localhost` with `127.0.0.1`, but that broke
13
+ * forwarding to dev servers that bind to IPv6 only (e.g. Vite 6 on macOS
14
+ * binds to `[::1]`). The hostname is now left as-is — `resolveLoopbackAddress`
15
+ * probes the actual target at startup to pick the right address.
16
+ */
17
+ export function normalizeTargetUrl(url) {
18
+ try {
19
+ const parsed = new URL(url);
20
+ return parsed.toString().replace(/\/$/, '');
21
+ }
22
+ catch {
23
+ return url;
24
+ }
25
+ }
26
+ /**
27
+ * Probe a localhost port to determine the correct loopback address.
28
+ * Dev servers may bind to IPv4 (127.0.0.1), IPv6 (::1), or both.
29
+ * Returns the first address that accepts a TCP connection.
30
+ */
31
+ export async function resolveLoopbackAddress(port) {
32
+ const candidates = ['127.0.0.1', '::1'];
33
+ for (const host of candidates) {
34
+ try {
35
+ const connected = await new Promise((resolve) => {
36
+ const socket = new net.Socket();
37
+ socket.setTimeout(1000);
38
+ socket.once('connect', () => {
39
+ socket.destroy();
40
+ resolve(true);
41
+ });
42
+ socket.once('error', () => {
43
+ socket.destroy();
44
+ resolve(false);
45
+ });
46
+ socket.once('timeout', () => {
47
+ socket.destroy();
48
+ resolve(false);
49
+ });
50
+ socket.connect(port, host);
51
+ });
52
+ if (connected) {
53
+ return host;
54
+ }
55
+ }
56
+ catch {
57
+ // Try next candidate
58
+ }
59
+ }
60
+ return null;
61
+ }
7
62
  // Global key so the proxy survives HMR
8
63
  const GLOBAL_KEY = '__codeyam_editor_proxy__';
64
+ // ─── Live Preview Health ─────────────────────────────────────────────
65
+ const PREVIEW_HEALTH_KEY = '__codeyam_preview_health__';
66
+ function getPreviewHealth() {
67
+ return globalThis[PREVIEW_HEALTH_KEY] ?? null;
68
+ }
69
+ function setPreviewHealth(report) {
70
+ globalThis[PREVIEW_HEALTH_KEY] = report;
71
+ }
72
+ /**
73
+ * Get the current live preview health report (read by API endpoint).
74
+ */
75
+ export function getPreviewHealthReport() {
76
+ return getPreviewHealth();
77
+ }
78
+ /**
79
+ * Reset preview health state (called when a new HTML page is served).
80
+ */
81
+ export function resetPreviewHealth() {
82
+ setPreviewHealth(null);
83
+ }
84
+ /**
85
+ * Error-catching script injected into HTML responses.
86
+ * Uses vanilla JS for maximum compatibility.
87
+ */
88
+ export const PREVIEW_HEALTH_SCRIPT = `<script data-codeyam-health>
89
+ (function() {
90
+ var errors = [];
91
+ var reported = false;
92
+ function report(type, msg, stack) {
93
+ errors.push({ type: type, message: msg, stack: stack, timestamp: Date.now() });
94
+ if (!reported) {
95
+ reported = true;
96
+ setTimeout(function() { flush(); }, 500);
97
+ }
98
+ }
99
+ function flush() {
100
+ fetch('/__codeyam__/preview-health', {
101
+ method: 'POST',
102
+ headers: { 'Content-Type': 'application/json' },
103
+ body: JSON.stringify({ errors: errors, url: location.href })
104
+ }).catch(function(){});
105
+ reported = false;
106
+ errors = [];
107
+ }
108
+ window.addEventListener('error', function(e) {
109
+ report('error', e.message, e.error && e.error.stack);
110
+ });
111
+ window.addEventListener('unhandledrejection', function(e) {
112
+ report('unhandledrejection', String(e.reason), e.reason && e.reason.stack);
113
+ });
114
+ var origError = console.error;
115
+ console.error = function() {
116
+ report('console.error', Array.prototype.join.call(arguments, ' '));
117
+ origError.apply(console, arguments);
118
+ };
119
+ window.addEventListener('load', function() {
120
+ setTimeout(function() {
121
+ var hasContent = document.body && document.body.innerText.trim().length > 0;
122
+ fetch('/__codeyam__/preview-health', {
123
+ method: 'POST',
124
+ headers: { 'Content-Type': 'application/json' },
125
+ body: JSON.stringify({
126
+ loaded: true,
127
+ hasContent: hasContent,
128
+ url: location.href,
129
+ errorCount: errors.length
130
+ })
131
+ }).catch(function(){});
132
+ }, 1000);
133
+ });
134
+ })();
135
+ </script>`;
9
136
  const CACHE_TTL_MS = 500;
10
137
  let scenarioCache = { data: null, timestamp: 0 };
138
+ // Session config extracted from the active scenario — drives cookie injection
139
+ let sessionConfig = undefined;
140
+ /** Session cookies from the seed adapter (e.g. Supabase auth tokens). */
141
+ let seedSessionCookies = undefined;
142
+ // localStorage config extracted from the active scenario — drives HTML injection
143
+ let localStorageConfig = null;
144
+ // Active scenario ID — used to gate localStorage seeding (only re-seed on switch)
145
+ let activeScenarioId = null;
146
+ // Prototype ID — used to gate a one-time localStorage.clear() when a new project is scaffolded
147
+ let currentPrototypeId = null;
148
+ // Current scenario type — 'application'/'user' for seed-based, 'component' for mock-based
149
+ let currentScenarioType = null;
11
150
  // Max body size to buffer for mock matching (10MB)
12
151
  const MAX_BODY_SIZE = 10 * 1024 * 1024;
13
152
  function getProxyState() {
@@ -38,6 +177,12 @@ export function getProxyUrl() {
38
177
  /**
39
178
  * Read the active scenario's mock data from disk, with brief caching.
40
179
  * Feeds the data into the MockStateManager.
180
+ *
181
+ * For application/user scenarios (type-aware): only loads `externalApis`
182
+ * into the mock state manager. All DB-backed routes flow through to the
183
+ * real app (database is seeded with real data).
184
+ *
185
+ * For component scenarios (or legacy): loads all routes as before.
41
186
  */
42
187
  function readScenarioData() {
43
188
  const now = Date.now();
@@ -55,6 +200,8 @@ function readScenarioData() {
55
200
  const active = JSON.parse(fs.readFileSync(activeScenarioPath, 'utf-8'));
56
201
  const scenarioId = active.scenarioId;
57
202
  if (!scenarioId) {
203
+ // No active scenario — but may have a prototypeId for localStorage clearing
204
+ currentPrototypeId = active.prototypeId || null;
58
205
  scenarioCache = { data: null, timestamp: now };
59
206
  return null;
60
207
  }
@@ -64,11 +211,37 @@ function readScenarioData() {
64
211
  scenarioCache = { data: null, timestamp: now };
65
212
  return null;
66
213
  }
67
- const data = JSON.parse(fs.readFileSync(dataFilePath, 'utf-8'));
68
- scenarioCache = { data, timestamp: now };
214
+ const rawData = JSON.parse(fs.readFileSync(dataFilePath, 'utf-8'));
215
+ // Extract session config for cookie injection
216
+ sessionConfig = rawData.session || null;
217
+ // Extract seed adapter session cookies (e.g. Supabase auth)
218
+ seedSessionCookies = rawData.sessionCookies || undefined;
219
+ // Extract localStorage config for HTML injection
220
+ localStorageConfig = rawData.localStorage || null;
221
+ activeScenarioId = scenarioId;
222
+ // Type-aware: for seed-based scenarios, only serve externalApis via proxy
223
+ const scenarioType = active.type || rawData.type || null;
224
+ currentScenarioType = scenarioType;
225
+ let mockData;
226
+ if ((scenarioType === 'application' || scenarioType === 'user') &&
227
+ rawData.seed) {
228
+ // Seed-based scenario: only load externalApis as routes for the proxy
229
+ if (rawData.externalApis && typeof rawData.externalApis === 'object') {
230
+ mockData = { routes: rawData.externalApis };
231
+ }
232
+ else {
233
+ // No external APIs — proxy passes everything through
234
+ mockData = {};
235
+ }
236
+ }
237
+ else {
238
+ // Component/legacy scenario: load all data
239
+ mockData = rawData;
240
+ }
241
+ scenarioCache = { data: mockData, timestamp: now };
69
242
  // Feed into mock state manager (smart reload handles dedup)
70
- getMockStateManager().loadScenario(data);
71
- return data;
243
+ getMockStateManager().loadScenario(mockData);
244
+ return mockData;
72
245
  }
73
246
  catch (err) {
74
247
  console.warn('[editorProxy] Error reading scenario data:', err);
@@ -104,26 +277,67 @@ function bufferRequestBody(req) {
104
277
  });
105
278
  });
106
279
  }
280
+ /**
281
+ * Strip IPv6 bracket notation for use with http.request hostname.
282
+ * URL.hostname returns `[::1]` for IPv6 but http.request needs `::1`.
283
+ */
284
+ function stripIPv6Brackets(hostname) {
285
+ if (hostname.startsWith('[') && hostname.endsWith(']')) {
286
+ return hostname.slice(1, -1);
287
+ }
288
+ return hostname;
289
+ }
107
290
  /**
108
291
  * Forward a buffered request to the target dev server.
109
292
  * Unlike the streaming forwardRequest, this replays a buffered body.
110
293
  */
111
294
  function forwardBufferedRequest(req, res, targetUrl, bodyBuffer) {
112
295
  const target = new URL(targetUrl);
296
+ const hostname = stripIPv6Brackets(target.hostname);
113
297
  const headers = { ...req.headers, host: `${target.hostname}:${target.port}` };
298
+ // Remove accept-encoding so the dev server returns uncompressed responses.
299
+ // The proxy injects a health script into HTML — this fails on compressed bodies.
300
+ delete headers['accept-encoding'];
114
301
  // Update content-length if we have the body buffer
115
302
  if (bodyBuffer) {
116
303
  headers['content-length'] = String(bodyBuffer.length);
117
304
  }
118
305
  const options = {
119
- hostname: target.hostname,
306
+ hostname,
120
307
  port: target.port,
121
308
  path: req.url,
122
309
  method: req.method,
123
310
  headers,
124
311
  };
125
312
  const proxyReq = http.request(options, (proxyRes) => {
126
- res.writeHead(proxyRes.statusCode || 200, proxyRes.headers);
313
+ const status = proxyRes.statusCode || 200;
314
+ if (status >= 400) {
315
+ console.warn(`[editorProxy] Target returned ${status} for ${req.method} ${req.url}`);
316
+ }
317
+ const headers = { ...proxyRes.headers };
318
+ injectSessionCookie(headers);
319
+ // Check if response is HTML — if so, buffer and inject health script
320
+ const contentType = proxyRes.headers['content-type'] || '';
321
+ if (contentType.includes('text/html')) {
322
+ resetPreviewHealth();
323
+ const chunks = [];
324
+ proxyRes.on('data', (chunk) => chunks.push(chunk));
325
+ proxyRes.on('end', () => {
326
+ const body = Buffer.concat(chunks).toString('utf-8');
327
+ const lsScript = buildLocalStorageScript(localStorageConfig, activeScenarioId || '', currentPrototypeId);
328
+ const injected = injectHealthScript(body, lsScript);
329
+ delete headers['content-length'];
330
+ delete headers['content-encoding'];
331
+ // Prevent browser from caching HTML responses — scenario switches
332
+ // serve different content from the same URL (seed data changes the
333
+ // rendered page but the proxy URL stays the same).
334
+ headers['cache-control'] = 'no-store, must-revalidate';
335
+ res.writeHead(status, headers);
336
+ res.end(injected);
337
+ });
338
+ return;
339
+ }
340
+ res.writeHead(status, headers);
127
341
  proxyRes.pipe(res, { end: true });
128
342
  });
129
343
  proxyReq.on('error', (err) => {
@@ -141,19 +355,58 @@ function forwardBufferedRequest(req, res, targetUrl, bodyBuffer) {
141
355
  }
142
356
  }
143
357
  /**
144
- * Forward an HTTP request to the target dev server (streaming, no body buffering).
358
+ * Forward an HTTP request to the target dev server.
359
+ * For HTML responses: buffers body to inject health-check script.
360
+ * For non-HTML responses: pipes directly (no buffering).
145
361
  */
146
362
  function forwardRequest(req, res, targetUrl) {
147
363
  const target = new URL(targetUrl);
364
+ const hostname = stripIPv6Brackets(target.hostname);
365
+ // Build headers, stripping accept-encoding so the dev server returns uncompressed
366
+ // responses. The proxy injects a health script into HTML — this fails on compressed bodies.
367
+ const { 'accept-encoding': _ae, ...forwardHeaders } = req.headers;
148
368
  const options = {
149
- hostname: target.hostname,
369
+ hostname,
150
370
  port: target.port,
151
371
  path: req.url,
152
372
  method: req.method,
153
- headers: { ...req.headers, host: `${target.hostname}:${target.port}` },
373
+ headers: {
374
+ ...forwardHeaders,
375
+ host: `${target.hostname}:${target.port}`,
376
+ },
154
377
  };
155
378
  const proxyReq = http.request(options, (proxyRes) => {
156
- res.writeHead(proxyRes.statusCode || 200, proxyRes.headers);
379
+ const status = proxyRes.statusCode || 200;
380
+ if (status >= 400) {
381
+ console.warn(`[editorProxy] Target returned ${status} for ${req.method} ${req.url}`);
382
+ }
383
+ const headers = { ...proxyRes.headers };
384
+ injectSessionCookie(headers);
385
+ // Check if response is HTML — if so, buffer and inject health script
386
+ const contentType = proxyRes.headers['content-type'] || '';
387
+ if (contentType.includes('text/html')) {
388
+ // Reset health state for new page loads
389
+ resetPreviewHealth();
390
+ const chunks = [];
391
+ proxyRes.on('data', (chunk) => chunks.push(chunk));
392
+ proxyRes.on('end', () => {
393
+ const body = Buffer.concat(chunks).toString('utf-8');
394
+ const lsScript = buildLocalStorageScript(localStorageConfig, activeScenarioId || '', currentPrototypeId);
395
+ const injected = injectHealthScript(body, lsScript);
396
+ // Remove content-length since body size changed; use chunked transfer
397
+ delete headers['content-length'];
398
+ // Remove content-encoding since we're serving uncompressed
399
+ delete headers['content-encoding'];
400
+ // Prevent browser from caching HTML responses — scenario switches
401
+ // serve different content from the same URL (seed data changes the
402
+ // rendered page but the proxy URL stays the same).
403
+ headers['cache-control'] = 'no-store, must-revalidate';
404
+ res.writeHead(status, headers);
405
+ res.end(injected);
406
+ });
407
+ return;
408
+ }
409
+ res.writeHead(status, headers);
157
410
  proxyRes.pipe(res, { end: true });
158
411
  });
159
412
  proxyReq.on('error', (err) => {
@@ -165,14 +418,251 @@ function forwardRequest(req, res, targetUrl) {
165
418
  });
166
419
  req.pipe(proxyReq, { end: true });
167
420
  }
421
+ /**
422
+ * Inject or clear the session-token cookie on proxied responses.
423
+ * When a scenario has session.cookieValue, sets the cookie to auto-log the user in.
424
+ * When a scenario has no session field (null), clears any existing session cookie.
425
+ * When sessionConfig is undefined (no scenario loaded yet), does nothing.
426
+ */
427
+ function injectSessionCookie(headers) {
428
+ const cookies = [];
429
+ // Dev auth cookie (built-in session-token)
430
+ if (sessionConfig !== undefined) {
431
+ if (sessionConfig?.cookieValue) {
432
+ cookies.push(`session-token=${sessionConfig.cookieValue}; Path=/; SameSite=Lax`);
433
+ }
434
+ else {
435
+ cookies.push(`session-token=; Path=/; Max-Age=0`);
436
+ }
437
+ }
438
+ // Seed adapter session cookies (e.g. Supabase auth tokens)
439
+ if (seedSessionCookies && seedSessionCookies.length > 0) {
440
+ for (const sc of seedSessionCookies) {
441
+ const cookiePath = sc.path || '/';
442
+ const sameSite = sc.sameSite || 'Lax';
443
+ cookies.push(`${sc.name}=${sc.value}; Path=${cookiePath}; SameSite=${sameSite}`);
444
+ }
445
+ }
446
+ if (cookies.length === 0)
447
+ return;
448
+ const existing = headers['set-cookie'];
449
+ if (existing) {
450
+ headers['set-cookie'] = [
451
+ ...(Array.isArray(existing) ? existing : [existing]),
452
+ ...cookies,
453
+ ];
454
+ }
455
+ else {
456
+ headers['set-cookie'] = cookies;
457
+ }
458
+ }
459
+ /**
460
+ * Get the current session config (for testing).
461
+ */
462
+ export function getSessionConfig() {
463
+ return sessionConfig;
464
+ }
465
+ /**
466
+ * Get the current localStorage config (for testing and script generation).
467
+ */
468
+ export function getLocalStorageConfig() {
469
+ return localStorageConfig;
470
+ }
471
+ /**
472
+ * Get the active scenario ID (for testing and script generation).
473
+ */
474
+ export function getActiveScenarioId() {
475
+ return activeScenarioId;
476
+ }
477
+ /**
478
+ * Get the current prototype ID (for testing).
479
+ */
480
+ export function getCurrentPrototypeId() {
481
+ return currentPrototypeId;
482
+ }
483
+ /**
484
+ * Simple djb2 hash — fast, deterministic, good enough for cache busting.
485
+ * Not cryptographic — just detects when localStorage config content changes.
486
+ */
487
+ function simpleHash(str) {
488
+ let hash = 5381;
489
+ for (let i = 0; i < str.length; i++) {
490
+ hash = ((hash << 5) + hash + str.charCodeAt(i)) | 0;
491
+ }
492
+ return (hash >>> 0).toString(36);
493
+ }
494
+ /**
495
+ * Build a script tag that seeds localStorage with scenario data on first load.
496
+ * Gated by scenario ID — only seeds when the scenario changes, preserving
497
+ * interactive modifications across page reloads / HMR.
498
+ *
499
+ * Returns empty string if no localStorage config is provided.
500
+ */
501
+ export function buildLocalStorageScript(localStorageConfig, scenarioId, prototypeId) {
502
+ // null/undefined means no localStorage config at all — but if we have a
503
+ // prototypeId, emit a one-time localStorage.clear() to flush stale data
504
+ // from a previous prototype session.
505
+ if (!localStorageConfig || typeof localStorageConfig !== 'object') {
506
+ if (prototypeId) {
507
+ return `<script data-codeyam-ls>
508
+ (function() {
509
+ if (localStorage.getItem('__codeyam_proto__') === ${JSON.stringify(prototypeId)}) return;
510
+ localStorage.clear();
511
+ localStorage.setItem('__codeyam_proto__', ${JSON.stringify(prototypeId)});
512
+ })();
513
+ </script>`;
514
+ }
515
+ return '';
516
+ }
517
+ // Even an empty object needs a cleanup script — switching from a scenario
518
+ // with localStorage data to one without must clear the previous keys.
519
+ const entries = Object.entries(localStorageConfig);
520
+ const keys = entries.map(([k]) => k);
521
+ // Build setItem calls — stringify non-string values
522
+ const setStatements = entries
523
+ .map(([key, value]) => {
524
+ const serialized = typeof value === 'string' ? value : JSON.stringify(value);
525
+ return `localStorage.setItem(${JSON.stringify(key)}, ${JSON.stringify(serialized)});`;
526
+ })
527
+ .join('\n');
528
+ // Guard value includes a content hash so re-registering a scenario with
529
+ // updated data (same ID, different content) busts the cache. Without this,
530
+ // the browser skips re-seeding because the scenario ID hasn't changed,
531
+ // causing stale data in the live preview while screenshots show fresh data.
532
+ const contentHash = simpleHash(JSON.stringify(localStorageConfig));
533
+ const guardValue = `${scenarioId}:${contentHash}`;
534
+ return (`<script data-codeyam-ls>
535
+ (function() {
536
+ if (localStorage.getItem('__codeyam_ls_sid__') === ${JSON.stringify(guardValue)}) return;
537
+ var prev = JSON.parse(localStorage.getItem('__codeyam_ls_keys__') || '[]');
538
+ for (var i = 0; i < prev.length; i++) localStorage.removeItem(prev[i]);
539
+ ${setStatements}
540
+ localStorage.setItem('__codeyam_ls_keys__', ${JSON.stringify(JSON.stringify(keys))});
541
+ localStorage.setItem('__codeyam_ls_sid__', ${JSON.stringify(guardValue)});
542
+ })();
543
+ </script>` + buildLocalStorageWatcherScript());
544
+ }
545
+ /**
546
+ * Build a script that watches for localStorage mutations and notifies the parent
547
+ * frame via postMessage. Also responds to `codeyam-get-localstorage` requests so
548
+ * the editor can read the current localStorage state when saving.
549
+ */
550
+ function buildLocalStorageWatcherScript() {
551
+ return `<script data-codeyam-ls-watcher>
552
+ (function() {
553
+ if (window.__codeyam_ls_watcher_installed__) return;
554
+ window.__codeyam_ls_watcher_installed__ = true;
555
+
556
+ var origSet = localStorage.setItem.bind(localStorage);
557
+ var origRemove = localStorage.removeItem.bind(localStorage);
558
+ var origClear = localStorage.clear.bind(localStorage);
559
+ window.__codeyam_orig_setItem__ = origSet;
560
+ window.__codeyam_orig_removeItem__ = origRemove;
561
+ window.__codeyam_orig_clear__ = origClear;
562
+
563
+ function isInternal(key) {
564
+ return typeof key === 'string' && key.indexOf('__codeyam_') === 0;
565
+ }
566
+
567
+ localStorage.setItem = function(key, value) {
568
+ origSet(key, value);
569
+ if (!isInternal(key) && window.parent !== window) {
570
+ window.parent.postMessage({ type: 'codeyam-localstorage-changed', action: 'set', key: key }, '*');
571
+ }
572
+ };
573
+
574
+ localStorage.removeItem = function(key) {
575
+ origRemove(key);
576
+ if (!isInternal(key) && window.parent !== window) {
577
+ window.parent.postMessage({ type: 'codeyam-localstorage-changed', action: 'remove', key: key }, '*');
578
+ }
579
+ };
580
+
581
+ localStorage.clear = function() {
582
+ origClear();
583
+ if (window.parent !== window) {
584
+ window.parent.postMessage({ type: 'codeyam-localstorage-changed', action: 'clear' }, '*');
585
+ }
586
+ };
587
+
588
+ window.addEventListener('message', function(event) {
589
+ if (event.data && event.data.type === 'codeyam-get-localstorage') {
590
+ var data = {};
591
+ for (var i = 0; i < localStorage.length; i++) {
592
+ var k = localStorage.key(i);
593
+ if (k && !isInternal(k)) {
594
+ data[k] = localStorage.getItem(k);
595
+ }
596
+ }
597
+ event.source.postMessage({ type: 'codeyam-localstorage-state', data: data }, '*');
598
+ }
599
+ });
600
+ })();
601
+ </script>`;
602
+ }
603
+ /**
604
+ * Inject the health-check script (and optional localStorage script) into an HTML response body.
605
+ * Inserts before </head> if present, otherwise before </body>, otherwise appends.
606
+ * When a localStorageScript is provided, it's injected BEFORE the health script
607
+ * so localStorage is populated before the app loads.
608
+ */
609
+ export function injectHealthScript(html, localStorageScript) {
610
+ const scripts = (localStorageScript || '') + PREVIEW_HEALTH_SCRIPT;
611
+ if (html.includes('</head>')) {
612
+ return html.replace('</head>', scripts + '</head>');
613
+ }
614
+ if (html.includes('</body>')) {
615
+ return html.replace('</body>', scripts + '</body>');
616
+ }
617
+ return html + scripts;
618
+ }
619
+ /**
620
+ * Handle POST /__codeyam__/preview-health — store health data in globalThis.
621
+ */
622
+ function handlePreviewHealthPost(req, res) {
623
+ const chunks = [];
624
+ req.on('data', (chunk) => chunks.push(chunk));
625
+ req.on('end', () => {
626
+ try {
627
+ const body = JSON.parse(Buffer.concat(chunks).toString('utf-8'));
628
+ const current = getPreviewHealth() || {
629
+ errors: [],
630
+ loaded: false,
631
+ hasContent: false,
632
+ url: '',
633
+ lastUpdated: 0,
634
+ };
635
+ if (body.errors && Array.isArray(body.errors)) {
636
+ current.errors = current.errors.concat(body.errors);
637
+ }
638
+ if (body.loaded !== undefined) {
639
+ current.loaded = body.loaded;
640
+ }
641
+ if (body.hasContent !== undefined) {
642
+ current.hasContent = body.hasContent;
643
+ }
644
+ if (body.url) {
645
+ current.url = body.url;
646
+ }
647
+ current.lastUpdated = Date.now();
648
+ setPreviewHealth(current);
649
+ }
650
+ catch {
651
+ // Ignore malformed JSON
652
+ }
653
+ res.writeHead(204);
654
+ res.end();
655
+ });
656
+ }
168
657
  /**
169
658
  * Handle WebSocket upgrade by piping to the target dev server.
170
659
  */
171
660
  function handleUpgrade(req, socket, head, targetUrl) {
172
661
  const target = new URL(targetUrl);
662
+ const hostname = stripIPv6Brackets(target.hostname);
173
663
  const port = parseInt(target.port, 10) || 80;
174
- console.log(`[editorProxy] WebSocket upgrade: ${req.url} → ${target.hostname}:${port}`);
175
- const proxySocket = net.connect(port, target.hostname, () => {
664
+ console.log(`[editorProxy] WebSocket upgrade: ${req.url} → ${hostname}:${port}`);
665
+ const proxySocket = net.connect(port, hostname, () => {
176
666
  // Reconstruct the HTTP upgrade request
177
667
  const requestLine = `${req.method} ${req.url} HTTP/${req.httpVersion}\r\n`;
178
668
  const headers = Object.entries(req.headers)
@@ -234,10 +724,34 @@ function removeProxyConfig() {
234
724
  * Supports all HTTP methods (GET, POST, PUT, DELETE, PATCH) with body buffering.
235
725
  */
236
726
  export async function startEditorProxy(options) {
237
- // Stop existing proxy first
727
+ // If proxy is already running, reuse it (prevents second tab from killing first tab's proxy)
728
+ const existing = getProxyState();
729
+ if (existing) {
730
+ console.log(`[editorProxy] Proxy already running on port ${existing.port} → ${existing.targetUrl}`);
731
+ return { port: existing.port };
732
+ }
733
+ // Stop any leftover state (shouldn't happen, but defensive)
238
734
  await stopEditorProxy();
239
- const { targetUrl } = options;
735
+ let targetUrl = normalizeTargetUrl(options.targetUrl);
240
736
  let port = options.port;
737
+ // When the target is localhost, probe to find the correct loopback address.
738
+ // Dev servers may bind to IPv4 (127.0.0.1) or IPv6 (::1) — Vite 6 on macOS
739
+ // binds to ::1 by default. We need to match the actual binding.
740
+ try {
741
+ const parsed = new URL(targetUrl);
742
+ if (parsed.hostname === 'localhost') {
743
+ const targetPort = parseInt(parsed.port || '80', 10);
744
+ const resolvedHost = await resolveLoopbackAddress(targetPort);
745
+ if (resolvedHost) {
746
+ parsed.hostname = resolvedHost;
747
+ targetUrl = parsed.toString().replace(/\/$/, '');
748
+ console.log(`[editorProxy] Resolved localhost to ${resolvedHost} for port ${targetPort}`);
749
+ }
750
+ }
751
+ }
752
+ catch {
753
+ // Keep original targetUrl
754
+ }
241
755
  console.log(`[editorProxy] Starting proxy (requested port ${port}, target ${targetUrl})`);
242
756
  const mockState = getMockStateManager();
243
757
  const server = http.createServer((req, res) => {
@@ -256,6 +770,11 @@ export async function startEditorProxy(options) {
256
770
  res.end();
257
771
  return;
258
772
  }
773
+ // Intercept preview health reports from the injected script
774
+ if (method === 'POST' && pathname === '/__codeyam__/preview-health') {
775
+ handlePreviewHealthPost(req, res);
776
+ return;
777
+ }
259
778
  // Load scenario data (also feeds MockStateManager)
260
779
  readScenarioData();
261
780
  // For methods that may carry a body, buffer it first
@@ -287,11 +806,17 @@ export async function startEditorProxy(options) {
287
806
  'Content-Type': 'application/json',
288
807
  'Access-Control-Allow-Origin': '*',
289
808
  'X-CodeYam-Proxy': 'scenario-data',
809
+ 'Cache-Control': 'no-store',
290
810
  });
291
811
  res.end(match.body != null ? JSON.stringify(match.body) : '');
292
812
  return;
293
813
  }
294
814
  // No mock match — forward with buffered body
815
+ if ((currentScenarioType === 'application' ||
816
+ currentScenarioType === 'user') &&
817
+ pathname.startsWith('/api/')) {
818
+ mockStateEventEmitter.emitDataMutationForwarded(method, pathname);
819
+ }
295
820
  forwardBufferedRequest(req, res, targetUrl, bodyBuffer);
296
821
  return;
297
822
  }
@@ -303,6 +828,7 @@ export async function startEditorProxy(options) {
303
828
  'Content-Type': 'application/json',
304
829
  'Access-Control-Allow-Origin': '*',
305
830
  'X-CodeYam-Proxy': 'scenario-data',
831
+ 'Cache-Control': 'no-store',
306
832
  });
307
833
  res.end(match.body != null ? JSON.stringify(match.body) : '');
308
834
  return;
@@ -327,7 +853,10 @@ export async function startEditorProxy(options) {
327
853
  resolve();
328
854
  });
329
855
  });
330
- port = currentPort;
856
+ // When port 0 is requested, the OS assigns an ephemeral port
857
+ const addr = server.address();
858
+ port =
859
+ typeof addr === 'object' && addr !== null ? addr.port : currentPort;
331
860
  const state = { server, port, targetUrl };
332
861
  setProxyState(state);
333
862
  // Write proxy-config.json for the preload module
@@ -370,6 +899,41 @@ export async function stopEditorProxy() {
370
899
  */
371
900
  export function invalidateScenarioCache() {
372
901
  scenarioCache = { data: null, timestamp: 0 };
902
+ sessionConfig = undefined;
903
+ seedSessionCookies = undefined;
904
+ localStorageConfig = null;
905
+ activeScenarioId = null;
906
+ currentPrototypeId = null;
907
+ }
908
+ /**
909
+ * Verify that the proxy can successfully forward a request to the target dev server.
910
+ * Makes a HEAD request through the proxy and checks that it gets a response (any status).
911
+ * Returns false if the proxy isn't running or if the request fails entirely.
912
+ */
913
+ export async function verifyProxyForwarding() {
914
+ const state = getProxyState();
915
+ if (!state) {
916
+ console.warn('[editorProxy] Cannot verify — proxy is not running');
917
+ return false;
918
+ }
919
+ try {
920
+ const response = await fetch(`http://127.0.0.1:${state.port}/`, {
921
+ method: 'HEAD',
922
+ signal: AbortSignal.timeout(5000),
923
+ });
924
+ // Any response from the target (even 404) means forwarding works.
925
+ // Only 502 (our own Bad Gateway) means the target is unreachable.
926
+ if (response.status === 502) {
927
+ console.warn(`[editorProxy] Verification failed — proxy returned 502 (target unreachable)`);
928
+ return false;
929
+ }
930
+ console.log(`[editorProxy] Verification passed — proxy forwarding to ${state.targetUrl} (status ${response.status})`);
931
+ return true;
932
+ }
933
+ catch (err) {
934
+ console.warn(`[editorProxy] Verification failed — could not reach proxy on port ${state.port}`);
935
+ return false;
936
+ }
373
937
  }
374
938
  /**
375
939
  * Ensure the proxy is running. If it's not, start it using the current dev server URL.
@@ -391,9 +955,10 @@ export async function ensureProxyRunning() {
391
955
  return null;
392
956
  }
393
957
  const codeyamPort = parseInt(process.env.CODEYAM_PORT || '3111', 10);
394
- console.log(`[editorProxy] Proxy not running, starting on-demand (port ${codeyamPort + 1}, target ${devServer.url})`);
958
+ const { proxyPort } = computeEditorPorts(codeyamPort);
959
+ console.log(`[editorProxy] Proxy not running, starting on-demand (port ${proxyPort}, target ${devServer.url})`);
395
960
  const result = await startEditorProxy({
396
- port: codeyamPort + 1,
961
+ port: proxyPort,
397
962
  targetUrl: devServer.url,
398
963
  });
399
964
  if (result) {
@@ -404,4 +969,8 @@ export async function ensureProxyRunning() {
404
969
  console.error('[editorProxy] Failed to start on-demand proxy');
405
970
  return null;
406
971
  }
972
+ /**
973
+ * Test-only export: trigger readScenarioData so tests can verify session config extraction.
974
+ */
975
+ export const _readScenarioDataForTest = readScenarioData;
407
976
  //# sourceMappingURL=editorProxy.js.map