@codeyam/codeyam-cli 0.1.0-staging.f777668 → 0.1.0-staging.fff1b4e

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 (570) 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 +7 -7
  4. package/analyzer-template/packages/ai/package.json +1 -1
  5. package/analyzer-template/packages/ai/src/lib/astScopes/methodSemantics.ts +135 -0
  6. package/analyzer-template/packages/ai/src/lib/astScopes/nodeToSource.ts +19 -0
  7. package/analyzer-template/packages/ai/src/lib/astScopes/paths.ts +11 -4
  8. package/analyzer-template/packages/ai/src/lib/dataStructure/ScopeDataStructure.ts +36 -9
  9. package/analyzer-template/packages/ai/src/lib/dataStructure/equivalencyManagers/ParentScopeManager.ts +10 -3
  10. package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/cleanKnownObjectFunctions.ts +16 -6
  11. package/analyzer-template/packages/analyze/index.ts +4 -1
  12. package/analyzer-template/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.ts +28 -2
  13. package/analyzer-template/packages/analyze/src/lib/files/analyze/analyzeEntities.ts +5 -36
  14. package/analyzer-template/packages/analyze/src/lib/files/analyze/findOrCreateEntity.ts +10 -6
  15. package/analyzer-template/packages/analyze/src/lib/files/analyze/gatherEntityMap.ts +9 -12
  16. package/analyzer-template/packages/analyze/src/lib/files/analyze/trackEntityCircularDependencies.ts +21 -0
  17. package/analyzer-template/packages/analyze/src/lib/files/analyze/validateDependencyAnalyses.ts +82 -10
  18. package/analyzer-template/packages/analyze/src/lib/files/analyzeChange.ts +4 -0
  19. package/analyzer-template/packages/analyze/src/lib/files/analyzeInitial.ts +4 -0
  20. package/analyzer-template/packages/analyze/src/lib/files/analyzeNextRoute.ts +8 -3
  21. package/analyzer-template/packages/analyze/src/lib/files/scenarios/generateDataStructure.ts +239 -58
  22. package/analyzer-template/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.ts +1684 -1462
  23. package/analyzer-template/packages/aws/package.json +7 -7
  24. package/analyzer-template/packages/database/package.json +3 -3
  25. package/analyzer-template/packages/database/src/lib/kysely/tables/editorScenariosTable.ts +96 -0
  26. package/analyzer-template/packages/database/src/lib/loadAnalysis.ts +25 -15
  27. package/analyzer-template/packages/database/src/lib/loadEntities.ts +0 -6
  28. package/analyzer-template/packages/database/src/lib/loadEntity.ts +19 -8
  29. package/analyzer-template/packages/database/src/lib/updateCommitMetadata.ts +0 -65
  30. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/editorScenariosTable.d.ts +7 -0
  31. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/editorScenariosTable.d.ts.map +1 -1
  32. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/editorScenariosTable.js +98 -0
  33. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/editorScenariosTable.js.map +1 -1
  34. package/analyzer-template/packages/github/dist/database/src/lib/loadAnalysis.d.ts.map +1 -1
  35. package/analyzer-template/packages/github/dist/database/src/lib/loadAnalysis.js +7 -1
  36. package/analyzer-template/packages/github/dist/database/src/lib/loadAnalysis.js.map +1 -1
  37. package/analyzer-template/packages/github/dist/database/src/lib/loadEntities.d.ts.map +1 -1
  38. package/analyzer-template/packages/github/dist/database/src/lib/loadEntities.js +0 -6
  39. package/analyzer-template/packages/github/dist/database/src/lib/loadEntities.js.map +1 -1
  40. package/analyzer-template/packages/github/dist/database/src/lib/loadEntity.d.ts +4 -1
  41. package/analyzer-template/packages/github/dist/database/src/lib/loadEntity.d.ts.map +1 -1
  42. package/analyzer-template/packages/github/dist/database/src/lib/loadEntity.js +5 -5
  43. package/analyzer-template/packages/github/dist/database/src/lib/loadEntity.js.map +1 -1
  44. package/analyzer-template/packages/github/dist/database/src/lib/updateCommitMetadata.d.ts.map +1 -1
  45. package/analyzer-template/packages/github/dist/database/src/lib/updateCommitMetadata.js +0 -25
  46. package/analyzer-template/packages/github/dist/database/src/lib/updateCommitMetadata.js.map +1 -1
  47. package/analyzer-template/packages/github/dist/types/src/enums/ProjectFramework.d.ts +2 -0
  48. package/analyzer-template/packages/github/dist/types/src/enums/ProjectFramework.d.ts.map +1 -1
  49. package/analyzer-template/packages/github/dist/types/src/enums/ProjectFramework.js +2 -0
  50. package/analyzer-template/packages/github/dist/types/src/enums/ProjectFramework.js.map +1 -1
  51. package/analyzer-template/packages/types/src/enums/ProjectFramework.ts +2 -0
  52. package/analyzer-template/packages/ui-components/package.json +1 -1
  53. package/analyzer-template/packages/utils/dist/types/src/enums/ProjectFramework.d.ts +2 -0
  54. package/analyzer-template/packages/utils/dist/types/src/enums/ProjectFramework.d.ts.map +1 -1
  55. package/analyzer-template/packages/utils/dist/types/src/enums/ProjectFramework.js +2 -0
  56. package/analyzer-template/packages/utils/dist/types/src/enums/ProjectFramework.js.map +1 -1
  57. package/analyzer-template/packages/utils/dist/utils/src/lib/fs/rsyncCopy.d.ts +3 -1
  58. package/analyzer-template/packages/utils/dist/utils/src/lib/fs/rsyncCopy.d.ts.map +1 -1
  59. package/analyzer-template/packages/utils/dist/utils/src/lib/fs/rsyncCopy.js +22 -1
  60. package/analyzer-template/packages/utils/dist/utils/src/lib/fs/rsyncCopy.js.map +1 -1
  61. package/analyzer-template/packages/utils/src/lib/fs/rsyncCopy.ts +27 -0
  62. package/analyzer-template/project/analyzeFileEntities.ts +26 -0
  63. package/analyzer-template/project/runMultiScenarioServer.ts +26 -3
  64. package/background/src/lib/virtualized/project/analyzeFileEntities.js +22 -0
  65. package/background/src/lib/virtualized/project/analyzeFileEntities.js.map +1 -1
  66. package/background/src/lib/virtualized/project/runMultiScenarioServer.js +23 -3
  67. package/background/src/lib/virtualized/project/runMultiScenarioServer.js.map +1 -1
  68. package/codeyam-cli/src/cli.js +24 -0
  69. package/codeyam-cli/src/cli.js.map +1 -1
  70. package/codeyam-cli/src/commands/__tests__/editor.analyzeImportsArgs.test.js +47 -0
  71. package/codeyam-cli/src/commands/__tests__/editor.analyzeImportsArgs.test.js.map +1 -0
  72. package/codeyam-cli/src/commands/__tests__/editor.auditNoAutoAnalysis.test.js +71 -0
  73. package/codeyam-cli/src/commands/__tests__/editor.auditNoAutoAnalysis.test.js.map +1 -0
  74. package/codeyam-cli/src/commands/__tests__/editor.designSystem.test.js +30 -0
  75. package/codeyam-cli/src/commands/__tests__/editor.designSystem.test.js.map +1 -0
  76. package/codeyam-cli/src/commands/__tests__/editor.isolateArgs.test.js +51 -0
  77. package/codeyam-cli/src/commands/__tests__/editor.isolateArgs.test.js.map +1 -0
  78. package/codeyam-cli/src/commands/__tests__/editor.statePersistence.test.js +55 -0
  79. package/codeyam-cli/src/commands/__tests__/editor.statePersistence.test.js.map +1 -0
  80. package/codeyam-cli/src/commands/__tests__/editor.stepDispatch.test.js +56 -0
  81. package/codeyam-cli/src/commands/__tests__/editor.stepDispatch.test.js.map +1 -0
  82. package/codeyam-cli/src/commands/__tests__/init.gitignore.test.js +137 -47
  83. package/codeyam-cli/src/commands/__tests__/init.gitignore.test.js.map +1 -1
  84. package/codeyam-cli/src/commands/editor.js +4373 -667
  85. package/codeyam-cli/src/commands/editor.js.map +1 -1
  86. package/codeyam-cli/src/commands/editorAnalyzeImportsArgs.js +23 -0
  87. package/codeyam-cli/src/commands/editorAnalyzeImportsArgs.js.map +1 -0
  88. package/codeyam-cli/src/commands/editorIsolateArgs.js +25 -0
  89. package/codeyam-cli/src/commands/editorIsolateArgs.js.map +1 -0
  90. package/codeyam-cli/src/commands/init.js +89 -34
  91. package/codeyam-cli/src/commands/init.js.map +1 -1
  92. package/codeyam-cli/src/commands/telemetry.js +37 -0
  93. package/codeyam-cli/src/commands/telemetry.js.map +1 -0
  94. package/codeyam-cli/src/data/designSystems.js +27 -0
  95. package/codeyam-cli/src/data/designSystems.js.map +1 -0
  96. package/codeyam-cli/src/data/techStacks.js +77 -0
  97. package/codeyam-cli/src/data/techStacks.js.map +1 -0
  98. package/codeyam-cli/src/utils/__tests__/analyzerFinalization.test.js +173 -0
  99. package/codeyam-cli/src/utils/__tests__/analyzerFinalization.test.js.map +1 -0
  100. package/codeyam-cli/src/utils/__tests__/backgroundServer.test.js +46 -0
  101. package/codeyam-cli/src/utils/__tests__/backgroundServer.test.js.map +1 -0
  102. package/codeyam-cli/src/utils/__tests__/devServerState.test.js +93 -1
  103. package/codeyam-cli/src/utils/__tests__/devServerState.test.js.map +1 -1
  104. package/codeyam-cli/src/utils/__tests__/editorApi.test.js +62 -8
  105. package/codeyam-cli/src/utils/__tests__/editorApi.test.js.map +1 -1
  106. package/codeyam-cli/src/utils/__tests__/editorAudit.test.js +3526 -1
  107. package/codeyam-cli/src/utils/__tests__/editorAudit.test.js.map +1 -1
  108. package/codeyam-cli/src/utils/__tests__/editorBroadcastViewport.test.js +76 -0
  109. package/codeyam-cli/src/utils/__tests__/editorBroadcastViewport.test.js.map +1 -0
  110. package/codeyam-cli/src/utils/__tests__/editorCaptureScenarioSeeding.test.js +137 -0
  111. package/codeyam-cli/src/utils/__tests__/editorCaptureScenarioSeeding.test.js.map +1 -0
  112. package/codeyam-cli/src/utils/__tests__/editorDeleteScenario.test.js +100 -0
  113. package/codeyam-cli/src/utils/__tests__/editorDeleteScenario.test.js.map +1 -0
  114. package/codeyam-cli/src/utils/__tests__/editorDevServer.test.js +152 -3
  115. package/codeyam-cli/src/utils/__tests__/editorDevServer.test.js.map +1 -1
  116. package/codeyam-cli/src/utils/__tests__/editorEntityChangeStatus.test.js +76 -3
  117. package/codeyam-cli/src/utils/__tests__/editorEntityChangeStatus.test.js.map +1 -1
  118. package/codeyam-cli/src/utils/__tests__/editorEntityHelpers.test.js +381 -0
  119. package/codeyam-cli/src/utils/__tests__/editorEntityHelpers.test.js.map +1 -0
  120. package/codeyam-cli/src/utils/__tests__/editorGuardMiddleware.test.js +67 -0
  121. package/codeyam-cli/src/utils/__tests__/editorGuardMiddleware.test.js.map +1 -0
  122. package/codeyam-cli/src/utils/__tests__/editorJournal.test.js +1 -1
  123. package/codeyam-cli/src/utils/__tests__/editorJournal.test.js.map +1 -1
  124. package/codeyam-cli/src/utils/__tests__/editorLoaderHelpers.test.js +202 -1
  125. package/codeyam-cli/src/utils/__tests__/editorLoaderHelpers.test.js.map +1 -1
  126. package/codeyam-cli/src/utils/__tests__/editorMigration.test.js +435 -0
  127. package/codeyam-cli/src/utils/__tests__/editorMigration.test.js.map +1 -0
  128. package/codeyam-cli/src/utils/__tests__/editorPreview.test.js +103 -8
  129. package/codeyam-cli/src/utils/__tests__/editorPreview.test.js.map +1 -1
  130. package/codeyam-cli/src/utils/__tests__/editorProxySession.test.js +250 -0
  131. package/codeyam-cli/src/utils/__tests__/editorProxySession.test.js.map +1 -0
  132. package/codeyam-cli/src/utils/__tests__/editorRoadmap.test.js +1108 -0
  133. package/codeyam-cli/src/utils/__tests__/editorRoadmap.test.js.map +1 -0
  134. package/codeyam-cli/src/utils/__tests__/editorScenarioLookup.test.js +5 -5
  135. package/codeyam-cli/src/utils/__tests__/editorScenarioLookup.test.js.map +1 -1
  136. package/codeyam-cli/src/utils/__tests__/editorScenarioSwitch.test.js +190 -0
  137. package/codeyam-cli/src/utils/__tests__/editorScenarioSwitch.test.js.map +1 -1
  138. package/codeyam-cli/src/utils/__tests__/editorScenarios.test.js +1549 -2
  139. package/codeyam-cli/src/utils/__tests__/editorScenarios.test.js.map +1 -1
  140. package/codeyam-cli/src/utils/__tests__/editorSeedAdapter.test.js +201 -1
  141. package/codeyam-cli/src/utils/__tests__/editorSeedAdapter.test.js.map +1 -1
  142. package/codeyam-cli/src/utils/__tests__/editorSeedAdapterPrismaValidation.test.js +143 -0
  143. package/codeyam-cli/src/utils/__tests__/editorSeedAdapterPrismaValidation.test.js.map +1 -0
  144. package/codeyam-cli/src/utils/__tests__/editorSessionFilter.test.js +66 -0
  145. package/codeyam-cli/src/utils/__tests__/editorSessionFilter.test.js.map +1 -0
  146. package/codeyam-cli/src/utils/__tests__/editorShouldRevalidate.test.js +53 -0
  147. package/codeyam-cli/src/utils/__tests__/editorShouldRevalidate.test.js.map +1 -0
  148. package/codeyam-cli/src/utils/__tests__/entityChangeStatus.test.js +455 -20
  149. package/codeyam-cli/src/utils/__tests__/entityChangeStatus.test.js.map +1 -1
  150. package/codeyam-cli/src/utils/__tests__/envFile.test.js +125 -0
  151. package/codeyam-cli/src/utils/__tests__/envFile.test.js.map +1 -0
  152. package/codeyam-cli/src/utils/__tests__/glossaryAdd.test.js +177 -0
  153. package/codeyam-cli/src/utils/__tests__/glossaryAdd.test.js.map +1 -0
  154. package/codeyam-cli/src/utils/__tests__/handoffContext.test.js +500 -0
  155. package/codeyam-cli/src/utils/__tests__/handoffContext.test.js.map +1 -0
  156. package/codeyam-cli/src/utils/__tests__/journalCaptureStabilization.test.js +16 -1
  157. package/codeyam-cli/src/utils/__tests__/journalCaptureStabilization.test.js.map +1 -1
  158. package/codeyam-cli/src/utils/__tests__/manualEntityAnalysis.test.js +302 -0
  159. package/codeyam-cli/src/utils/__tests__/manualEntityAnalysis.test.js.map +1 -0
  160. package/codeyam-cli/src/utils/__tests__/parseRegisterArg.test.js +30 -2
  161. package/codeyam-cli/src/utils/__tests__/parseRegisterArg.test.js.map +1 -1
  162. package/codeyam-cli/src/utils/__tests__/registerScenarioResult.test.js +127 -0
  163. package/codeyam-cli/src/utils/__tests__/registerScenarioResult.test.js.map +1 -0
  164. package/codeyam-cli/src/utils/__tests__/routePatternMatching.test.js +118 -0
  165. package/codeyam-cli/src/utils/__tests__/routePatternMatching.test.js.map +1 -0
  166. package/codeyam-cli/src/utils/__tests__/scenarioCoverage.test.js +284 -0
  167. package/codeyam-cli/src/utils/__tests__/scenarioCoverage.test.js.map +1 -0
  168. package/codeyam-cli/src/utils/__tests__/scenariosManifest.test.js +649 -223
  169. package/codeyam-cli/src/utils/__tests__/scenariosManifest.test.js.map +1 -1
  170. package/codeyam-cli/src/utils/__tests__/screenshotHash.test.js +84 -0
  171. package/codeyam-cli/src/utils/__tests__/screenshotHash.test.js.map +1 -0
  172. package/codeyam-cli/src/utils/__tests__/setupClaudeCodeSettings.test.js +1 -0
  173. package/codeyam-cli/src/utils/__tests__/setupClaudeCodeSettings.test.js.map +1 -1
  174. package/codeyam-cli/src/utils/__tests__/telemetry.test.js +159 -0
  175. package/codeyam-cli/src/utils/__tests__/telemetry.test.js.map +1 -0
  176. package/codeyam-cli/src/utils/__tests__/templateConsistency.test.js +2 -1
  177. package/codeyam-cli/src/utils/__tests__/templateConsistency.test.js.map +1 -1
  178. package/codeyam-cli/src/utils/__tests__/testRunner.test.js +216 -0
  179. package/codeyam-cli/src/utils/__tests__/testRunner.test.js.map +1 -0
  180. package/codeyam-cli/src/utils/__tests__/webappDetection.test.js +148 -0
  181. package/codeyam-cli/src/utils/__tests__/webappDetection.test.js.map +1 -0
  182. package/codeyam-cli/src/utils/analysisRunner.js +39 -8
  183. package/codeyam-cli/src/utils/analysisRunner.js.map +1 -1
  184. package/codeyam-cli/src/utils/analyzer.js +19 -0
  185. package/codeyam-cli/src/utils/analyzer.js.map +1 -1
  186. package/codeyam-cli/src/utils/analyzerFinalization.js +100 -0
  187. package/codeyam-cli/src/utils/analyzerFinalization.js.map +1 -0
  188. package/codeyam-cli/src/utils/backgroundServer.js +93 -17
  189. package/codeyam-cli/src/utils/backgroundServer.js.map +1 -1
  190. package/codeyam-cli/src/utils/database.js +37 -2
  191. package/codeyam-cli/src/utils/database.js.map +1 -1
  192. package/codeyam-cli/src/utils/designSystemShowcase.js +810 -0
  193. package/codeyam-cli/src/utils/designSystemShowcase.js.map +1 -0
  194. package/codeyam-cli/src/utils/devServerState.js +32 -0
  195. package/codeyam-cli/src/utils/devServerState.js.map +1 -1
  196. package/codeyam-cli/src/utils/editorApi.js +27 -5
  197. package/codeyam-cli/src/utils/editorApi.js.map +1 -1
  198. package/codeyam-cli/src/utils/editorAudit.js +700 -10
  199. package/codeyam-cli/src/utils/editorAudit.js.map +1 -1
  200. package/codeyam-cli/src/utils/editorBroadcastViewport.js +26 -0
  201. package/codeyam-cli/src/utils/editorBroadcastViewport.js.map +1 -0
  202. package/codeyam-cli/src/utils/editorDeleteScenario.js +67 -0
  203. package/codeyam-cli/src/utils/editorDeleteScenario.js.map +1 -0
  204. package/codeyam-cli/src/utils/editorDevServer.js +89 -1
  205. package/codeyam-cli/src/utils/editorDevServer.js.map +1 -1
  206. package/codeyam-cli/src/utils/editorEntityChangeStatus.js +13 -7
  207. package/codeyam-cli/src/utils/editorEntityChangeStatus.js.map +1 -1
  208. package/codeyam-cli/src/utils/editorEntityHelpers.js +144 -0
  209. package/codeyam-cli/src/utils/editorEntityHelpers.js.map +1 -0
  210. package/codeyam-cli/src/utils/editorGuard.js +36 -0
  211. package/codeyam-cli/src/utils/editorGuard.js.map +1 -0
  212. package/codeyam-cli/src/utils/editorLoaderHelpers.js +72 -1
  213. package/codeyam-cli/src/utils/editorLoaderHelpers.js.map +1 -1
  214. package/codeyam-cli/src/utils/editorMigration.js +224 -0
  215. package/codeyam-cli/src/utils/editorMigration.js.map +1 -0
  216. package/codeyam-cli/src/utils/editorPreview.js +35 -2
  217. package/codeyam-cli/src/utils/editorPreview.js.map +1 -1
  218. package/codeyam-cli/src/utils/editorRecapture.js +109 -0
  219. package/codeyam-cli/src/utils/editorRecapture.js.map +1 -0
  220. package/codeyam-cli/src/utils/editorRoadmap.js +574 -0
  221. package/codeyam-cli/src/utils/editorRoadmap.js.map +1 -0
  222. package/codeyam-cli/src/utils/editorScenarioSwitch.js +39 -2
  223. package/codeyam-cli/src/utils/editorScenarioSwitch.js.map +1 -1
  224. package/codeyam-cli/src/utils/editorScenarios.js +591 -0
  225. package/codeyam-cli/src/utils/editorScenarios.js.map +1 -1
  226. package/codeyam-cli/src/utils/editorSeedAdapter.js +308 -6
  227. package/codeyam-cli/src/utils/editorSeedAdapter.js.map +1 -1
  228. package/codeyam-cli/src/utils/editorShouldRevalidate.js +21 -0
  229. package/codeyam-cli/src/utils/editorShouldRevalidate.js.map +1 -0
  230. package/codeyam-cli/src/utils/entityChangeStatus.js +62 -5
  231. package/codeyam-cli/src/utils/entityChangeStatus.js.map +1 -1
  232. package/codeyam-cli/src/utils/entityChangeStatus.server.js +128 -8
  233. package/codeyam-cli/src/utils/entityChangeStatus.server.js.map +1 -1
  234. package/codeyam-cli/src/utils/envFile.js +90 -0
  235. package/codeyam-cli/src/utils/envFile.js.map +1 -0
  236. package/codeyam-cli/src/utils/fileWatcher.js +38 -0
  237. package/codeyam-cli/src/utils/fileWatcher.js.map +1 -1
  238. package/codeyam-cli/src/utils/glossaryAdd.js +74 -0
  239. package/codeyam-cli/src/utils/glossaryAdd.js.map +1 -0
  240. package/codeyam-cli/src/utils/handoffContext.js +257 -0
  241. package/codeyam-cli/src/utils/handoffContext.js.map +1 -0
  242. package/codeyam-cli/src/utils/install-skills.js +50 -6
  243. package/codeyam-cli/src/utils/install-skills.js.map +1 -1
  244. package/codeyam-cli/src/utils/manualEntityAnalysis.js +196 -0
  245. package/codeyam-cli/src/utils/manualEntityAnalysis.js.map +1 -0
  246. package/codeyam-cli/src/utils/parseRegisterArg.js.map +1 -1
  247. package/codeyam-cli/src/utils/progress.js +2 -2
  248. package/codeyam-cli/src/utils/progress.js.map +1 -1
  249. package/codeyam-cli/src/utils/queue/__tests__/job.interactiveStart.test.js +159 -0
  250. package/codeyam-cli/src/utils/queue/__tests__/job.interactiveStart.test.js.map +1 -0
  251. package/codeyam-cli/src/utils/queue/job.js +35 -6
  252. package/codeyam-cli/src/utils/queue/job.js.map +1 -1
  253. package/codeyam-cli/src/utils/registerScenarioResult.js +52 -0
  254. package/codeyam-cli/src/utils/registerScenarioResult.js.map +1 -0
  255. package/codeyam-cli/src/utils/routePatternMatching.js +129 -0
  256. package/codeyam-cli/src/utils/routePatternMatching.js.map +1 -0
  257. package/codeyam-cli/src/utils/scenarioCoverage.js +77 -0
  258. package/codeyam-cli/src/utils/scenarioCoverage.js.map +1 -0
  259. package/codeyam-cli/src/utils/scenariosManifest.js +275 -74
  260. package/codeyam-cli/src/utils/scenariosManifest.js.map +1 -1
  261. package/codeyam-cli/src/utils/screenshotHash.js +26 -0
  262. package/codeyam-cli/src/utils/screenshotHash.js.map +1 -0
  263. package/codeyam-cli/src/utils/serverState.js +30 -0
  264. package/codeyam-cli/src/utils/serverState.js.map +1 -1
  265. package/codeyam-cli/src/utils/setupClaudeCodeSettings.js +1 -0
  266. package/codeyam-cli/src/utils/setupClaudeCodeSettings.js.map +1 -1
  267. package/codeyam-cli/src/utils/simulationGateMiddleware.js +17 -1
  268. package/codeyam-cli/src/utils/simulationGateMiddleware.js.map +1 -1
  269. package/codeyam-cli/src/utils/slugUtils.js +25 -0
  270. package/codeyam-cli/src/utils/slugUtils.js.map +1 -0
  271. package/codeyam-cli/src/utils/syncMocksMiddleware.js +2 -2
  272. package/codeyam-cli/src/utils/syncMocksMiddleware.js.map +1 -1
  273. package/codeyam-cli/src/utils/techStackConfig.js +38 -0
  274. package/codeyam-cli/src/utils/techStackConfig.js.map +1 -0
  275. package/codeyam-cli/src/utils/techStackConfig.test.js +85 -0
  276. package/codeyam-cli/src/utils/techStackConfig.test.js.map +1 -0
  277. package/codeyam-cli/src/utils/telemetry.js +106 -0
  278. package/codeyam-cli/src/utils/telemetry.js.map +1 -0
  279. package/codeyam-cli/src/utils/telemetryMiddleware.js +22 -0
  280. package/codeyam-cli/src/utils/telemetryMiddleware.js.map +1 -0
  281. package/codeyam-cli/src/utils/testResultCache.js +53 -0
  282. package/codeyam-cli/src/utils/testResultCache.js.map +1 -0
  283. package/codeyam-cli/src/utils/testResultCache.server.js +81 -0
  284. package/codeyam-cli/src/utils/testResultCache.server.js.map +1 -0
  285. package/codeyam-cli/src/utils/testResultCache.server.test.js +187 -0
  286. package/codeyam-cli/src/utils/testResultCache.server.test.js.map +1 -0
  287. package/codeyam-cli/src/utils/testResultCache.test.js +230 -0
  288. package/codeyam-cli/src/utils/testResultCache.test.js.map +1 -0
  289. package/codeyam-cli/src/utils/testRunner.js +193 -1
  290. package/codeyam-cli/src/utils/testRunner.js.map +1 -1
  291. package/codeyam-cli/src/utils/webappDetection.js +25 -2
  292. package/codeyam-cli/src/utils/webappDetection.js.map +1 -1
  293. package/codeyam-cli/src/webserver/__tests__/api.interactive-switch-scenario.test.js +99 -0
  294. package/codeyam-cli/src/webserver/__tests__/api.interactive-switch-scenario.test.js.map +1 -0
  295. package/codeyam-cli/src/webserver/__tests__/buildPtyEnv.test.js +153 -0
  296. package/codeyam-cli/src/webserver/__tests__/buildPtyEnv.test.js.map +1 -0
  297. package/codeyam-cli/src/webserver/__tests__/clientErrors.test.js +107 -0
  298. package/codeyam-cli/src/webserver/__tests__/clientErrors.test.js.map +1 -0
  299. package/codeyam-cli/src/webserver/__tests__/editorProxy.test.js +1000 -0
  300. package/codeyam-cli/src/webserver/__tests__/editorProxy.test.js.map +1 -0
  301. package/codeyam-cli/src/webserver/__tests__/idleDetector.test.js +315 -0
  302. package/codeyam-cli/src/webserver/__tests__/idleDetector.test.js.map +1 -0
  303. package/codeyam-cli/src/webserver/__tests__/stripClaudeCommand.test.js +135 -0
  304. package/codeyam-cli/src/webserver/__tests__/stripClaudeCommand.test.js.map +1 -0
  305. package/codeyam-cli/src/webserver/app/lib/clientErrors.js +86 -0
  306. package/codeyam-cli/src/webserver/app/lib/clientErrors.js.map +1 -0
  307. package/codeyam-cli/src/webserver/app/lib/database.js.map +1 -1
  308. package/codeyam-cli/src/webserver/app/lib/git.js +3 -2
  309. package/codeyam-cli/src/webserver/app/lib/git.js.map +1 -1
  310. package/codeyam-cli/src/webserver/app/routes/api.interactive-switch-scenario.js +34 -0
  311. package/codeyam-cli/src/webserver/app/routes/api.interactive-switch-scenario.js.map +1 -0
  312. package/codeyam-cli/src/webserver/app/types/editor.js +8 -0
  313. package/codeyam-cli/src/webserver/app/types/editor.js.map +1 -0
  314. package/codeyam-cli/src/webserver/backgroundServer.js +60 -61
  315. package/codeyam-cli/src/webserver/backgroundServer.js.map +1 -1
  316. package/codeyam-cli/src/webserver/build/client/assets/CopyButton-DTBZZfSk.js +1 -0
  317. package/codeyam-cli/src/webserver/build/client/assets/{EntityItem-C76mRRiF.js → EntityItem-BxclONWq.js} +5 -5
  318. package/codeyam-cli/src/webserver/build/client/assets/EntityTypeBadge-CQgyEGV-.js +1 -0
  319. package/codeyam-cli/src/webserver/build/client/assets/{EntityTypeIcon-CobE682z.js → EntityTypeIcon-BsnEOJZ_.js} +9 -9
  320. package/codeyam-cli/src/webserver/build/client/assets/InlineSpinner-ByaELMbv.js +1 -0
  321. package/codeyam-cli/src/webserver/build/client/assets/InteractivePreview-6WjVfhxX.js +25 -0
  322. package/codeyam-cli/src/webserver/build/client/assets/LibraryFunctionPreview-ChX-Hp7W.js +3 -0
  323. package/codeyam-cli/src/webserver/build/client/assets/{LoadingDots-BU_OAEMP.js → LoadingDots-By5zI316.js} +1 -1
  324. package/codeyam-cli/src/webserver/build/client/assets/{LogViewer-ceAyBX-H.js → LogViewer-C-9zQdXg.js} +3 -3
  325. package/codeyam-cli/src/webserver/build/client/assets/MiniClaudeChat-Bs2_Oua4.js +36 -0
  326. package/codeyam-cli/src/webserver/build/client/assets/{ReportIssueModal-djPLI-WV.js → ReportIssueModal-DQsceHVv.js} +4 -4
  327. package/codeyam-cli/src/webserver/build/client/assets/SafeScreenshot-DThcm_9M.js +1 -0
  328. package/codeyam-cli/src/webserver/build/client/assets/{ScenarioViewer-ZlRKbhrq.js → ScenarioViewer-Cl4oOA3A.js} +3 -3
  329. package/codeyam-cli/src/webserver/build/client/assets/Spinner-CIil5-gb.js +34 -0
  330. package/codeyam-cli/src/webserver/build/client/assets/TruncatedFilePath-CK7-NaPZ.js +1 -0
  331. package/codeyam-cli/src/webserver/build/client/assets/ViewportInspectBar-BqkA9zyZ.js +1 -0
  332. package/codeyam-cli/src/webserver/build/client/assets/{_index-C96V0n15.js → _index-DnOgyseQ.js} +4 -4
  333. package/codeyam-cli/src/webserver/build/client/assets/{activity.(_tab)-BpKzcsJz.js → activity.(_tab)-DqM9hbNE.js} +8 -8
  334. package/codeyam-cli/src/webserver/build/client/assets/{addon-web-links-Duc5hnl7.js → addon-web-links-C58dYPwR.js} +1 -1
  335. package/codeyam-cli/src/webserver/build/client/assets/{agent-transcripts-D9hemwl6.js → agent-transcripts-B8NCeOrm.js} +7 -7
  336. package/codeyam-cli/src/webserver/build/client/assets/api.editor-database-verify-l0sNRNKZ.js +1 -0
  337. package/codeyam-cli/src/webserver/build/client/assets/api.editor-github-verify-l0sNRNKZ.js +1 -0
  338. package/codeyam-cli/src/webserver/build/client/assets/api.editor-handoff-l0sNRNKZ.js +1 -0
  339. package/codeyam-cli/src/webserver/build/client/assets/api.editor-hosting-verify-l0sNRNKZ.js +1 -0
  340. package/codeyam-cli/src/webserver/build/client/assets/api.editor-recapture-stale-l0sNRNKZ.js +1 -0
  341. package/codeyam-cli/src/webserver/build/client/assets/api.editor-rename-scenario-l0sNRNKZ.js +1 -0
  342. package/codeyam-cli/src/webserver/build/client/assets/api.editor-roadmap-l0sNRNKZ.js +1 -0
  343. package/codeyam-cli/src/webserver/build/client/assets/api.editor-save-scenario-data-l0sNRNKZ.js +1 -0
  344. package/codeyam-cli/src/webserver/build/client/assets/api.editor-save-seed-state-l0sNRNKZ.js +1 -0
  345. package/codeyam-cli/src/webserver/build/client/assets/api.editor-scenario-coverage-l0sNRNKZ.js +1 -0
  346. package/codeyam-cli/src/webserver/build/client/assets/api.editor-scenario-prompt-l0sNRNKZ.js +1 -0
  347. package/codeyam-cli/src/webserver/build/client/assets/api.editor-schema-l0sNRNKZ.js +1 -0
  348. package/codeyam-cli/src/webserver/build/client/assets/api.editor-session-l0sNRNKZ.js +1 -0
  349. package/codeyam-cli/src/webserver/build/client/assets/api.editor-verify-routes-l0sNRNKZ.js +1 -0
  350. package/codeyam-cli/src/webserver/build/client/assets/api.interactive-switch-scenario-l0sNRNKZ.js +1 -0
  351. package/codeyam-cli/src/webserver/build/client/assets/{book-open-D_nMCFmP.js → book-open-BFSIqZgO.js} +2 -2
  352. package/codeyam-cli/src/webserver/build/client/assets/{chevron-down-BH2h1Ea2.js → chevron-down-B9fDzFVh.js} +2 -2
  353. package/codeyam-cli/src/webserver/build/client/assets/chunk-UVKPFVEO-Bmq2apuh.js +43 -0
  354. package/codeyam-cli/src/webserver/build/client/assets/{circle-check-DyIKORY6.js → circle-check-DLPObLUx.js} +2 -2
  355. package/codeyam-cli/src/webserver/build/client/assets/{copy-NDbZjXao.js → copy-DXEmO0TD.js} +3 -3
  356. package/codeyam-cli/src/webserver/build/client/assets/createLucideIcon-BwyFiRot.js +41 -0
  357. package/codeyam-cli/src/webserver/build/client/assets/cy-logo-cli-Coe5NhbS.js +1 -0
  358. package/codeyam-cli/src/webserver/build/client/assets/{cy-logo-cli-CCKUIm0S.svg → cy-logo-cli-DoA97ML3.svg} +2 -2
  359. package/codeyam-cli/src/webserver/build/client/assets/dev.empty-iRhRIFlp.js +1 -0
  360. package/codeyam-cli/src/webserver/build/client/assets/editor._tab-BZPBzV73.js +1 -0
  361. package/codeyam-cli/src/webserver/build/client/assets/editor.entity.(_sha)-DhtVC4aI.js +161 -0
  362. package/codeyam-cli/src/webserver/build/client/assets/editorPreview-C6fEYHrh.js +41 -0
  363. package/codeyam-cli/src/webserver/build/client/assets/{entity._sha._-DItJnD8s.js → entity._sha._-pc-vc6wO.js} +14 -13
  364. package/codeyam-cli/src/webserver/build/client/assets/entity._sha.scenarios._scenarioId.dev-C8AyYgYT.js +6 -0
  365. package/codeyam-cli/src/webserver/build/client/assets/entity._sha.scenarios._scenarioId.fullscreen-DziaVQX1.js +6 -0
  366. package/codeyam-cli/src/webserver/build/client/assets/entity._sha_.create-scenario-BTcpgIpC.js +6 -0
  367. package/codeyam-cli/src/webserver/build/client/assets/{entity._sha_.edit._scenarioId-BMvVHNXU.js → entity._sha_.edit._scenarioId-D_O_ajfZ.js} +2 -2
  368. package/codeyam-cli/src/webserver/build/client/assets/{entry.client-DTvKq3TY.js → entry.client-j1Vi0bco.js} +6 -6
  369. package/codeyam-cli/src/webserver/build/client/assets/fileTableUtils-Daa96Fr1.js +1 -0
  370. package/codeyam-cli/src/webserver/build/client/assets/files-kuny2Q_s.js +1 -0
  371. package/codeyam-cli/src/webserver/build/client/assets/git-DgCZPMie.js +1 -0
  372. package/codeyam-cli/src/webserver/build/client/assets/globals-L-aUIeux.css +1 -0
  373. package/codeyam-cli/src/webserver/build/client/assets/{index-BcvgDzbZ.js → index-BliGSSpl.js} +1 -1
  374. package/codeyam-cli/src/webserver/build/client/assets/{index-yHOVb4rc.js → index-SqjQKTdH.js} +1 -1
  375. package/codeyam-cli/src/webserver/build/client/assets/{index-10oVnAAH.js → index-vyrZD2g4.js} +1 -1
  376. package/codeyam-cli/src/webserver/build/client/assets/jsx-runtime-D_zvdyIk.js +9 -0
  377. package/codeyam-cli/src/webserver/build/client/assets/labs-c3yLxSEp.js +1 -0
  378. package/codeyam-cli/src/webserver/build/client/assets/{loader-circle-BAXYRVEO.js → loader-circle-D-q28GLF.js} +2 -2
  379. package/codeyam-cli/src/webserver/build/client/assets/manifest-79d0d81a.js +1 -0
  380. package/codeyam-cli/src/webserver/build/client/assets/memory-CEWIUC4t.js +101 -0
  381. package/codeyam-cli/src/webserver/build/client/assets/{pause-DTAcYxBt.js → pause-BP6fitdh.js} +3 -3
  382. package/codeyam-cli/src/webserver/build/client/assets/root-L2V0jea7.js +80 -0
  383. package/codeyam-cli/src/webserver/build/client/assets/{search-fKo7v0Zo.js → search-BooqacKS.js} +2 -2
  384. package/codeyam-cli/src/webserver/build/client/assets/settings-BM0nbryO.js +1 -0
  385. package/codeyam-cli/src/webserver/build/client/assets/simulations-ovy6FjRY.js +1 -0
  386. package/codeyam-cli/src/webserver/build/client/assets/{terminal-BG4heKCG.js → terminal-DHemCJIs.js} +3 -3
  387. package/codeyam-cli/src/webserver/build/client/assets/{triangle-alert-DtSmdtM4.js → triangle-alert-D87ekDl8.js} +2 -2
  388. package/codeyam-cli/src/webserver/build/client/assets/useCustomSizes-Dk0Tciqg.js +1 -0
  389. package/codeyam-cli/src/webserver/build/client/assets/useLastLogLine-C8QvIe05.js +2 -0
  390. package/codeyam-cli/src/webserver/build/client/assets/useReportContext-jkCytuYz.js +1 -0
  391. package/codeyam-cli/src/webserver/build/client/assets/useToast-BgqkixU9.js +1 -0
  392. package/codeyam-cli/src/webserver/build/client/sound-test.html +98 -0
  393. package/codeyam-cli/src/webserver/build/server/assets/analysisRunner-QgInFGdU.js +16 -0
  394. package/codeyam-cli/src/webserver/build/server/assets/index-zblh9auj.js +1 -0
  395. package/codeyam-cli/src/webserver/build/server/assets/init-DaE0CBjk.js +14 -0
  396. package/codeyam-cli/src/webserver/build/server/assets/progress-CHTtrxFG.js +1 -0
  397. package/codeyam-cli/src/webserver/build/server/assets/server-build-CNvgz1cC.js +853 -0
  398. package/codeyam-cli/src/webserver/build/server/index.js +1 -1
  399. package/codeyam-cli/src/webserver/build-info.json +5 -5
  400. package/codeyam-cli/src/webserver/editorProxy.js +849 -17
  401. package/codeyam-cli/src/webserver/editorProxy.js.map +1 -1
  402. package/codeyam-cli/src/webserver/idleDetector.js +130 -0
  403. package/codeyam-cli/src/webserver/idleDetector.js.map +1 -0
  404. package/codeyam-cli/src/webserver/mockStateEvents.js +28 -0
  405. package/codeyam-cli/src/webserver/mockStateEvents.js.map +1 -0
  406. package/codeyam-cli/src/webserver/public/sound-test.html +98 -0
  407. package/codeyam-cli/src/webserver/scripts/journalCapture.ts +53 -0
  408. package/codeyam-cli/src/webserver/server.js +192 -4
  409. package/codeyam-cli/src/webserver/server.js.map +1 -1
  410. package/codeyam-cli/src/webserver/terminalServer.js +394 -57
  411. package/codeyam-cli/src/webserver/terminalServer.js.map +1 -1
  412. package/codeyam-cli/templates/__tests__/editor-step-hook.prompt-capture.test.ts +118 -0
  413. package/codeyam-cli/templates/chrome-extension-react/EXTENSION_SETUP.md +75 -0
  414. package/codeyam-cli/templates/chrome-extension-react/README.md +46 -0
  415. package/codeyam-cli/templates/chrome-extension-react/gitignore +15 -0
  416. package/codeyam-cli/templates/chrome-extension-react/index.html +12 -0
  417. package/codeyam-cli/templates/chrome-extension-react/package.json +27 -0
  418. package/codeyam-cli/templates/chrome-extension-react/popup.html +12 -0
  419. package/codeyam-cli/templates/chrome-extension-react/public/manifest.json +15 -0
  420. package/codeyam-cli/templates/chrome-extension-react/src/background/service-worker.ts +7 -0
  421. package/codeyam-cli/templates/chrome-extension-react/src/globals.css +6 -0
  422. package/codeyam-cli/templates/chrome-extension-react/src/lib/storage.ts +37 -0
  423. package/codeyam-cli/templates/chrome-extension-react/src/popup/App.tsx +12 -0
  424. package/codeyam-cli/templates/chrome-extension-react/src/popup/main.tsx +10 -0
  425. package/codeyam-cli/templates/chrome-extension-react/tsconfig.json +24 -0
  426. package/codeyam-cli/templates/chrome-extension-react/vite.config.ts +41 -0
  427. package/codeyam-cli/templates/codeyam-editor-claude.md +86 -5
  428. package/codeyam-cli/templates/codeyam-editor-codex.md +61 -0
  429. package/codeyam-cli/templates/codeyam-editor-gemini.md +59 -0
  430. package/codeyam-cli/templates/codeyam-editor-reference.md +216 -0
  431. package/codeyam-cli/templates/design-systems/clean-dashboard-design-system.md +255 -0
  432. package/codeyam-cli/templates/design-systems/editorial-design-system.md +267 -0
  433. package/codeyam-cli/templates/design-systems/mono-brutalist-design-system.md +256 -0
  434. package/codeyam-cli/templates/design-systems/neo-brutalist-design-system.md +294 -0
  435. package/codeyam-cli/templates/editor-step-hook.py +214 -54
  436. package/codeyam-cli/templates/expo-react-native/MOBILE_SETUP.md +288 -0
  437. package/codeyam-cli/templates/expo-react-native/README.md +41 -0
  438. package/codeyam-cli/templates/expo-react-native/__tests__/.gitkeep +0 -0
  439. package/codeyam-cli/templates/expo-react-native/app/_layout.tsx +15 -0
  440. package/codeyam-cli/templates/expo-react-native/app/index.tsx +36 -0
  441. package/codeyam-cli/templates/expo-react-native/app.json +29 -0
  442. package/codeyam-cli/templates/expo-react-native/babel.config.js +10 -0
  443. package/codeyam-cli/templates/expo-react-native/gitignore +14 -0
  444. package/codeyam-cli/templates/expo-react-native/global.css +10 -0
  445. package/codeyam-cli/templates/expo-react-native/lib/storage.ts +32 -0
  446. package/codeyam-cli/templates/expo-react-native/lib/theme.ts +73 -0
  447. package/codeyam-cli/templates/expo-react-native/metro.config.js +6 -0
  448. package/codeyam-cli/templates/expo-react-native/nativewind-env.d.ts +1 -0
  449. package/codeyam-cli/templates/expo-react-native/package.json +54 -0
  450. package/codeyam-cli/templates/expo-react-native/patches/expo-modules-autolinking+3.0.24.patch +29 -0
  451. package/codeyam-cli/templates/expo-react-native/tailwind.config.js +10 -0
  452. package/codeyam-cli/templates/expo-react-native/tsconfig.json +10 -0
  453. package/codeyam-cli/templates/isolation-route/expo-router.tsx.template +54 -0
  454. package/codeyam-cli/templates/nextjs-prisma-sqlite/AUTH_PATTERNS.md +308 -0
  455. package/codeyam-cli/templates/nextjs-prisma-sqlite/AUTH_UPGRADE.md +304 -0
  456. package/codeyam-cli/templates/nextjs-prisma-sqlite/DATABASE.md +126 -0
  457. package/codeyam-cli/templates/nextjs-prisma-sqlite/FEATURE_PATTERNS.md +37 -0
  458. package/codeyam-cli/templates/nextjs-prisma-sqlite/README.md +53 -0
  459. package/codeyam-cli/templates/nextjs-prisma-sqlite/app/lib/prisma.ts +9 -4
  460. package/codeyam-cli/templates/nextjs-prisma-sqlite/env +4 -0
  461. package/codeyam-cli/templates/nextjs-prisma-sqlite/gitignore +1 -0
  462. package/codeyam-cli/templates/nextjs-prisma-sqlite/package.json +2 -1
  463. package/codeyam-cli/templates/nextjs-prisma-sqlite/prisma/seed.ts +4 -1
  464. package/codeyam-cli/templates/nextjs-prisma-sqlite/seed-adapter.ts +92 -41
  465. package/codeyam-cli/templates/nextjs-prisma-supabase/README.md +52 -0
  466. package/codeyam-cli/templates/{nextjs-prisma-sqlite/PRISMA_SETUP.md → nextjs-prisma-supabase/SUPABASE_SETUP.md} +37 -17
  467. package/codeyam-cli/templates/nextjs-prisma-supabase/app/api/todos/route.ts +17 -0
  468. package/codeyam-cli/templates/nextjs-prisma-supabase/app/globals.css +26 -0
  469. package/codeyam-cli/templates/nextjs-prisma-supabase/app/layout.tsx +34 -0
  470. package/codeyam-cli/templates/nextjs-prisma-supabase/app/lib/prisma.ts +20 -0
  471. package/codeyam-cli/templates/nextjs-prisma-supabase/app/lib/supabase.ts +12 -0
  472. package/codeyam-cli/templates/nextjs-prisma-supabase/app/page.tsx +10 -0
  473. package/codeyam-cli/templates/nextjs-prisma-supabase/env +9 -0
  474. package/codeyam-cli/templates/nextjs-prisma-supabase/eslint.config.mjs +11 -0
  475. package/codeyam-cli/templates/nextjs-prisma-supabase/gitignore +40 -0
  476. package/codeyam-cli/templates/nextjs-prisma-supabase/next.config.ts +11 -0
  477. package/codeyam-cli/templates/nextjs-prisma-supabase/package.json +37 -0
  478. package/codeyam-cli/templates/nextjs-prisma-supabase/postcss.config.mjs +7 -0
  479. package/codeyam-cli/templates/nextjs-prisma-supabase/prisma/schema.prisma +27 -0
  480. package/codeyam-cli/templates/nextjs-prisma-supabase/prisma/seed.ts +39 -0
  481. package/codeyam-cli/templates/nextjs-prisma-supabase/prisma.config.ts +12 -0
  482. package/codeyam-cli/templates/nextjs-prisma-supabase/tsconfig.json +34 -0
  483. package/codeyam-cli/templates/seed-adapters/supabase.ts +475 -0
  484. package/codeyam-cli/templates/skills/codeyam-dev-mode/SKILL.md +1 -1
  485. package/codeyam-cli/templates/skills/codeyam-editor/SKILL.md +119 -11
  486. package/package.json +2 -1
  487. package/packages/ai/src/lib/astScopes/methodSemantics.js +99 -0
  488. package/packages/ai/src/lib/astScopes/methodSemantics.js.map +1 -1
  489. package/packages/ai/src/lib/astScopes/nodeToSource.js +16 -0
  490. package/packages/ai/src/lib/astScopes/nodeToSource.js.map +1 -1
  491. package/packages/ai/src/lib/astScopes/paths.js +12 -3
  492. package/packages/ai/src/lib/astScopes/paths.js.map +1 -1
  493. package/packages/ai/src/lib/dataStructure/ScopeDataStructure.js +27 -10
  494. package/packages/ai/src/lib/dataStructure/ScopeDataStructure.js.map +1 -1
  495. package/packages/ai/src/lib/dataStructure/equivalencyManagers/ParentScopeManager.js +9 -2
  496. package/packages/ai/src/lib/dataStructure/equivalencyManagers/ParentScopeManager.js.map +1 -1
  497. package/packages/ai/src/lib/dataStructure/helpers/cleanKnownObjectFunctions.js +14 -4
  498. package/packages/ai/src/lib/dataStructure/helpers/cleanKnownObjectFunctions.js.map +1 -1
  499. package/packages/analyze/index.js +1 -1
  500. package/packages/analyze/index.js.map +1 -1
  501. package/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.js +16 -2
  502. package/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.js.map +1 -1
  503. package/packages/analyze/src/lib/files/analyze/analyzeEntities.js +6 -26
  504. package/packages/analyze/src/lib/files/analyze/analyzeEntities.js.map +1 -1
  505. package/packages/analyze/src/lib/files/analyze/findOrCreateEntity.js +3 -2
  506. package/packages/analyze/src/lib/files/analyze/findOrCreateEntity.js.map +1 -1
  507. package/packages/analyze/src/lib/files/analyze/gatherEntityMap.js +9 -7
  508. package/packages/analyze/src/lib/files/analyze/gatherEntityMap.js.map +1 -1
  509. package/packages/analyze/src/lib/files/analyze/trackEntityCircularDependencies.js +14 -0
  510. package/packages/analyze/src/lib/files/analyze/trackEntityCircularDependencies.js.map +1 -1
  511. package/packages/analyze/src/lib/files/analyze/validateDependencyAnalyses.js +44 -11
  512. package/packages/analyze/src/lib/files/analyze/validateDependencyAnalyses.js.map +1 -1
  513. package/packages/analyze/src/lib/files/analyzeChange.js +1 -0
  514. package/packages/analyze/src/lib/files/analyzeChange.js.map +1 -1
  515. package/packages/analyze/src/lib/files/analyzeInitial.js +1 -0
  516. package/packages/analyze/src/lib/files/analyzeInitial.js.map +1 -1
  517. package/packages/analyze/src/lib/files/analyzeNextRoute.js +5 -1
  518. package/packages/analyze/src/lib/files/analyzeNextRoute.js.map +1 -1
  519. package/packages/analyze/src/lib/files/scenarios/generateDataStructure.js +120 -28
  520. package/packages/analyze/src/lib/files/scenarios/generateDataStructure.js.map +1 -1
  521. package/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.js +1368 -1193
  522. package/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.js.map +1 -1
  523. package/packages/database/src/lib/kysely/tables/editorScenariosTable.js +98 -0
  524. package/packages/database/src/lib/kysely/tables/editorScenariosTable.js.map +1 -1
  525. package/packages/database/src/lib/loadAnalysis.js +7 -1
  526. package/packages/database/src/lib/loadAnalysis.js.map +1 -1
  527. package/packages/database/src/lib/loadEntities.js +0 -6
  528. package/packages/database/src/lib/loadEntities.js.map +1 -1
  529. package/packages/database/src/lib/loadEntity.js +5 -5
  530. package/packages/database/src/lib/loadEntity.js.map +1 -1
  531. package/packages/database/src/lib/updateCommitMetadata.js +0 -25
  532. package/packages/database/src/lib/updateCommitMetadata.js.map +1 -1
  533. package/packages/types/src/enums/ProjectFramework.js +2 -0
  534. package/packages/types/src/enums/ProjectFramework.js.map +1 -1
  535. package/packages/utils/src/lib/fs/rsyncCopy.js +22 -1
  536. package/packages/utils/src/lib/fs/rsyncCopy.js.map +1 -1
  537. package/codeyam-cli/src/webserver/build/client/assets/CopyButton-DmJveP3T.js +0 -1
  538. package/codeyam-cli/src/webserver/build/client/assets/EntityTypeBadge-g3saevPb.js +0 -1
  539. package/codeyam-cli/src/webserver/build/client/assets/InlineSpinner-Bu6c6aDe.js +0 -1
  540. package/codeyam-cli/src/webserver/build/client/assets/InteractivePreview-DYFW3lDD.js +0 -25
  541. package/codeyam-cli/src/webserver/build/client/assets/LibraryFunctionPreview-DLeucoVX.js +0 -3
  542. package/codeyam-cli/src/webserver/build/client/assets/SafeScreenshot-BED4B6sP.js +0 -1
  543. package/codeyam-cli/src/webserver/build/client/assets/Spinner-Bb5uFQ5V.js +0 -34
  544. package/codeyam-cli/src/webserver/build/client/assets/TruncatedFilePath-C8OKAR5x.js +0 -1
  545. package/codeyam-cli/src/webserver/build/client/assets/ViewportInspectBar-oAf2Kqsf.js +0 -1
  546. package/codeyam-cli/src/webserver/build/client/assets/chunk-JZWAC4HX-C4pqxYJB.js +0 -51
  547. package/codeyam-cli/src/webserver/build/client/assets/createLucideIcon-CMT1jU2q.js +0 -21
  548. package/codeyam-cli/src/webserver/build/client/assets/cy-logo-cli-DcX-ZS3p.js +0 -1
  549. package/codeyam-cli/src/webserver/build/client/assets/dev.empty-CltMNppm.js +0 -1
  550. package/codeyam-cli/src/webserver/build/client/assets/editor-DTEBHY7Z.js +0 -10
  551. package/codeyam-cli/src/webserver/build/client/assets/editorPreview-B7ztwLut.js +0 -41
  552. package/codeyam-cli/src/webserver/build/client/assets/entity._sha.scenarios._scenarioId.dev-D5rYBT5x.js +0 -6
  553. package/codeyam-cli/src/webserver/build/client/assets/entity._sha.scenarios._scenarioId.fullscreen-CF164ouH.js +0 -6
  554. package/codeyam-cli/src/webserver/build/client/assets/entity._sha_.create-scenario-p9hhkjJM.js +0 -6
  555. package/codeyam-cli/src/webserver/build/client/assets/fileTableUtils-cPo8LiG3.js +0 -1
  556. package/codeyam-cli/src/webserver/build/client/assets/files-DO4CZ16O.js +0 -1
  557. package/codeyam-cli/src/webserver/build/client/assets/git-CdN8sCqs.js +0 -1
  558. package/codeyam-cli/src/webserver/build/client/assets/globals-JMY99HpD.css +0 -1
  559. package/codeyam-cli/src/webserver/build/client/assets/labs-Zk7ryIM1.js +0 -1
  560. package/codeyam-cli/src/webserver/build/client/assets/manifest-7aab51c4.js +0 -1
  561. package/codeyam-cli/src/webserver/build/client/assets/memory-Dg0mvYrI.js +0 -96
  562. package/codeyam-cli/src/webserver/build/client/assets/root-FRztnN-P.js +0 -67
  563. package/codeyam-cli/src/webserver/build/client/assets/settings-DfuTtcJP.js +0 -1
  564. package/codeyam-cli/src/webserver/build/client/assets/simulations-B3aOzpCZ.js +0 -1
  565. package/codeyam-cli/src/webserver/build/client/assets/useCustomSizes-CrAK28Bc.js +0 -1
  566. package/codeyam-cli/src/webserver/build/client/assets/useLastLogLine-C14nCb1q.js +0 -2
  567. package/codeyam-cli/src/webserver/build/client/assets/useReportContext-O-jkvSPx.js +0 -1
  568. package/codeyam-cli/src/webserver/build/client/assets/useToast-9FIWuYfK.js +0 -1
  569. package/codeyam-cli/src/webserver/build/server/assets/index-Cz751Dm2.js +0 -1
  570. package/codeyam-cli/src/webserver/build/server/assets/server-build-DSylnYVM.js +0 -367
@@ -4,10 +4,185 @@ 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
+ // Network-idle detection: notify the parent editor when all initial
136
+ // fetch requests have completed, so it can show the preview after
137
+ // client-side data (API calls) has arrived — not just when the DOM loads.
138
+ var inflight = 0;
139
+ var settled = false;
140
+ var settleTimer = null;
141
+ var origFetch = window.fetch;
142
+ window.fetch = function() {
143
+ if (!settled) inflight++;
144
+ return origFetch.apply(this, arguments).then(function(resp) {
145
+ if (!settled) { inflight--; checkSettle(); }
146
+ return resp;
147
+ }, function(err) {
148
+ if (!settled) { inflight--; checkSettle(); }
149
+ throw err;
150
+ });
151
+ };
152
+ function checkSettle() {
153
+ if (inflight <= 0 && !settled) {
154
+ clearTimeout(settleTimer);
155
+ // Small delay to allow React to re-render with the fetched data
156
+ settleTimer = setTimeout(function() {
157
+ if (inflight <= 0) {
158
+ settled = true;
159
+ try {
160
+ window.parent.postMessage({ type: 'codeyam-preview-ready' }, '*');
161
+ } catch(e) {}
162
+ }
163
+ }, 100);
164
+ }
165
+ }
166
+ // Fallback: if no fetches happen (static page), settle after load
167
+ window.addEventListener('load', function() {
168
+ setTimeout(function() { checkSettle(); }, 200);
169
+ });
170
+ })();
171
+ </script>`;
9
172
  const CACHE_TTL_MS = 500;
10
173
  let scenarioCache = { data: null, timestamp: 0 };
174
+ // Session config extracted from the active scenario — drives cookie injection
175
+ let sessionConfig = undefined;
176
+ /** Session cookies from the seed adapter (e.g. Supabase auth tokens). */
177
+ let seedSessionCookies = undefined;
178
+ // localStorage config extracted from the active scenario — drives HTML injection
179
+ let localStorageConfig = null;
180
+ // Active scenario ID — used to gate localStorage seeding (only re-seed on switch)
181
+ let activeScenarioId = null;
182
+ // Prototype ID — used to gate a one-time localStorage.clear() when a new project is scaffolded
183
+ let currentPrototypeId = null;
184
+ // Current scenario type — 'application'/'user' for seed-based, 'component' for mock-based
185
+ let currentScenarioType = null;
11
186
  // Max body size to buffer for mock matching (10MB)
12
187
  const MAX_BODY_SIZE = 10 * 1024 * 1024;
13
188
  function getProxyState() {
@@ -61,6 +236,8 @@ function readScenarioData() {
61
236
  const active = JSON.parse(fs.readFileSync(activeScenarioPath, 'utf-8'));
62
237
  const scenarioId = active.scenarioId;
63
238
  if (!scenarioId) {
239
+ // No active scenario — but may have a prototypeId for localStorage clearing
240
+ currentPrototypeId = active.prototypeId || null;
64
241
  scenarioCache = { data: null, timestamp: now };
65
242
  return null;
66
243
  }
@@ -71,8 +248,16 @@ function readScenarioData() {
71
248
  return null;
72
249
  }
73
250
  const rawData = JSON.parse(fs.readFileSync(dataFilePath, 'utf-8'));
251
+ // Extract session config for cookie injection
252
+ sessionConfig = rawData.session || null;
253
+ // Extract seed adapter session cookies (e.g. Supabase auth)
254
+ seedSessionCookies = rawData.sessionCookies || undefined;
255
+ // Extract localStorage config for HTML injection
256
+ localStorageConfig = rawData.localStorage || null;
257
+ activeScenarioId = scenarioId;
74
258
  // Type-aware: for seed-based scenarios, only serve externalApis via proxy
75
259
  const scenarioType = active.type || rawData.type || null;
260
+ currentScenarioType = scenarioType;
76
261
  let mockData;
77
262
  if ((scenarioType === 'application' || scenarioType === 'user') &&
78
263
  rawData.seed) {
@@ -128,33 +313,108 @@ function bufferRequestBody(req) {
128
313
  });
129
314
  });
130
315
  }
316
+ /**
317
+ * Strip IPv6 bracket notation for use with http.request hostname.
318
+ * URL.hostname returns `[::1]` for IPv6 but http.request needs `::1`.
319
+ */
320
+ function stripIPv6Brackets(hostname) {
321
+ if (hostname.startsWith('[') && hostname.endsWith(']')) {
322
+ return hostname.slice(1, -1);
323
+ }
324
+ return hostname;
325
+ }
131
326
  /**
132
327
  * Forward a buffered request to the target dev server.
133
328
  * Unlike the streaming forwardRequest, this replays a buffered body.
134
329
  */
135
330
  function forwardBufferedRequest(req, res, targetUrl, bodyBuffer) {
136
331
  const target = new URL(targetUrl);
332
+ const hostname = stripIPv6Brackets(target.hostname);
137
333
  const headers = { ...req.headers, host: `${target.hostname}:${target.port}` };
334
+ // Remove accept-encoding so the dev server returns uncompressed responses.
335
+ // The proxy injects a health script into HTML — this fails on compressed bodies.
336
+ delete headers['accept-encoding'];
337
+ // Inject session cookies into the request so the dev server sees auth
338
+ // on the first request after a scenario switch (before the browser has
339
+ // stored them from Set-Cookie responses).
340
+ injectRequestCookies(headers);
138
341
  // Update content-length if we have the body buffer
139
342
  if (bodyBuffer) {
140
343
  headers['content-length'] = String(bodyBuffer.length);
141
344
  }
142
345
  const options = {
143
- hostname: target.hostname,
346
+ hostname,
144
347
  port: target.port,
145
348
  path: req.url,
146
349
  method: req.method,
147
350
  headers,
148
351
  };
149
352
  const proxyReq = http.request(options, (proxyRes) => {
150
- res.writeHead(proxyRes.statusCode || 200, proxyRes.headers);
353
+ const status = proxyRes.statusCode || 200;
354
+ if (status >= 300 && status < 400) {
355
+ console.log(`[editorProxy] Target redirect ${status} for ${req.method} ${req.url} → ${proxyRes.headers.location}`);
356
+ }
357
+ if (status >= 400) {
358
+ console.warn(`[editorProxy] Target returned ${status} for ${req.method} ${req.url}`);
359
+ }
360
+ const headers = { ...proxyRes.headers };
361
+ injectSessionCookie(headers);
362
+ // Check if response is HTML — if so, buffer and inject health script
363
+ const contentType = proxyRes.headers['content-type'] || '';
364
+ if (contentType.includes('text/html')) {
365
+ resetPreviewHealth();
366
+ const chunks = [];
367
+ proxyRes.on('data', (chunk) => chunks.push(chunk));
368
+ proxyRes.on('end', () => {
369
+ const body = Buffer.concat(chunks).toString('utf-8');
370
+ delete headers['content-length'];
371
+ delete headers['content-encoding'];
372
+ headers['cache-control'] = 'no-store, must-revalidate';
373
+ // Serve a friendly error page for 5xx responses instead of
374
+ // forwarding the raw error HTML (e.g. Next.js "Internal Server Error")
375
+ if (status >= 500) {
376
+ const errorPage = buildErrorPage(status, 'Internal Server Error', body);
377
+ res.writeHead(status, headers);
378
+ res.end(errorPage);
379
+ return;
380
+ }
381
+ const lsScript = buildLocalStorageScript(localStorageConfig, activeScenarioId || '', currentPrototypeId);
382
+ const injected = injectHealthScript(body, lsScript);
383
+ res.writeHead(status, headers);
384
+ res.end(injected);
385
+ });
386
+ return;
387
+ }
388
+ // For 5xx responses without a content type or with text/plain,
389
+ // serve a friendly error page. These are typically broken dev servers
390
+ // (e.g. Next.js returning bare "Internal Server Error" with no headers).
391
+ // JSON API errors are left alone — they're legitimate responses.
392
+ if (status >= 500 && !contentType.includes('application/json')) {
393
+ const chunks = [];
394
+ proxyRes.on('data', (chunk) => chunks.push(chunk));
395
+ proxyRes.on('end', () => {
396
+ const body = Buffer.concat(chunks).toString('utf-8');
397
+ const errorPage = buildErrorPage(status, 'Internal Server Error', body);
398
+ res.writeHead(status, {
399
+ 'Content-Type': 'text/html',
400
+ 'Cache-Control': 'no-store',
401
+ });
402
+ res.end(errorPage);
403
+ });
404
+ return;
405
+ }
406
+ res.writeHead(status, headers);
151
407
  proxyRes.pipe(res, { end: true });
152
408
  });
153
409
  proxyReq.on('error', (err) => {
154
410
  console.warn(`[editorProxy] Forward error for ${req.method} ${req.url}: ${err.message}`);
155
411
  if (!res.headersSent) {
156
- res.writeHead(502, { 'Content-Type': 'text/plain' });
157
- res.end('Bad Gateway — dev server unreachable');
412
+ const errorPage = buildErrorPage(502, 'Dev Server Unreachable', `The proxy could not connect to the dev server. It may be starting up, restarting, or crashed.\n\n${err.message}`);
413
+ res.writeHead(502, {
414
+ 'Content-Type': 'text/html',
415
+ 'Cache-Control': 'no-store',
416
+ });
417
+ res.end(errorPage);
158
418
  }
159
419
  });
160
420
  if (bodyBuffer && bodyBuffer.length > 0) {
@@ -165,38 +425,531 @@ function forwardBufferedRequest(req, res, targetUrl, bodyBuffer) {
165
425
  }
166
426
  }
167
427
  /**
168
- * Forward an HTTP request to the target dev server (streaming, no body buffering).
428
+ * Forward an HTTP request to the target dev server.
429
+ * For HTML responses: buffers body to inject health-check script.
430
+ * For non-HTML responses: pipes directly (no buffering).
169
431
  */
170
432
  function forwardRequest(req, res, targetUrl) {
171
433
  const target = new URL(targetUrl);
434
+ const hostname = stripIPv6Brackets(target.hostname);
435
+ // Build headers, stripping accept-encoding so the dev server returns uncompressed
436
+ // responses. The proxy injects a health script into HTML — this fails on compressed bodies.
437
+ const { 'accept-encoding': _ae, ...forwardHeaders } = req.headers;
438
+ const reqHeaders = {
439
+ ...forwardHeaders,
440
+ host: `${target.hostname}:${target.port}`,
441
+ };
442
+ // Inject session cookies into the request so the dev server sees auth
443
+ // on the first request after a scenario switch.
444
+ injectRequestCookies(reqHeaders);
172
445
  const options = {
173
- hostname: target.hostname,
446
+ hostname,
174
447
  port: target.port,
175
448
  path: req.url,
176
449
  method: req.method,
177
- headers: { ...req.headers, host: `${target.hostname}:${target.port}` },
450
+ headers: reqHeaders,
178
451
  };
179
452
  const proxyReq = http.request(options, (proxyRes) => {
180
- res.writeHead(proxyRes.statusCode || 200, proxyRes.headers);
453
+ const status = proxyRes.statusCode || 200;
454
+ if (status >= 300 && status < 400) {
455
+ console.log(`[editorProxy] Target redirect ${status} for ${req.method} ${req.url} → ${proxyRes.headers.location}`);
456
+ }
457
+ if (status >= 400) {
458
+ console.warn(`[editorProxy] Target returned ${status} for ${req.method} ${req.url}`);
459
+ }
460
+ const headers = { ...proxyRes.headers };
461
+ injectSessionCookie(headers);
462
+ // Check if response is HTML — if so, buffer and inject health script
463
+ const contentType = proxyRes.headers['content-type'] || '';
464
+ if (contentType.includes('text/html')) {
465
+ // Reset health state for new page loads
466
+ resetPreviewHealth();
467
+ const chunks = [];
468
+ proxyRes.on('data', (chunk) => chunks.push(chunk));
469
+ proxyRes.on('end', () => {
470
+ const body = Buffer.concat(chunks).toString('utf-8');
471
+ delete headers['content-length'];
472
+ delete headers['content-encoding'];
473
+ headers['cache-control'] = 'no-store, must-revalidate';
474
+ // Serve a friendly error page for 5xx responses instead of
475
+ // forwarding the raw error HTML (e.g. Next.js "Internal Server Error")
476
+ if (status >= 500) {
477
+ const errorPage = buildErrorPage(status, 'Internal Server Error', body);
478
+ res.writeHead(status, headers);
479
+ res.end(errorPage);
480
+ return;
481
+ }
482
+ const lsScript = buildLocalStorageScript(localStorageConfig, activeScenarioId || '', currentPrototypeId);
483
+ const injected = injectHealthScript(body, lsScript);
484
+ res.writeHead(status, headers);
485
+ res.end(injected);
486
+ });
487
+ return;
488
+ }
489
+ // For 5xx responses without a content type or with text/plain,
490
+ // serve a friendly error page. These are typically broken dev servers
491
+ // (e.g. Next.js returning bare "Internal Server Error" with no headers).
492
+ // JSON API errors are left alone — they're legitimate responses.
493
+ if (status >= 500 && !contentType.includes('application/json')) {
494
+ const chunks = [];
495
+ proxyRes.on('data', (chunk) => chunks.push(chunk));
496
+ proxyRes.on('end', () => {
497
+ const body = Buffer.concat(chunks).toString('utf-8');
498
+ const errorPage = buildErrorPage(status, 'Internal Server Error', body);
499
+ res.writeHead(status, {
500
+ 'Content-Type': 'text/html',
501
+ 'Cache-Control': 'no-store',
502
+ });
503
+ res.end(errorPage);
504
+ });
505
+ return;
506
+ }
507
+ res.writeHead(status, headers);
181
508
  proxyRes.pipe(res, { end: true });
182
509
  });
183
510
  proxyReq.on('error', (err) => {
184
511
  console.warn(`[editorProxy] Forward error for ${req.method} ${req.url}: ${err.message}`);
185
512
  if (!res.headersSent) {
186
- res.writeHead(502, { 'Content-Type': 'text/plain' });
187
- res.end('Bad Gateway — dev server unreachable');
513
+ const errorPage = buildErrorPage(502, 'Dev Server Unreachable', `The proxy could not connect to the dev server. It may be starting up, restarting, or crashed.\n\n${err.message}`);
514
+ res.writeHead(502, {
515
+ 'Content-Type': 'text/html',
516
+ 'Cache-Control': 'no-store',
517
+ });
518
+ res.end(errorPage);
188
519
  }
189
520
  });
190
521
  req.pipe(proxyReq, { end: true });
191
522
  }
523
+ /**
524
+ * Inject or clear the session-token cookie on proxied responses.
525
+ * When a scenario has session.cookieValue, sets the cookie to auto-log the user in.
526
+ * When a scenario has no session field (null), clears any existing session cookie.
527
+ * When sessionConfig is undefined (no scenario loaded yet), does nothing.
528
+ */
529
+ function injectSessionCookie(headers) {
530
+ const cookies = [];
531
+ // Dev auth cookie (built-in session-token)
532
+ if (sessionConfig !== undefined) {
533
+ if (sessionConfig?.cookieValue) {
534
+ cookies.push(`session-token=${sessionConfig.cookieValue}; Path=/; SameSite=Lax`);
535
+ }
536
+ else {
537
+ cookies.push(`session-token=; Path=/; Max-Age=0`);
538
+ }
539
+ }
540
+ // Seed adapter session cookies (e.g. Supabase auth tokens)
541
+ if (seedSessionCookies && seedSessionCookies.length > 0) {
542
+ for (const sc of seedSessionCookies) {
543
+ const cookiePath = sc.path || '/';
544
+ const sameSite = sc.sameSite || 'Lax';
545
+ cookies.push(`${sc.name}=${sc.value}; Path=${cookiePath}; SameSite=${sameSite}`);
546
+ }
547
+ }
548
+ if (cookies.length === 0)
549
+ return;
550
+ const existing = headers['set-cookie'];
551
+ if (existing) {
552
+ headers['set-cookie'] = [
553
+ ...(Array.isArray(existing) ? existing : [existing]),
554
+ ...cookies,
555
+ ];
556
+ }
557
+ else {
558
+ headers['set-cookie'] = cookies;
559
+ }
560
+ }
561
+ /**
562
+ * Get session cookies that should be injected into requests forwarded to the
563
+ * dev server. Returns an array of {name, value} pairs, or null if no session
564
+ * cookies are configured.
565
+ *
566
+ * This is the counterpart to `injectSessionCookie()` (which adds Set-Cookie
567
+ * to responses). Without request-side injection, the first request after a
568
+ * scenario switch has no cookies — the dev server's auth middleware sees no
569
+ * session and redirects to the login page before the browser ever receives
570
+ * the Set-Cookie response.
571
+ */
572
+ export function getRequestCookieInjection() {
573
+ const cookies = [];
574
+ if (sessionConfig?.cookieValue) {
575
+ cookies.push({ name: 'session-token', value: sessionConfig.cookieValue });
576
+ }
577
+ if (seedSessionCookies && seedSessionCookies.length > 0) {
578
+ for (const sc of seedSessionCookies) {
579
+ cookies.push({ name: sc.name, value: sc.value });
580
+ }
581
+ }
582
+ return cookies.length > 0 ? cookies : null;
583
+ }
584
+ /**
585
+ * Inject session cookies into the request's Cookie header before forwarding
586
+ * to the dev server. This ensures the dev server sees auth cookies on the
587
+ * very first request after a scenario switch (before the browser has stored
588
+ * them from Set-Cookie responses).
589
+ */
590
+ function injectRequestCookies(headers) {
591
+ const injection = getRequestCookieInjection();
592
+ if (!injection)
593
+ return;
594
+ // Parse existing cookies from the request
595
+ const existing = typeof headers.cookie === 'string' ? headers.cookie : '';
596
+ const existingPairs = existing
597
+ ? existing.split(';').map((s) => s.trim())
598
+ : [];
599
+ // Build a map of existing cookies for deduplication
600
+ const cookieMap = new Map();
601
+ for (const pair of existingPairs) {
602
+ const eqIdx = pair.indexOf('=');
603
+ if (eqIdx !== -1) {
604
+ cookieMap.set(pair.slice(0, eqIdx), pair.slice(eqIdx + 1));
605
+ }
606
+ }
607
+ // Override with injected cookies
608
+ for (const { name, value } of injection) {
609
+ cookieMap.set(name, value);
610
+ }
611
+ // Reassemble
612
+ const parts = [];
613
+ for (const [k, v] of cookieMap) {
614
+ parts.push(`${k}=${v}`);
615
+ }
616
+ if (parts.length > 0) {
617
+ headers.cookie = parts.join('; ');
618
+ }
619
+ }
620
+ /**
621
+ * Get the current session config (for testing).
622
+ */
623
+ export function getSessionConfig() {
624
+ return sessionConfig;
625
+ }
626
+ /**
627
+ * Get the current localStorage config (for testing and script generation).
628
+ */
629
+ export function getLocalStorageConfig() {
630
+ return localStorageConfig;
631
+ }
632
+ /**
633
+ * Get the active scenario ID (for testing and script generation).
634
+ */
635
+ export function getActiveScenarioId() {
636
+ return activeScenarioId;
637
+ }
638
+ /**
639
+ * Get the current prototype ID (for testing).
640
+ */
641
+ export function getCurrentPrototypeId() {
642
+ return currentPrototypeId;
643
+ }
644
+ /**
645
+ * Simple djb2 hash — fast, deterministic, good enough for cache busting.
646
+ * Not cryptographic — just detects when localStorage config content changes.
647
+ */
648
+ function simpleHash(str) {
649
+ let hash = 5381;
650
+ for (let i = 0; i < str.length; i++) {
651
+ hash = ((hash << 5) + hash + str.charCodeAt(i)) | 0;
652
+ }
653
+ return (hash >>> 0).toString(36);
654
+ }
655
+ /**
656
+ * Build a script tag that seeds localStorage with scenario data on first load.
657
+ * Gated by scenario ID — only seeds when the scenario changes, preserving
658
+ * interactive modifications across page reloads / HMR.
659
+ *
660
+ * Returns empty string if no localStorage config is provided.
661
+ */
662
+ export function buildLocalStorageScript(localStorageConfig, scenarioId, prototypeId) {
663
+ // null/undefined means no localStorage config at all — clean up keys
664
+ // that were set by a previous scenario so stale filter/sort state
665
+ // doesn't bleed through and hide data in the new scenario.
666
+ if (!localStorageConfig || typeof localStorageConfig !== 'object') {
667
+ // Always clean up previous scenario's keys, gated by scenarioId
668
+ // so it only runs once per switch (not on every HMR reload).
669
+ const guardValue = scenarioId ? `clear:${scenarioId}` : '';
670
+ if (prototypeId) {
671
+ return `<script data-codeyam-ls>
672
+ (function() {
673
+ if (localStorage.getItem('__codeyam_proto__') === ${JSON.stringify(prototypeId)}) return;
674
+ localStorage.clear();
675
+ localStorage.setItem('__codeyam_proto__', ${JSON.stringify(prototypeId)});
676
+ })();
677
+ </script>`;
678
+ }
679
+ if (scenarioId) {
680
+ // No prototypeId but we do have a scenarioId — clean up keys
681
+ // from the previous scenario without doing a full clear.
682
+ return `<script data-codeyam-ls>
683
+ (function() {
684
+ if (localStorage.getItem('__codeyam_ls_sid__') === ${JSON.stringify(guardValue)}) return;
685
+ var prev = JSON.parse(localStorage.getItem('__codeyam_ls_keys__') || '[]');
686
+ for (var i = 0; i < prev.length; i++) localStorage.removeItem(prev[i]);
687
+ localStorage.removeItem('__codeyam_ls_keys__');
688
+ localStorage.setItem('__codeyam_ls_sid__', ${JSON.stringify(guardValue)});
689
+ })();
690
+ </script>`;
691
+ }
692
+ return '';
693
+ }
694
+ // Even an empty object needs a cleanup script — switching from a scenario
695
+ // with localStorage data to one without must clear the previous keys.
696
+ const entries = Object.entries(localStorageConfig);
697
+ const keys = entries.map(([k]) => k);
698
+ // Build setItem calls — stringify non-string values
699
+ const setStatements = entries
700
+ .map(([key, value]) => {
701
+ const serialized = typeof value === 'string' ? value : JSON.stringify(value);
702
+ return `localStorage.setItem(${JSON.stringify(key)}, ${JSON.stringify(serialized)});`;
703
+ })
704
+ .join('\n');
705
+ // Guard value includes a content hash so re-registering a scenario with
706
+ // updated data (same ID, different content) busts the cache. Without this,
707
+ // the browser skips re-seeding because the scenario ID hasn't changed,
708
+ // causing stale data in the live preview while screenshots show fresh data.
709
+ const contentHash = simpleHash(JSON.stringify(localStorageConfig));
710
+ const guardValue = `${scenarioId}:${contentHash}`;
711
+ return (`<script data-codeyam-ls>
712
+ (function() {
713
+ if (localStorage.getItem('__codeyam_ls_sid__') === ${JSON.stringify(guardValue)}) return;
714
+ var prev = JSON.parse(localStorage.getItem('__codeyam_ls_keys__') || '[]');
715
+ for (var i = 0; i < prev.length; i++) localStorage.removeItem(prev[i]);
716
+ ${setStatements}
717
+ localStorage.setItem('__codeyam_ls_keys__', ${JSON.stringify(JSON.stringify(keys))});
718
+ localStorage.setItem('__codeyam_ls_sid__', ${JSON.stringify(guardValue)});
719
+ })();
720
+ </script>` + buildLocalStorageWatcherScript());
721
+ }
722
+ /**
723
+ * Build a script that watches for localStorage mutations and notifies the parent
724
+ * frame via postMessage. Also responds to `codeyam-get-localstorage` requests so
725
+ * the editor can read the current localStorage state when saving.
726
+ */
727
+ function buildLocalStorageWatcherScript() {
728
+ return `<script data-codeyam-ls-watcher>
729
+ (function() {
730
+ if (window.__codeyam_ls_watcher_installed__) return;
731
+ window.__codeyam_ls_watcher_installed__ = true;
732
+
733
+ var origSet = localStorage.setItem.bind(localStorage);
734
+ var origRemove = localStorage.removeItem.bind(localStorage);
735
+ var origClear = localStorage.clear.bind(localStorage);
736
+ window.__codeyam_orig_setItem__ = origSet;
737
+ window.__codeyam_orig_removeItem__ = origRemove;
738
+ window.__codeyam_orig_clear__ = origClear;
739
+
740
+ function isInternal(key) {
741
+ return typeof key === 'string' && key.indexOf('__codeyam_') === 0;
742
+ }
743
+
744
+ localStorage.setItem = function(key, value) {
745
+ origSet(key, value);
746
+ if (!isInternal(key) && window.parent !== window) {
747
+ window.parent.postMessage({ type: 'codeyam-localstorage-changed', action: 'set', key: key }, '*');
748
+ }
749
+ };
750
+
751
+ localStorage.removeItem = function(key) {
752
+ origRemove(key);
753
+ if (!isInternal(key) && window.parent !== window) {
754
+ window.parent.postMessage({ type: 'codeyam-localstorage-changed', action: 'remove', key: key }, '*');
755
+ }
756
+ };
757
+
758
+ localStorage.clear = function() {
759
+ origClear();
760
+ if (window.parent !== window) {
761
+ window.parent.postMessage({ type: 'codeyam-localstorage-changed', action: 'clear' }, '*');
762
+ }
763
+ };
764
+
765
+ window.addEventListener('message', function(event) {
766
+ if (event.data && event.data.type === 'codeyam-get-localstorage') {
767
+ var data = {};
768
+ for (var i = 0; i < localStorage.length; i++) {
769
+ var k = localStorage.key(i);
770
+ if (k && !isInternal(k)) {
771
+ data[k] = localStorage.getItem(k);
772
+ }
773
+ }
774
+ event.source.postMessage({ type: 'codeyam-localstorage-state', data: data }, '*');
775
+ }
776
+ });
777
+ })();
778
+ </script>`;
779
+ }
780
+ /**
781
+ * Inject the health-check script (and optional localStorage script) into an HTML response body.
782
+ * Inserts before </head> if present, otherwise before </body>, otherwise appends.
783
+ * When a localStorageScript is provided, it's injected BEFORE the health script
784
+ * so localStorage is populated before the app loads.
785
+ */
786
+ export function injectHealthScript(html, localStorageScript) {
787
+ const scripts = (localStorageScript || '') + PREVIEW_HEALTH_SCRIPT;
788
+ if (html.includes('</head>')) {
789
+ return html.replace('</head>', scripts + '</head>');
790
+ }
791
+ if (html.includes('</body>')) {
792
+ return html.replace('</body>', scripts + '</body>');
793
+ }
794
+ return html + scripts;
795
+ }
796
+ /**
797
+ * Escape HTML special characters to prevent XSS when embedding
798
+ * dev server error output into the error page.
799
+ */
800
+ export function escapeHtml(str) {
801
+ return str
802
+ .replace(/&/g, '&amp;')
803
+ .replace(/</g, '&lt;')
804
+ .replace(/>/g, '&gt;')
805
+ .replace(/"/g, '&quot;')
806
+ .replace(/'/g, '&#39;');
807
+ }
808
+ /**
809
+ * Build a self-contained HTML error page for display in the preview iframe.
810
+ *
811
+ * - Sends `codeyam-server-error` postMessage to the parent editor on load
812
+ * so the editor can auto-restart the dev server.
813
+ * - Includes a "Retry" button that sends `codeyam-server-error-retry`.
814
+ * - Does NOT send `codeyam-preview-ready` (so the editor doesn't
815
+ * mistake the error page for a successful load).
816
+ */
817
+ export function buildErrorPage(statusCode, title, detail) {
818
+ const escapedDetail = escapeHtml(detail);
819
+ const escapedTitle = escapeHtml(title);
820
+ return `<!DOCTYPE html>
821
+ <html lang="en">
822
+ <head>
823
+ <meta charset="utf-8" />
824
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
825
+ <title>${escapedTitle}</title>
826
+ <style>
827
+ * { margin: 0; padding: 0; box-sizing: border-box; }
828
+ body {
829
+ background: #1e1e1e;
830
+ color: #e0e0e0;
831
+ font-family: 'IBM Plex Sans', -apple-system, BlinkMacSystemFont, sans-serif;
832
+ display: flex;
833
+ align-items: center;
834
+ justify-content: center;
835
+ min-height: 100vh;
836
+ padding: 24px;
837
+ }
838
+ .container {
839
+ max-width: 560px;
840
+ width: 100%;
841
+ text-align: center;
842
+ }
843
+ .status-code {
844
+ font-size: 48px;
845
+ font-weight: 600;
846
+ color: #f87171;
847
+ line-height: 1;
848
+ margin-bottom: 8px;
849
+ }
850
+ .title {
851
+ font-size: 18px;
852
+ font-weight: 500;
853
+ color: #f87171;
854
+ margin-bottom: 16px;
855
+ }
856
+ .detail {
857
+ background: #2a2a2a;
858
+ border: 1px solid #3a3a3a;
859
+ border-radius: 6px;
860
+ padding: 16px;
861
+ margin-bottom: 20px;
862
+ max-height: 240px;
863
+ overflow: auto;
864
+ text-align: left;
865
+ }
866
+ .detail pre {
867
+ font-family: 'IBM Plex Mono', monospace;
868
+ font-size: 12px;
869
+ color: #b0b0b0;
870
+ white-space: pre-wrap;
871
+ word-break: break-word;
872
+ }
873
+ .message {
874
+ font-size: 13px;
875
+ color: #888;
876
+ margin-bottom: 16px;
877
+ }
878
+ button {
879
+ background: #005c75;
880
+ color: white;
881
+ border: none;
882
+ border-radius: 4px;
883
+ padding: 8px 20px;
884
+ font-size: 14px;
885
+ font-weight: 500;
886
+ cursor: pointer;
887
+ transition: background 0.15s;
888
+ }
889
+ button:hover { background: #004d63; }
890
+ </style>
891
+ </head>
892
+ <body>
893
+ <div class="container">
894
+ <div class="status-code">${statusCode}</div>
895
+ <div class="title">${escapedTitle}</div>
896
+ <div class="detail"><pre>${escapedDetail}</pre></div>
897
+ <p class="message">Attempting to restart the dev server...</p>
898
+ <button onclick="window.parent.postMessage({type:'codeyam-server-error-retry'},'*')">Retry</button>
899
+ </div>
900
+ <script>
901
+ try { window.parent.postMessage({type:'codeyam-server-error',statusCode:${statusCode}},'*'); } catch(e) {}
902
+ </script>
903
+ </body>
904
+ </html>`;
905
+ }
906
+ /**
907
+ * Handle POST /__codeyam__/preview-health — store health data in globalThis.
908
+ */
909
+ function handlePreviewHealthPost(req, res) {
910
+ const chunks = [];
911
+ req.on('data', (chunk) => chunks.push(chunk));
912
+ req.on('end', () => {
913
+ try {
914
+ const body = JSON.parse(Buffer.concat(chunks).toString('utf-8'));
915
+ const current = getPreviewHealth() || {
916
+ errors: [],
917
+ loaded: false,
918
+ hasContent: false,
919
+ url: '',
920
+ lastUpdated: 0,
921
+ };
922
+ if (body.errors && Array.isArray(body.errors)) {
923
+ current.errors = current.errors.concat(body.errors);
924
+ }
925
+ if (body.loaded !== undefined) {
926
+ current.loaded = body.loaded;
927
+ }
928
+ if (body.hasContent !== undefined) {
929
+ current.hasContent = body.hasContent;
930
+ }
931
+ if (body.url) {
932
+ current.url = body.url;
933
+ }
934
+ current.lastUpdated = Date.now();
935
+ setPreviewHealth(current);
936
+ }
937
+ catch {
938
+ // Ignore malformed JSON
939
+ }
940
+ res.writeHead(204);
941
+ res.end();
942
+ });
943
+ }
192
944
  /**
193
945
  * Handle WebSocket upgrade by piping to the target dev server.
194
946
  */
195
947
  function handleUpgrade(req, socket, head, targetUrl) {
196
948
  const target = new URL(targetUrl);
949
+ const hostname = stripIPv6Brackets(target.hostname);
197
950
  const port = parseInt(target.port, 10) || 80;
198
- console.log(`[editorProxy] WebSocket upgrade: ${req.url} → ${target.hostname}:${port}`);
199
- const proxySocket = net.connect(port, target.hostname, () => {
951
+ console.log(`[editorProxy] WebSocket upgrade: ${req.url} → ${hostname}:${port}`);
952
+ const proxySocket = net.connect(port, hostname, () => {
200
953
  // Reconstruct the HTTP upgrade request
201
954
  const requestLine = `${req.method} ${req.url} HTTP/${req.httpVersion}\r\n`;
202
955
  const headers = Object.entries(req.headers)
@@ -258,10 +1011,34 @@ function removeProxyConfig() {
258
1011
  * Supports all HTTP methods (GET, POST, PUT, DELETE, PATCH) with body buffering.
259
1012
  */
260
1013
  export async function startEditorProxy(options) {
261
- // Stop existing proxy first
1014
+ // If proxy is already running, reuse it (prevents second tab from killing first tab's proxy)
1015
+ const existing = getProxyState();
1016
+ if (existing) {
1017
+ console.log(`[editorProxy] Proxy already running on port ${existing.port} → ${existing.targetUrl}`);
1018
+ return { port: existing.port };
1019
+ }
1020
+ // Stop any leftover state (shouldn't happen, but defensive)
262
1021
  await stopEditorProxy();
263
- const { targetUrl } = options;
1022
+ let targetUrl = normalizeTargetUrl(options.targetUrl);
264
1023
  let port = options.port;
1024
+ // When the target is localhost, probe to find the correct loopback address.
1025
+ // Dev servers may bind to IPv4 (127.0.0.1) or IPv6 (::1) — Vite 6 on macOS
1026
+ // binds to ::1 by default. We need to match the actual binding.
1027
+ try {
1028
+ const parsed = new URL(targetUrl);
1029
+ if (parsed.hostname === 'localhost') {
1030
+ const targetPort = parseInt(parsed.port || '80', 10);
1031
+ const resolvedHost = await resolveLoopbackAddress(targetPort);
1032
+ if (resolvedHost) {
1033
+ parsed.hostname = resolvedHost;
1034
+ targetUrl = parsed.toString().replace(/\/$/, '');
1035
+ console.log(`[editorProxy] Resolved localhost to ${resolvedHost} for port ${targetPort}`);
1036
+ }
1037
+ }
1038
+ }
1039
+ catch {
1040
+ // Keep original targetUrl
1041
+ }
265
1042
  console.log(`[editorProxy] Starting proxy (requested port ${port}, target ${targetUrl})`);
266
1043
  const mockState = getMockStateManager();
267
1044
  const server = http.createServer((req, res) => {
@@ -280,6 +1057,11 @@ export async function startEditorProxy(options) {
280
1057
  res.end();
281
1058
  return;
282
1059
  }
1060
+ // Intercept preview health reports from the injected script
1061
+ if (method === 'POST' && pathname === '/__codeyam__/preview-health') {
1062
+ handlePreviewHealthPost(req, res);
1063
+ return;
1064
+ }
283
1065
  // Load scenario data (also feeds MockStateManager)
284
1066
  readScenarioData();
285
1067
  // For methods that may carry a body, buffer it first
@@ -311,11 +1093,17 @@ export async function startEditorProxy(options) {
311
1093
  'Content-Type': 'application/json',
312
1094
  'Access-Control-Allow-Origin': '*',
313
1095
  'X-CodeYam-Proxy': 'scenario-data',
1096
+ 'Cache-Control': 'no-store',
314
1097
  });
315
1098
  res.end(match.body != null ? JSON.stringify(match.body) : '');
316
1099
  return;
317
1100
  }
318
1101
  // No mock match — forward with buffered body
1102
+ if ((currentScenarioType === 'application' ||
1103
+ currentScenarioType === 'user') &&
1104
+ pathname.startsWith('/api/')) {
1105
+ mockStateEventEmitter.emitDataMutationForwarded(method, pathname);
1106
+ }
319
1107
  forwardBufferedRequest(req, res, targetUrl, bodyBuffer);
320
1108
  return;
321
1109
  }
@@ -327,6 +1115,7 @@ export async function startEditorProxy(options) {
327
1115
  'Content-Type': 'application/json',
328
1116
  'Access-Control-Allow-Origin': '*',
329
1117
  'X-CodeYam-Proxy': 'scenario-data',
1118
+ 'Cache-Control': 'no-store',
330
1119
  });
331
1120
  res.end(match.body != null ? JSON.stringify(match.body) : '');
332
1121
  return;
@@ -351,7 +1140,10 @@ export async function startEditorProxy(options) {
351
1140
  resolve();
352
1141
  });
353
1142
  });
354
- port = currentPort;
1143
+ // When port 0 is requested, the OS assigns an ephemeral port
1144
+ const addr = server.address();
1145
+ port =
1146
+ typeof addr === 'object' && addr !== null ? addr.port : currentPort;
355
1147
  const state = { server, port, targetUrl };
356
1148
  setProxyState(state);
357
1149
  // Write proxy-config.json for the preload module
@@ -394,6 +1186,41 @@ export async function stopEditorProxy() {
394
1186
  */
395
1187
  export function invalidateScenarioCache() {
396
1188
  scenarioCache = { data: null, timestamp: 0 };
1189
+ sessionConfig = undefined;
1190
+ seedSessionCookies = undefined;
1191
+ localStorageConfig = null;
1192
+ activeScenarioId = null;
1193
+ currentPrototypeId = null;
1194
+ }
1195
+ /**
1196
+ * Verify that the proxy can successfully forward a request to the target dev server.
1197
+ * Makes a HEAD request through the proxy and checks that it gets a response (any status).
1198
+ * Returns false if the proxy isn't running or if the request fails entirely.
1199
+ */
1200
+ export async function verifyProxyForwarding() {
1201
+ const state = getProxyState();
1202
+ if (!state) {
1203
+ console.warn('[editorProxy] Cannot verify — proxy is not running');
1204
+ return false;
1205
+ }
1206
+ try {
1207
+ const response = await fetch(`http://127.0.0.1:${state.port}/`, {
1208
+ method: 'HEAD',
1209
+ signal: AbortSignal.timeout(5000),
1210
+ });
1211
+ // Any response from the target (even 404) means forwarding works.
1212
+ // Only 502 (our own Bad Gateway) means the target is unreachable.
1213
+ if (response.status === 502) {
1214
+ console.warn(`[editorProxy] Verification failed — proxy returned 502 (target unreachable)`);
1215
+ return false;
1216
+ }
1217
+ console.log(`[editorProxy] Verification passed — proxy forwarding to ${state.targetUrl} (status ${response.status})`);
1218
+ return true;
1219
+ }
1220
+ catch (err) {
1221
+ console.warn(`[editorProxy] Verification failed — could not reach proxy on port ${state.port}`);
1222
+ return false;
1223
+ }
397
1224
  }
398
1225
  /**
399
1226
  * Ensure the proxy is running. If it's not, start it using the current dev server URL.
@@ -415,9 +1242,10 @@ export async function ensureProxyRunning() {
415
1242
  return null;
416
1243
  }
417
1244
  const codeyamPort = parseInt(process.env.CODEYAM_PORT || '3111', 10);
418
- console.log(`[editorProxy] Proxy not running, starting on-demand (port ${codeyamPort + 1}, target ${devServer.url})`);
1245
+ const { proxyPort } = computeEditorPorts(codeyamPort);
1246
+ console.log(`[editorProxy] Proxy not running, starting on-demand (port ${proxyPort}, target ${devServer.url})`);
419
1247
  const result = await startEditorProxy({
420
- port: codeyamPort + 1,
1248
+ port: proxyPort,
421
1249
  targetUrl: devServer.url,
422
1250
  });
423
1251
  if (result) {
@@ -428,4 +1256,8 @@ export async function ensureProxyRunning() {
428
1256
  console.error('[editorProxy] Failed to start on-demand proxy');
429
1257
  return null;
430
1258
  }
1259
+ /**
1260
+ * Test-only export: trigger readScenarioData so tests can verify session config extraction.
1261
+ */
1262
+ export const _readScenarioDataForTest = readScenarioData;
431
1263
  //# sourceMappingURL=editorProxy.js.map