@codeyam/codeyam-cli 0.1.6 → 0.1.8

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 (398) hide show
  1. package/analyzer-template/.build-info.json +7 -7
  2. package/analyzer-template/log.txt +3 -3
  3. package/analyzer-template/package.json +6 -6
  4. package/analyzer-template/packages/ai/package.json +1 -1
  5. package/analyzer-template/packages/ai/src/lib/astScopes/astScopeAnalyzer.ts +34 -3
  6. package/analyzer-template/packages/ai/src/lib/completionCall.ts +14 -2
  7. package/analyzer-template/packages/ai/src/lib/dataStructure/ScopeDataStructure.ts +27 -0
  8. package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/coercePrimitivesToArraysBySchema.ts +62 -0
  9. package/analyzer-template/packages/ai/src/lib/generateEntityScenarioData.ts +78 -2
  10. package/analyzer-template/packages/analyze/src/lib/ProjectAnalyzer.ts +6 -0
  11. package/analyzer-template/packages/analyze/src/lib/files/analyze/analyzeEntities.ts +9 -1
  12. package/analyzer-template/packages/analyze/src/lib/files/analyze/dependencyResolver.ts +0 -6
  13. package/analyzer-template/packages/analyze/src/lib/files/analyze/findOrCreateEntity.ts +12 -0
  14. package/analyzer-template/packages/analyze/src/lib/files/scenarios/TransformationTracer.ts +65 -28
  15. package/analyzer-template/packages/analyze/src/lib/files/scenarios/generateDataStructure.ts +83 -0
  16. package/analyzer-template/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.ts +23 -4
  17. package/analyzer-template/packages/aws/package.json +1 -1
  18. package/analyzer-template/packages/database/index.ts +1 -0
  19. package/analyzer-template/packages/database/package.json +3 -3
  20. package/analyzer-template/packages/database/src/lib/kysely/db.ts +8 -0
  21. package/analyzer-template/packages/database/src/lib/kysely/tables/editorScenariosTable.ts +62 -0
  22. package/analyzer-template/packages/database/src/lib/loadCommits.ts +31 -20
  23. package/analyzer-template/packages/database/src/lib/loadReadyToBeCapturedAnalyses.ts +0 -5
  24. package/analyzer-template/packages/database/src/lib/updateCommitMetadata.ts +151 -135
  25. package/analyzer-template/packages/database/src/lib/updateFreshAnalysisStatus.ts +58 -42
  26. package/analyzer-template/packages/database/src/lib/updateFreshAnalysisStatusWithScenarios.ts +81 -65
  27. package/analyzer-template/packages/generate/src/lib/componentScenarioPage/generateScenarioClientWrapper.ts +29 -1
  28. package/analyzer-template/packages/generate/src/lib/componentScenarioPage/getIFrameMessageListenerCode.ts +33 -5
  29. package/analyzer-template/packages/github/dist/database/index.d.ts +1 -0
  30. package/analyzer-template/packages/github/dist/database/index.d.ts.map +1 -1
  31. package/analyzer-template/packages/github/dist/database/index.js +1 -0
  32. package/analyzer-template/packages/github/dist/database/index.js.map +1 -1
  33. package/analyzer-template/packages/github/dist/database/src/lib/kysely/db.d.ts +2 -0
  34. package/analyzer-template/packages/github/dist/database/src/lib/kysely/db.d.ts.map +1 -1
  35. package/analyzer-template/packages/github/dist/database/src/lib/kysely/db.js +5 -0
  36. package/analyzer-template/packages/github/dist/database/src/lib/kysely/db.js.map +1 -1
  37. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/editorScenariosTable.d.ts +20 -0
  38. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/editorScenariosTable.d.ts.map +1 -0
  39. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/editorScenariosTable.js +45 -0
  40. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/editorScenariosTable.js.map +1 -0
  41. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/scenariosTable.d.ts +5 -0
  42. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/scenariosTable.d.ts.map +1 -1
  43. package/analyzer-template/packages/github/dist/database/src/lib/loadCommits.d.ts.map +1 -1
  44. package/analyzer-template/packages/github/dist/database/src/lib/loadCommits.js +23 -13
  45. package/analyzer-template/packages/github/dist/database/src/lib/loadCommits.js.map +1 -1
  46. package/analyzer-template/packages/github/dist/database/src/lib/loadReadyToBeCapturedAnalyses.d.ts.map +1 -1
  47. package/analyzer-template/packages/github/dist/database/src/lib/loadReadyToBeCapturedAnalyses.js +1 -4
  48. package/analyzer-template/packages/github/dist/database/src/lib/loadReadyToBeCapturedAnalyses.js.map +1 -1
  49. package/analyzer-template/packages/github/dist/database/src/lib/updateCommitMetadata.d.ts.map +1 -1
  50. package/analyzer-template/packages/github/dist/database/src/lib/updateCommitMetadata.js +100 -89
  51. package/analyzer-template/packages/github/dist/database/src/lib/updateCommitMetadata.js.map +1 -1
  52. package/analyzer-template/packages/github/dist/database/src/lib/updateFreshAnalysisStatus.d.ts.map +1 -1
  53. package/analyzer-template/packages/github/dist/database/src/lib/updateFreshAnalysisStatus.js +41 -30
  54. package/analyzer-template/packages/github/dist/database/src/lib/updateFreshAnalysisStatus.js.map +1 -1
  55. package/analyzer-template/packages/github/dist/database/src/lib/updateFreshAnalysisStatusWithScenarios.d.ts.map +1 -1
  56. package/analyzer-template/packages/github/dist/database/src/lib/updateFreshAnalysisStatusWithScenarios.js +68 -57
  57. package/analyzer-template/packages/github/dist/database/src/lib/updateFreshAnalysisStatusWithScenarios.js.map +1 -1
  58. package/analyzer-template/packages/github/dist/generate/src/lib/componentScenarioPage/generateScenarioClientWrapper.d.ts.map +1 -1
  59. package/analyzer-template/packages/github/dist/generate/src/lib/componentScenarioPage/generateScenarioClientWrapper.js +29 -1
  60. package/analyzer-template/packages/github/dist/generate/src/lib/componentScenarioPage/generateScenarioClientWrapper.js.map +1 -1
  61. package/analyzer-template/packages/github/dist/generate/src/lib/componentScenarioPage/getIFrameMessageListenerCode.d.ts.map +1 -1
  62. package/analyzer-template/packages/github/dist/generate/src/lib/componentScenarioPage/getIFrameMessageListenerCode.js +33 -5
  63. package/analyzer-template/packages/github/dist/generate/src/lib/componentScenarioPage/getIFrameMessageListenerCode.js.map +1 -1
  64. package/analyzer-template/packages/github/dist/types/src/types/ProjectMetadata.d.ts +1 -0
  65. package/analyzer-template/packages/github/dist/types/src/types/ProjectMetadata.d.ts.map +1 -1
  66. package/analyzer-template/packages/github/dist/types/src/types/Scenario.d.ts +10 -0
  67. package/analyzer-template/packages/github/dist/types/src/types/Scenario.d.ts.map +1 -1
  68. package/analyzer-template/packages/github/package.json +1 -1
  69. package/analyzer-template/packages/types/src/types/ProjectMetadata.ts +1 -0
  70. package/analyzer-template/packages/types/src/types/Scenario.ts +10 -0
  71. package/analyzer-template/packages/utils/dist/types/src/types/ProjectMetadata.d.ts +1 -0
  72. package/analyzer-template/packages/utils/dist/types/src/types/ProjectMetadata.d.ts.map +1 -1
  73. package/analyzer-template/packages/utils/dist/types/src/types/Scenario.d.ts +10 -0
  74. package/analyzer-template/packages/utils/dist/types/src/types/Scenario.d.ts.map +1 -1
  75. package/analyzer-template/playwright/captureFromUrl.ts +89 -82
  76. package/analyzer-template/project/constructMockCode.ts +136 -43
  77. package/analyzer-template/project/reconcileMockDataKeys.ts +19 -14
  78. package/analyzer-template/project/start.ts +3 -0
  79. package/analyzer-template/project/startScenarioCapture.ts +9 -0
  80. package/analyzer-template/project/writeClientLogRoute.ts +125 -0
  81. package/analyzer-template/project/writeMockDataTsx.ts +17 -0
  82. package/analyzer-template/project/writeScenarioComponents.ts +36 -7
  83. package/analyzer-template/tsconfig.json +13 -1
  84. package/background/src/lib/virtualized/project/constructMockCode.js +115 -34
  85. package/background/src/lib/virtualized/project/constructMockCode.js.map +1 -1
  86. package/background/src/lib/virtualized/project/reconcileMockDataKeys.js +17 -11
  87. package/background/src/lib/virtualized/project/reconcileMockDataKeys.js.map +1 -1
  88. package/background/src/lib/virtualized/project/start.js +2 -0
  89. package/background/src/lib/virtualized/project/start.js.map +1 -1
  90. package/background/src/lib/virtualized/project/startScenarioCapture.js +5 -0
  91. package/background/src/lib/virtualized/project/startScenarioCapture.js.map +1 -1
  92. package/background/src/lib/virtualized/project/writeClientLogRoute.js +110 -0
  93. package/background/src/lib/virtualized/project/writeClientLogRoute.js.map +1 -0
  94. package/background/src/lib/virtualized/project/writeMockDataTsx.js +12 -0
  95. package/background/src/lib/virtualized/project/writeMockDataTsx.js.map +1 -1
  96. package/background/src/lib/virtualized/project/writeScenarioComponents.js +29 -7
  97. package/background/src/lib/virtualized/project/writeScenarioComponents.js.map +1 -1
  98. package/codeyam-cli/scripts/apply-setup.js +208 -11
  99. package/codeyam-cli/scripts/apply-setup.js.map +1 -1
  100. package/codeyam-cli/src/cli.js +2 -0
  101. package/codeyam-cli/src/cli.js.map +1 -1
  102. package/codeyam-cli/src/commands/analyze.js +17 -7
  103. package/codeyam-cli/src/commands/analyze.js.map +1 -1
  104. package/codeyam-cli/src/commands/default.js +58 -3
  105. package/codeyam-cli/src/commands/default.js.map +1 -1
  106. package/codeyam-cli/src/commands/editor.js +1839 -0
  107. package/codeyam-cli/src/commands/editor.js.map +1 -0
  108. package/codeyam-cli/src/commands/init.js +40 -11
  109. package/codeyam-cli/src/commands/init.js.map +1 -1
  110. package/codeyam-cli/src/commands/memory.js +26 -2
  111. package/codeyam-cli/src/commands/memory.js.map +1 -1
  112. package/codeyam-cli/src/utils/__tests__/editorAudit.test.js +246 -0
  113. package/codeyam-cli/src/utils/__tests__/editorAudit.test.js.map +1 -0
  114. package/codeyam-cli/src/utils/__tests__/editorDevServer.test.js +126 -0
  115. package/codeyam-cli/src/utils/__tests__/editorDevServer.test.js.map +1 -0
  116. package/codeyam-cli/src/utils/__tests__/editorJournal.test.js +295 -0
  117. package/codeyam-cli/src/utils/__tests__/editorJournal.test.js.map +1 -0
  118. package/codeyam-cli/src/utils/__tests__/editorMockState.test.js +270 -0
  119. package/codeyam-cli/src/utils/__tests__/editorMockState.test.js.map +1 -0
  120. package/codeyam-cli/src/utils/__tests__/editorPreloadHelpers.test.js +100 -0
  121. package/codeyam-cli/src/utils/__tests__/editorPreloadHelpers.test.js.map +1 -0
  122. package/codeyam-cli/src/utils/__tests__/editorPreview.test.js +147 -0
  123. package/codeyam-cli/src/utils/__tests__/editorPreview.test.js.map +1 -0
  124. package/codeyam-cli/src/utils/__tests__/editorScenarios.test.js +76 -0
  125. package/codeyam-cli/src/utils/__tests__/editorScenarios.test.js.map +1 -0
  126. package/codeyam-cli/src/utils/__tests__/git.editor.test.js +134 -0
  127. package/codeyam-cli/src/utils/__tests__/git.editor.test.js.map +1 -0
  128. package/codeyam-cli/src/utils/__tests__/pathIgnoring.test.js +9 -0
  129. package/codeyam-cli/src/utils/__tests__/pathIgnoring.test.js.map +1 -1
  130. package/codeyam-cli/src/utils/__tests__/project.test.js +65 -0
  131. package/codeyam-cli/src/utils/__tests__/project.test.js.map +1 -0
  132. package/codeyam-cli/src/utils/__tests__/scenarioMarkers.test.js +121 -0
  133. package/codeyam-cli/src/utils/__tests__/scenarioMarkers.test.js.map +1 -0
  134. package/codeyam-cli/src/utils/__tests__/setupClaudeCodeSettings.test.js +26 -0
  135. package/codeyam-cli/src/utils/__tests__/setupClaudeCodeSettings.test.js.map +1 -1
  136. package/codeyam-cli/src/utils/backgroundServer.js +19 -3
  137. package/codeyam-cli/src/utils/backgroundServer.js.map +1 -1
  138. package/codeyam-cli/src/utils/buildFlags.js +4 -0
  139. package/codeyam-cli/src/utils/buildFlags.js.map +1 -0
  140. package/codeyam-cli/src/utils/devModeEvents.js +40 -0
  141. package/codeyam-cli/src/utils/devModeEvents.js.map +1 -0
  142. package/codeyam-cli/src/utils/editorAudit.js +82 -0
  143. package/codeyam-cli/src/utils/editorAudit.js.map +1 -0
  144. package/codeyam-cli/src/utils/editorDevServer.js +98 -0
  145. package/codeyam-cli/src/utils/editorDevServer.js.map +1 -0
  146. package/codeyam-cli/src/utils/editorJournal.js +137 -0
  147. package/codeyam-cli/src/utils/editorJournal.js.map +1 -0
  148. package/codeyam-cli/src/utils/editorMockState.js +248 -0
  149. package/codeyam-cli/src/utils/editorMockState.js.map +1 -0
  150. package/codeyam-cli/src/utils/editorPreloadHelpers.js +64 -0
  151. package/codeyam-cli/src/utils/editorPreloadHelpers.js.map +1 -0
  152. package/codeyam-cli/src/utils/editorPreview.js +66 -0
  153. package/codeyam-cli/src/utils/editorPreview.js.map +1 -0
  154. package/codeyam-cli/src/utils/editorScenarios.js +56 -0
  155. package/codeyam-cli/src/utils/editorScenarios.js.map +1 -0
  156. package/codeyam-cli/src/utils/fileMetadata.js +5 -0
  157. package/codeyam-cli/src/utils/fileMetadata.js.map +1 -1
  158. package/codeyam-cli/src/utils/fileWatcher.js +25 -9
  159. package/codeyam-cli/src/utils/fileWatcher.js.map +1 -1
  160. package/codeyam-cli/src/utils/git.js +103 -0
  161. package/codeyam-cli/src/utils/git.js.map +1 -1
  162. package/codeyam-cli/src/utils/install-skills.js +55 -13
  163. package/codeyam-cli/src/utils/install-skills.js.map +1 -1
  164. package/codeyam-cli/src/utils/interactiveSyncWatcher.js +126 -0
  165. package/codeyam-cli/src/utils/interactiveSyncWatcher.js.map +1 -0
  166. package/codeyam-cli/src/utils/pathIgnoring.js +19 -7
  167. package/codeyam-cli/src/utils/pathIgnoring.js.map +1 -1
  168. package/codeyam-cli/src/utils/project.js +15 -5
  169. package/codeyam-cli/src/utils/project.js.map +1 -1
  170. package/codeyam-cli/src/utils/queue/__tests__/heartbeat.test.js +11 -11
  171. package/codeyam-cli/src/utils/queue/__tests__/heartbeat.test.js.map +1 -1
  172. package/codeyam-cli/src/utils/queue/__tests__/manager.test.js +22 -0
  173. package/codeyam-cli/src/utils/queue/__tests__/manager.test.js.map +1 -1
  174. package/codeyam-cli/src/utils/queue/heartbeat.js +13 -5
  175. package/codeyam-cli/src/utils/queue/heartbeat.js.map +1 -1
  176. package/codeyam-cli/src/utils/queue/job.js +70 -1
  177. package/codeyam-cli/src/utils/queue/job.js.map +1 -1
  178. package/codeyam-cli/src/utils/queue/manager.js +7 -6
  179. package/codeyam-cli/src/utils/queue/manager.js.map +1 -1
  180. package/codeyam-cli/src/utils/scenarioMarkers.js +134 -0
  181. package/codeyam-cli/src/utils/scenarioMarkers.js.map +1 -0
  182. package/codeyam-cli/src/utils/serverState.js +27 -2
  183. package/codeyam-cli/src/utils/serverState.js.map +1 -1
  184. package/codeyam-cli/src/utils/setupClaudeCodeSettings.js +45 -4
  185. package/codeyam-cli/src/utils/setupClaudeCodeSettings.js.map +1 -1
  186. package/codeyam-cli/src/utils/testRunner.js +158 -0
  187. package/codeyam-cli/src/utils/testRunner.js.map +1 -0
  188. package/codeyam-cli/src/utils/transcriptPruning.js +67 -0
  189. package/codeyam-cli/src/utils/transcriptPruning.js.map +1 -0
  190. package/codeyam-cli/src/utils/webappDetection.js +14 -2
  191. package/codeyam-cli/src/utils/webappDetection.js.map +1 -1
  192. package/codeyam-cli/src/webserver/app/lib/database.js +41 -27
  193. package/codeyam-cli/src/webserver/app/lib/database.js.map +1 -1
  194. package/codeyam-cli/src/webserver/app/lib/dbNotifier.js.map +1 -1
  195. package/codeyam-cli/src/webserver/backgroundServer.js +109 -19
  196. package/codeyam-cli/src/webserver/backgroundServer.js.map +1 -1
  197. package/codeyam-cli/src/webserver/build/client/assets/{CopyButton-CtmbP4Gl.js → CopyButton-DmJveP3T.js} +1 -1
  198. package/codeyam-cli/src/webserver/build/client/assets/{EntityItem-DlMph_Hm.js → EntityItem-C76mRRiF.js} +1 -1
  199. package/codeyam-cli/src/webserver/build/client/assets/{EntityTypeBadge-B-0PjGOU.js → EntityTypeBadge-g3saevPb.js} +1 -1
  200. package/codeyam-cli/src/webserver/build/client/assets/{EntityTypeIcon-DN9eiJAO.js → EntityTypeIcon-CobE682z.js} +1 -1
  201. package/codeyam-cli/src/webserver/build/client/assets/InlineSpinner-Bu6c6aDe.js +1 -0
  202. package/codeyam-cli/src/webserver/build/client/assets/{InteractivePreview-rE_fI2h2.js → InteractivePreview-DYFW3lDD.js} +3 -3
  203. package/codeyam-cli/src/webserver/build/client/assets/{LibraryFunctionPreview-CnatsCw2.js → LibraryFunctionPreview-DLeucoVX.js} +1 -1
  204. package/codeyam-cli/src/webserver/build/client/assets/{LoadingDots-CSP6DZrh.js → LoadingDots-BU_OAEMP.js} +1 -1
  205. package/codeyam-cli/src/webserver/build/client/assets/{LogViewer-CMK8Q7yk.js → LogViewer-ceAyBX-H.js} +1 -1
  206. package/codeyam-cli/src/webserver/build/client/assets/{ReportIssueModal-TCV_HBjy.js → ReportIssueModal-djPLI-WV.js} +1 -1
  207. package/codeyam-cli/src/webserver/build/client/assets/{SafeScreenshot-CG2uh31y.js → SafeScreenshot-BED4B6sP.js} +1 -1
  208. package/codeyam-cli/src/webserver/build/client/assets/{ScenarioViewer-CU_TDYd8.js → ScenarioViewer-B76aig_2.js} +1 -1
  209. package/codeyam-cli/src/webserver/build/client/assets/Spinner-Bb5uFQ5V.js +34 -0
  210. package/codeyam-cli/src/webserver/build/client/assets/Terminal-Dnj5CY9R.js +41 -0
  211. package/codeyam-cli/src/webserver/build/client/assets/{TruncatedFilePath-D7IoaWUW.js → TruncatedFilePath-C8OKAR5x.js} +1 -1
  212. package/codeyam-cli/src/webserver/build/client/assets/{_index-B8z7mjR-.js → _index-C96V0n15.js} +1 -1
  213. package/codeyam-cli/src/webserver/build/client/assets/{activity.(_tab)-DZu78RI1.js → activity.(_tab)-BpKzcsJz.js} +1 -1
  214. package/codeyam-cli/src/webserver/build/client/assets/addon-fit-CUXOrorO.js +1 -0
  215. package/codeyam-cli/src/webserver/build/client/assets/addon-web-links-Duc5hnl7.js +1 -0
  216. package/codeyam-cli/src/webserver/build/client/assets/agent-transcripts-D9hemwl6.js +22 -0
  217. package/codeyam-cli/src/webserver/build/client/assets/api.dev-mode-events-l0sNRNKZ.js +1 -0
  218. package/codeyam-cli/src/webserver/build/client/assets/api.editor-audit-l0sNRNKZ.js +1 -0
  219. package/codeyam-cli/src/webserver/build/client/assets/api.editor-capture-scenario-l0sNRNKZ.js +1 -0
  220. package/codeyam-cli/src/webserver/build/client/assets/api.editor-client-errors-l0sNRNKZ.js +1 -0
  221. package/codeyam-cli/src/webserver/build/client/assets/api.editor-commit-l0sNRNKZ.js +1 -0
  222. package/codeyam-cli/src/webserver/build/client/assets/api.editor-dev-server-l0sNRNKZ.js +1 -0
  223. package/codeyam-cli/src/webserver/build/client/assets/api.editor-entity-status-l0sNRNKZ.js +1 -0
  224. package/codeyam-cli/src/webserver/build/client/assets/api.editor-journal-entry-l0sNRNKZ.js +1 -0
  225. package/codeyam-cli/src/webserver/build/client/assets/api.editor-journal-image._-l0sNRNKZ.js +1 -0
  226. package/codeyam-cli/src/webserver/build/client/assets/api.editor-journal-l0sNRNKZ.js +1 -0
  227. package/codeyam-cli/src/webserver/build/client/assets/api.editor-journal-screenshot-l0sNRNKZ.js +1 -0
  228. package/codeyam-cli/src/webserver/build/client/assets/api.editor-journal-update-l0sNRNKZ.js +1 -0
  229. package/codeyam-cli/src/webserver/build/client/assets/api.editor-load-commit-l0sNRNKZ.js +1 -0
  230. package/codeyam-cli/src/webserver/build/client/assets/api.editor-refresh-l0sNRNKZ.js +1 -0
  231. package/codeyam-cli/src/webserver/build/client/assets/api.editor-register-scenario-l0sNRNKZ.js +1 -0
  232. package/codeyam-cli/src/webserver/build/client/assets/api.editor-scenario-data-l0sNRNKZ.js +1 -0
  233. package/codeyam-cli/src/webserver/build/client/assets/api.editor-scenario-image._-l0sNRNKZ.js +1 -0
  234. package/codeyam-cli/src/webserver/build/client/assets/api.editor-scenarios-l0sNRNKZ.js +1 -0
  235. package/codeyam-cli/src/webserver/build/client/assets/api.editor-switch-scenario-l0sNRNKZ.js +1 -0
  236. package/codeyam-cli/src/webserver/build/client/assets/api.editor-test-results-l0sNRNKZ.js +1 -0
  237. package/codeyam-cli/src/webserver/build/client/assets/{book-open-Bp5FLkd4.js → book-open-D_nMCFmP.js} +1 -1
  238. package/codeyam-cli/src/webserver/build/client/assets/{chevron-down-DQJA9f4o.js → chevron-down-BH2h1Ea2.js} +1 -1
  239. package/codeyam-cli/src/webserver/build/client/assets/{chunk-JZWAC4HX-7VptmeIr.js → chunk-JZWAC4HX-C4pqxYJB.js} +1 -1
  240. package/codeyam-cli/src/webserver/build/client/assets/{circle-check-B6C4LY9o.js → circle-check-DyIKORY6.js} +1 -1
  241. package/codeyam-cli/src/webserver/build/client/assets/{copy-6nzYCu0G.js → copy-NDbZjXao.js} +1 -1
  242. package/codeyam-cli/src/webserver/build/client/assets/{createLucideIcon-D-QUFOwe.js → createLucideIcon-CMT1jU2q.js} +1 -1
  243. package/codeyam-cli/src/webserver/build/client/assets/dev.empty-BiM6z3Do.js +1 -0
  244. package/codeyam-cli/src/webserver/build/client/assets/editor-D1DAKXtT.js +8 -0
  245. package/codeyam-cli/src/webserver/build/client/assets/{entity._sha._--zvFJ4OH.js → entity._sha._-CrjR3zZW.js} +10 -10
  246. package/codeyam-cli/src/webserver/build/client/assets/entity._sha.scenarios._scenarioId.dev-DkzqFzFj.js +6 -0
  247. package/codeyam-cli/src/webserver/build/client/assets/entity._sha.scenarios._scenarioId.fullscreen-C28BiQzt.js +6 -0
  248. package/codeyam-cli/src/webserver/build/client/assets/entity._sha_.create-scenario-p9hhkjJM.js +6 -0
  249. package/codeyam-cli/src/webserver/build/client/assets/{entity._sha_.edit._scenarioId-C7ysA4Jq.js → entity._sha_.edit._scenarioId-BMvVHNXU.js} +2 -2
  250. package/codeyam-cli/src/webserver/build/client/assets/{entry.client-CU6EUArK.js → entry.client-DTvKq3TY.js} +1 -1
  251. package/codeyam-cli/src/webserver/build/client/assets/{fileTableUtils-EWpfFU4X.js → fileTableUtils-cPo8LiG3.js} +1 -1
  252. package/codeyam-cli/src/webserver/build/client/assets/{files-CrxAoWIL.js → files-DO4CZ16O.js} +1 -1
  253. package/codeyam-cli/src/webserver/build/client/assets/{git-BldHtKeW.js → git-CFCTYk9I.js} +1 -1
  254. package/codeyam-cli/src/webserver/build/client/assets/globals-B17TBSS6.css +1 -0
  255. package/codeyam-cli/src/webserver/build/client/assets/{index-7-1FmlHo.js → index-10oVnAAH.js} +1 -1
  256. package/codeyam-cli/src/webserver/build/client/assets/{index-DuYcwYp_.js → index-BcvgDzbZ.js} +1 -1
  257. package/codeyam-cli/src/webserver/build/client/assets/{labs-CPPVOSWB.js → labs-Zk7ryIM1.js} +1 -1
  258. package/codeyam-cli/src/webserver/build/client/assets/{loader-circle-BnDcD54R.js → loader-circle-BAXYRVEO.js} +1 -1
  259. package/codeyam-cli/src/webserver/build/client/assets/manifest-a632de18.js +1 -0
  260. package/codeyam-cli/src/webserver/build/client/assets/memory-Dg0mvYrI.js +96 -0
  261. package/codeyam-cli/src/webserver/build/client/assets/{pause-DhQX2g22.js → pause-DTAcYxBt.js} +1 -1
  262. package/codeyam-cli/src/webserver/build/client/assets/root-DUKqhFlb.js +67 -0
  263. package/codeyam-cli/src/webserver/build/client/assets/{search-DborVoKD.js → search-fKo7v0Zo.js} +1 -1
  264. package/codeyam-cli/src/webserver/build/client/assets/settings-DfuTtcJP.js +1 -0
  265. package/codeyam-cli/src/webserver/build/client/assets/{simulations-BtrtCYJg.js → simulations-B3aOzpCZ.js} +1 -1
  266. package/codeyam-cli/src/webserver/build/client/assets/{terminal-Bs4NC-VZ.js → terminal-BG4heKCG.js} +1 -1
  267. package/codeyam-cli/src/webserver/build/client/assets/{triangle-alert-DTf3Jojp.js → triangle-alert-DtSmdtM4.js} +1 -1
  268. package/codeyam-cli/src/webserver/build/client/assets/{useCustomSizes-D_bDZyDU.js → useCustomSizes-ByhSyh0W.js} +1 -1
  269. package/codeyam-cli/src/webserver/build/client/assets/useLastLogLine-C14nCb1q.js +2 -0
  270. package/codeyam-cli/src/webserver/build/client/assets/{useReportContext-BsQb6rFd.js → useReportContext-O-jkvSPx.js} +1 -1
  271. package/codeyam-cli/src/webserver/build/client/assets/{useToast-BOur3mUv.js → useToast-9FIWuYfK.js} +1 -1
  272. package/codeyam-cli/src/webserver/build/client/assets/xterm-BqvuqXEL.js +27 -0
  273. package/codeyam-cli/src/webserver/build/server/assets/index-HfLydfDq.js +1 -0
  274. package/codeyam-cli/src/webserver/build/server/assets/server-build-CUu_F-oo.js +366 -0
  275. package/codeyam-cli/src/webserver/build/server/index.js +1 -1
  276. package/codeyam-cli/src/webserver/build-info.json +5 -5
  277. package/codeyam-cli/src/webserver/devServer.js +39 -5
  278. package/codeyam-cli/src/webserver/devServer.js.map +1 -1
  279. package/codeyam-cli/src/webserver/editorProxy.js +440 -0
  280. package/codeyam-cli/src/webserver/editorProxy.js.map +1 -0
  281. package/codeyam-cli/src/webserver/scripts/codeyam-preload.mjs +175 -0
  282. package/codeyam-cli/src/webserver/scripts/journalCapture.ts +140 -0
  283. package/codeyam-cli/src/webserver/server.js +226 -1
  284. package/codeyam-cli/src/webserver/server.js.map +1 -1
  285. package/codeyam-cli/src/webserver/terminalServer.js +698 -0
  286. package/codeyam-cli/src/webserver/terminalServer.js.map +1 -0
  287. package/codeyam-cli/templates/codeyam-editor-claude.md +68 -0
  288. package/codeyam-cli/templates/editor-step-hook.py +147 -0
  289. package/codeyam-cli/templates/isolation-route/next-app.tsx.template +80 -0
  290. package/codeyam-cli/templates/isolation-route/next-pages.tsx.template +79 -0
  291. package/codeyam-cli/templates/isolation-route/vite-react.tsx.template +78 -0
  292. package/codeyam-cli/templates/msw/browser-setup.ts.template +47 -0
  293. package/codeyam-cli/templates/msw/handler-router.ts.template +47 -0
  294. package/codeyam-cli/templates/msw/server-setup.ts.template +52 -0
  295. package/codeyam-cli/templates/nextjs-prisma-sqlite/PRISMA_SETUP.md +84 -0
  296. package/codeyam-cli/templates/nextjs-prisma-sqlite/app/api/todos/route.ts +17 -0
  297. package/codeyam-cli/templates/nextjs-prisma-sqlite/app/globals.css +26 -0
  298. package/codeyam-cli/templates/nextjs-prisma-sqlite/app/layout.tsx +34 -0
  299. package/codeyam-cli/templates/nextjs-prisma-sqlite/app/lib/prisma.ts +19 -0
  300. package/codeyam-cli/templates/nextjs-prisma-sqlite/app/page.tsx +10 -0
  301. package/codeyam-cli/templates/nextjs-prisma-sqlite/eslint.config.mjs +11 -0
  302. package/codeyam-cli/templates/nextjs-prisma-sqlite/gitignore +43 -0
  303. package/codeyam-cli/templates/nextjs-prisma-sqlite/next.config.ts +14 -0
  304. package/codeyam-cli/templates/nextjs-prisma-sqlite/package.json +35 -0
  305. package/codeyam-cli/templates/nextjs-prisma-sqlite/postcss.config.mjs +7 -0
  306. package/codeyam-cli/templates/nextjs-prisma-sqlite/prisma/schema.prisma +27 -0
  307. package/codeyam-cli/templates/nextjs-prisma-sqlite/prisma/seed.ts +37 -0
  308. package/codeyam-cli/templates/nextjs-prisma-sqlite/prisma.config.ts +12 -0
  309. package/codeyam-cli/templates/nextjs-prisma-sqlite/tsconfig.json +34 -0
  310. package/codeyam-cli/templates/prompts/conversation-guidance.txt +12 -0
  311. package/codeyam-cli/templates/prompts/conversation-prompt.txt +3 -3
  312. package/codeyam-cli/templates/prompts/interruption-prompt.txt +3 -3
  313. package/codeyam-cli/templates/prompts/stale-rules-prompt.txt +3 -3
  314. package/codeyam-cli/templates/rule-notification-hook.py +44 -17
  315. package/codeyam-cli/templates/rule-reflection-hook.py +24 -4
  316. package/codeyam-cli/templates/rules-instructions.md +4 -3
  317. package/codeyam-cli/templates/skills/codeyam-dev-mode/SKILL.md +237 -0
  318. package/codeyam-cli/templates/skills/codeyam-editor/SKILL.md +69 -0
  319. package/codeyam-cli/templates/{codeyam-memory.md → skills/codeyam-memory/SKILL.md} +215 -0
  320. package/codeyam-cli/templates/skills/codeyam-memory/scripts/holistic-analysis/deprecated-prompt.md +100 -0
  321. package/codeyam-cli/templates/skills/codeyam-memory/scripts/holistic-analysis/detect-deprecated-patterns.sh +108 -0
  322. package/codeyam-cli/templates/skills/codeyam-memory/scripts/holistic-analysis/find-exports.sh +69 -0
  323. package/codeyam-cli/templates/skills/codeyam-memory/scripts/holistic-analysis/misleading-api-prompt.md +117 -0
  324. package/codeyam-cli/templates/skills/codeyam-memory/scripts/session-mining/analyze-prompt.md +46 -0
  325. package/codeyam-cli/templates/skills/codeyam-memory/scripts/session-mining/cleanup.sh +12 -0
  326. package/codeyam-cli/templates/skills/codeyam-memory/scripts/session-mining/filter.jq +45 -0
  327. package/codeyam-cli/templates/skills/codeyam-memory/scripts/session-mining/preprocess.sh +139 -0
  328. package/package.json +4 -2
  329. package/packages/ai/src/lib/astScopes/astScopeAnalyzer.js +22 -4
  330. package/packages/ai/src/lib/astScopes/astScopeAnalyzer.js.map +1 -1
  331. package/packages/ai/src/lib/completionCall.js +10 -2
  332. package/packages/ai/src/lib/completionCall.js.map +1 -1
  333. package/packages/ai/src/lib/dataStructure/ScopeDataStructure.js +21 -0
  334. package/packages/ai/src/lib/dataStructure/ScopeDataStructure.js.map +1 -1
  335. package/packages/ai/src/lib/dataStructure/helpers/coercePrimitivesToArraysBySchema.js +54 -0
  336. package/packages/ai/src/lib/dataStructure/helpers/coercePrimitivesToArraysBySchema.js.map +1 -0
  337. package/packages/ai/src/lib/dataStructure/helpers/stripNullableMarkers.js +34 -0
  338. package/packages/ai/src/lib/dataStructure/helpers/stripNullableMarkers.js.map +1 -0
  339. package/packages/ai/src/lib/generateEntityScenarioData.js +57 -2
  340. package/packages/ai/src/lib/generateEntityScenarioData.js.map +1 -1
  341. package/packages/analyze/src/lib/ProjectAnalyzer.js +3 -0
  342. package/packages/analyze/src/lib/ProjectAnalyzer.js.map +1 -1
  343. package/packages/analyze/src/lib/files/analyze/analyzeEntities.js +8 -1
  344. package/packages/analyze/src/lib/files/analyze/analyzeEntities.js.map +1 -1
  345. package/packages/analyze/src/lib/files/analyze/dependencyResolver.js +0 -5
  346. package/packages/analyze/src/lib/files/analyze/dependencyResolver.js.map +1 -1
  347. package/packages/analyze/src/lib/files/analyze/findOrCreateEntity.js +9 -0
  348. package/packages/analyze/src/lib/files/analyze/findOrCreateEntity.js.map +1 -1
  349. package/packages/analyze/src/lib/files/scenarios/TransformationTracer.js +54 -27
  350. package/packages/analyze/src/lib/files/scenarios/TransformationTracer.js.map +1 -1
  351. package/packages/analyze/src/lib/files/scenarios/generateDataStructure.js +65 -0
  352. package/packages/analyze/src/lib/files/scenarios/generateDataStructure.js.map +1 -1
  353. package/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.js +18 -4
  354. package/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.js.map +1 -1
  355. package/packages/database/index.js +1 -0
  356. package/packages/database/index.js.map +1 -1
  357. package/packages/database/src/lib/kysely/db.js +5 -0
  358. package/packages/database/src/lib/kysely/db.js.map +1 -1
  359. package/packages/database/src/lib/kysely/tables/editorScenariosTable.js +45 -0
  360. package/packages/database/src/lib/kysely/tables/editorScenariosTable.js.map +1 -0
  361. package/packages/database/src/lib/loadCommits.js +23 -13
  362. package/packages/database/src/lib/loadCommits.js.map +1 -1
  363. package/packages/database/src/lib/loadReadyToBeCapturedAnalyses.js +1 -4
  364. package/packages/database/src/lib/loadReadyToBeCapturedAnalyses.js.map +1 -1
  365. package/packages/database/src/lib/updateCommitMetadata.js +100 -89
  366. package/packages/database/src/lib/updateCommitMetadata.js.map +1 -1
  367. package/packages/database/src/lib/updateFreshAnalysisStatus.js +41 -30
  368. package/packages/database/src/lib/updateFreshAnalysisStatus.js.map +1 -1
  369. package/packages/database/src/lib/updateFreshAnalysisStatusWithScenarios.js +68 -57
  370. package/packages/database/src/lib/updateFreshAnalysisStatusWithScenarios.js.map +1 -1
  371. package/packages/generate/src/lib/componentScenarioPage/generateScenarioClientWrapper.js +29 -1
  372. package/packages/generate/src/lib/componentScenarioPage/generateScenarioClientWrapper.js.map +1 -1
  373. package/packages/generate/src/lib/componentScenarioPage/getIFrameMessageListenerCode.js +33 -5
  374. package/packages/generate/src/lib/componentScenarioPage/getIFrameMessageListenerCode.js.map +1 -1
  375. package/scripts/npm-post-install.cjs +34 -0
  376. package/codeyam-cli/src/webserver/app/routes/api.agent-transcripts.js +0 -486
  377. package/codeyam-cli/src/webserver/app/routes/api.agent-transcripts.js.map +0 -1
  378. package/codeyam-cli/src/webserver/build/client/assets/InlineSpinner-C1rIyZdV.js +0 -34
  379. package/codeyam-cli/src/webserver/build/client/assets/agent-transcripts-DxCa1oBt.js +0 -23
  380. package/codeyam-cli/src/webserver/build/client/assets/dev.empty-DmzSmblj.js +0 -1
  381. package/codeyam-cli/src/webserver/build/client/assets/entity._sha.scenarios._scenarioId.fullscreen-DVTcUnur.js +0 -6
  382. package/codeyam-cli/src/webserver/build/client/assets/entity._sha_.create-scenario-BVgNO76F.js +0 -6
  383. package/codeyam-cli/src/webserver/build/client/assets/globals-B4MPiL7S.css +0 -1
  384. package/codeyam-cli/src/webserver/build/client/assets/manifest-c1fc3656.js +0 -1
  385. package/codeyam-cli/src/webserver/build/client/assets/memory-CfpYxpNu.js +0 -93
  386. package/codeyam-cli/src/webserver/build/client/assets/root-CAAbm4U5.js +0 -62
  387. package/codeyam-cli/src/webserver/build/client/assets/settings-BpLDWmGh.js +0 -1
  388. package/codeyam-cli/src/webserver/build/client/assets/useLastLogLine-DZp6rrQD.js +0 -2
  389. package/codeyam-cli/src/webserver/build/server/assets/index-B8A_aaGG.js +0 -1
  390. package/codeyam-cli/src/webserver/build/server/assets/server-build-69rRZnZo.js +0 -286
  391. package/scripts/finalize-analyzer.cjs +0 -13
  392. /package/codeyam-cli/templates/{codeyam-diagnose.md → commands/codeyam-diagnose.md} +0 -0
  393. /package/codeyam-cli/templates/{codeyam-debug.md → skills/codeyam-debug/SKILL.md} +0 -0
  394. /package/codeyam-cli/templates/{codeyam-new-rule.md → skills/codeyam-new-rule/SKILL.md} +0 -0
  395. /package/codeyam-cli/templates/{codeyam-setup.md → skills/codeyam-setup/SKILL.md} +0 -0
  396. /package/codeyam-cli/templates/{codeyam-sim.md → skills/codeyam-sim/SKILL.md} +0 -0
  397. /package/codeyam-cli/templates/{codeyam-test.md → skills/codeyam-test/SKILL.md} +0 -0
  398. /package/codeyam-cli/templates/{codeyam-verify.md → skills/codeyam-verify/SKILL.md} +0 -0
@@ -0,0 +1,1839 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import * as os from 'os';
4
+ import { fileURLToPath } from 'url';
5
+ import chalk from 'chalk';
6
+ import { runAnalysisForEntities } from "../utils/analysisRunner.js";
7
+ import { ProgressReporter } from "../utils/progress.js";
8
+ import { initializeEnvironment } from "../utils/database.js";
9
+ import { loadEntities, loadAnalyses } from "../../../packages/database/index.js";
10
+ import { IS_INTERNAL_BUILD } from "../utils/buildFlags.js";
11
+ const __filename = fileURLToPath(import.meta.url);
12
+ const __dirname = path.dirname(__filename);
13
+ const STEP_LABELS = {
14
+ 1: 'Plan',
15
+ 2: 'Prototype',
16
+ 3: 'Confirm',
17
+ 4: 'Deconstruct',
18
+ 5: 'Extract',
19
+ 6: 'Glossary',
20
+ 7: 'Analyze',
21
+ 8: 'App Scenarios',
22
+ 9: 'User Scenarios',
23
+ 10: 'Verify',
24
+ 11: 'Journal',
25
+ 12: 'Review',
26
+ };
27
+ /**
28
+ * Append a JSONL log entry to .codeyam/logs/editor-log.jsonl
29
+ */
30
+ function logEvent(root, event, data) {
31
+ try {
32
+ const logsDir = path.join(root, '.codeyam', 'logs');
33
+ fs.mkdirSync(logsDir, { recursive: true });
34
+ const logPath = path.join(logsDir, 'editor-log.jsonl');
35
+ const entry = JSON.stringify({
36
+ ts: new Date().toISOString(),
37
+ event,
38
+ ...data,
39
+ });
40
+ fs.appendFileSync(logPath, entry + '\n', 'utf8');
41
+ }
42
+ catch {
43
+ // Logging is best-effort
44
+ }
45
+ }
46
+ /**
47
+ * Get the project root (where .codeyam/ lives) or cwd.
48
+ */
49
+ function getProjectRoot() {
50
+ return process.env.CODEYAM_ROOT_PATH || process.cwd();
51
+ }
52
+ /**
53
+ * Path to the editor step state file.
54
+ */
55
+ function getStatePath(root) {
56
+ return path.join(root, '.codeyam', 'editor-step.json');
57
+ }
58
+ /**
59
+ * Read the current editor state, or null if none.
60
+ */
61
+ function readState(root) {
62
+ const statePath = getStatePath(root);
63
+ try {
64
+ const content = fs.readFileSync(statePath, 'utf8');
65
+ return JSON.parse(content);
66
+ }
67
+ catch {
68
+ return null;
69
+ }
70
+ }
71
+ /**
72
+ * Write the editor state.
73
+ */
74
+ function writeState(root, state) {
75
+ const statePath = getStatePath(root);
76
+ const dir = path.dirname(statePath);
77
+ fs.mkdirSync(dir, { recursive: true });
78
+ fs.writeFileSync(statePath, JSON.stringify(state, null, 2), 'utf8');
79
+ }
80
+ /**
81
+ * Clear the editor state (for starting a new feature).
82
+ */
83
+ function clearState(root) {
84
+ const statePath = getStatePath(root);
85
+ try {
86
+ fs.unlinkSync(statePath);
87
+ }
88
+ catch {
89
+ // File doesn't exist, that's fine
90
+ }
91
+ }
92
+ /**
93
+ * Check if a project has been scaffolded (package.json exists).
94
+ */
95
+ function hasProject(root) {
96
+ return fs.existsSync(path.join(root, 'package.json'));
97
+ }
98
+ /**
99
+ * Get the CodeYam server port from env or default.
100
+ */
101
+ function getServerPort() {
102
+ return process.env.CODEYAM_PORT || '3111';
103
+ }
104
+ /**
105
+ * Print a checklist item.
106
+ * Inline backtick-wrapped text is highlighted in cyan for visibility.
107
+ */
108
+ function checkbox(text) {
109
+ // Highlight `backtick-wrapped` segments in cyan
110
+ const highlighted = text.replace(/`([^`]+)`/g, (_m, code) => chalk.cyan(code));
111
+ console.log(` ${chalk.dim('[ ]')} ${highlighted}`);
112
+ }
113
+ /**
114
+ * Print a section header.
115
+ */
116
+ function stepHeader(step, title, feature) {
117
+ console.log();
118
+ console.log(chalk.bold.cyan(`━━━ Step ${step}: ${title} ━━━`));
119
+ if (feature) {
120
+ console.log(chalk.dim(`Feature: "${feature}"`));
121
+ }
122
+ console.log();
123
+ }
124
+ /**
125
+ * Print a colored progress tracker showing all 11 steps.
126
+ * Steps before `current` are green ✓, `current` is bold cyan →, future steps are dim ○.
127
+ */
128
+ function printProgressTracker(current) {
129
+ console.log();
130
+ console.log(chalk.dim('┌─────────────────────────────────────┐'));
131
+ for (let i = 1; i <= 12; i++) {
132
+ const label = STEP_LABELS[i];
133
+ const num = i < 10 ? ` ${i}` : `${i}`;
134
+ const content = `${num}. ${label.padEnd(28)}`;
135
+ if (i < current) {
136
+ console.log(chalk.dim(' │') + chalk.green(` ✓ ${content}`) + chalk.dim('│'));
137
+ }
138
+ else if (i === current) {
139
+ console.log(chalk.dim(' │') + chalk.bold.cyan(` → ${content}`) + chalk.dim('│'));
140
+ }
141
+ else {
142
+ console.log(chalk.dim(` │ ○ ${content}│`));
143
+ }
144
+ }
145
+ console.log(chalk.dim(' └─────────────────────────────────────┘'));
146
+ }
147
+ /**
148
+ * Print a hard STOP gate directing to the next command.
149
+ *
150
+ * Options:
151
+ * - confirm: true → step requires user confirmation before proceeding (steps 1, 3, 11)
152
+ */
153
+ function stopGate(current, opts) {
154
+ console.log();
155
+ console.log(chalk.bold.red('━━━ STOP ━━━'));
156
+ console.log();
157
+ console.log(chalk.red('Complete each checklist item above before proceeding to the next step.'));
158
+ if (opts?.confirm) {
159
+ console.log();
160
+ console.log(chalk.yellow('Wait for user confirmation before moving on.'));
161
+ }
162
+ console.log();
163
+ console.log(chalk.bold.yellow('Present the following progress tracker to the user (copy it verbatim):'));
164
+ printProgressTracker(current);
165
+ console.log();
166
+ console.log(chalk.yellow('For the CURRENT step (→), show each checklist item with ✓ (done) or ✗ (skipped + reason).'));
167
+ console.log(chalk.yellow('If any items are ✗, explain why and ask if the user wants to address them.'));
168
+ console.log();
169
+ if (current < 12) {
170
+ console.log(chalk.green('When done, run: ') +
171
+ chalk.bold(`codeyam editor ${current + 1}`));
172
+ }
173
+ else {
174
+ console.log(chalk.green('Feature complete! Run: ') +
175
+ chalk.bold('codeyam editor 1') +
176
+ chalk.green(' to start the next feature'));
177
+ }
178
+ console.log();
179
+ }
180
+ /**
181
+ * Print a RESUMING header with step-specific investigation instructions.
182
+ * Called when a step is re-entered (prevState.step === current step).
183
+ */
184
+ function printResumptionHeader(step) {
185
+ const port = getServerPort();
186
+ const checks = {
187
+ 1: [
188
+ 'Check if plan was already written to context file:\n `cat .codeyam/editor-mode-context.md`',
189
+ ],
190
+ 2: ['Check if project files already exist:\n `ls package.json src/`'],
191
+ 3: ['This is a confirmation step — just re-present to user'],
192
+ 4: [
193
+ 'Check if extraction plan already exists in context file:\n `cat .codeyam/editor-mode-context.md`',
194
+ ],
195
+ 5: [
196
+ 'Check if components/functions already extracted:\n `ls src/components/ src/lib/`',
197
+ ],
198
+ 6: [
199
+ 'Check if glossary already populated:\n `cat .codeyam/glossary.json`',
200
+ ],
201
+ 7: ['Check if isolation routes and registered scenarios already exist'],
202
+ 8: [
203
+ `Check existing scenarios:\n \`curl -s http://localhost:${port}/api/editor-scenarios\``,
204
+ ],
205
+ 9: [
206
+ `Check existing user-persona scenarios:\n \`curl -s http://localhost:${port}/api/editor-scenarios\``,
207
+ ],
208
+ 10: ['Re-verify is safe to repeat — just re-run the checks'],
209
+ 11: [
210
+ `Check if a journal entry already exists for this feature:\n \`curl -s http://localhost:${port}/api/editor-journal\``,
211
+ 'If an entry exists, use PATCH to update it — do NOT create a new one',
212
+ ],
213
+ 12: ['Check if commit already made:\n `git log --oneline -3`'],
214
+ };
215
+ const label = STEP_LABELS[step] || 'Unknown';
216
+ console.log(chalk.bold.yellow(`━━━ RESUMING Step ${step}: ${label} ━━━`));
217
+ console.log(chalk.yellow('This step was already started. Before repeating any actions, investigate:'));
218
+ const items = checks[step] || [];
219
+ for (const item of items) {
220
+ checkbox(item);
221
+ }
222
+ console.log();
223
+ }
224
+ function captureOutput(fn) {
225
+ const stdoutWrite = process.stdout.write.bind(process.stdout);
226
+ const stderrWrite = process.stderr.write.bind(process.stderr);
227
+ const chunks = [];
228
+ const captureWrite = (chunk, encoding, cb) => {
229
+ const text = typeof chunk === 'string'
230
+ ? chunk
231
+ : chunk instanceof Buffer
232
+ ? chunk.toString(typeof encoding === 'string' ? encoding : undefined)
233
+ : String(chunk);
234
+ chunks.push(text);
235
+ if (typeof encoding === 'function') {
236
+ encoding();
237
+ }
238
+ if (typeof cb === 'function') {
239
+ cb();
240
+ }
241
+ return true;
242
+ };
243
+ process.stdout.write = captureWrite;
244
+ process.stderr.write = captureWrite;
245
+ try {
246
+ fn();
247
+ }
248
+ finally {
249
+ process.stdout.write = stdoutWrite;
250
+ process.stderr.write = stderrWrite;
251
+ }
252
+ return chunks.join('');
253
+ }
254
+ function withTempRoot(hasProject, fn) {
255
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), 'codeyam-editor-debug-'));
256
+ if (hasProject) {
257
+ fs.writeFileSync(path.join(root, 'package.json'), '{"name":"codeyam-editor-debug","private":true}', 'utf8');
258
+ }
259
+ try {
260
+ return fn(root);
261
+ }
262
+ finally {
263
+ try {
264
+ fs.rmSync(root, { recursive: true, force: true });
265
+ }
266
+ catch {
267
+ // Best-effort cleanup
268
+ }
269
+ }
270
+ }
271
+ function makeState(step, feature) {
272
+ const now = new Date().toISOString();
273
+ return {
274
+ feature,
275
+ step,
276
+ label: STEP_LABELS[step],
277
+ startedAt: now,
278
+ featureStartedAt: now,
279
+ };
280
+ }
281
+ function normalizeDebugTarget(raw) {
282
+ const value = raw.trim().toLowerCase();
283
+ if (!value)
284
+ return '';
285
+ if (value === 'setup')
286
+ return 'setup';
287
+ if (value === 'overview')
288
+ return 'overview';
289
+ if (value === 'overview-with-state' || value === 'overview-state') {
290
+ return 'overview-with-state';
291
+ }
292
+ if (/^\d+$/.test(value)) {
293
+ return `step-${value}`;
294
+ }
295
+ if (/^step-?\d+$/.test(value)) {
296
+ const num = value.replace('step', '').replace('-', '');
297
+ return `step-${num}`;
298
+ }
299
+ return value;
300
+ }
301
+ function parseDebugTargets(target) {
302
+ if (!target || target.trim().toLowerCase() === 'all')
303
+ return null;
304
+ const rawTargets = target
305
+ .split(',')
306
+ .map((t) => normalizeDebugTarget(t))
307
+ .filter(Boolean);
308
+ const valid = new Set();
309
+ for (const entry of rawTargets) {
310
+ if (entry === 'setup' ||
311
+ entry === 'overview' ||
312
+ entry === 'overview-with-state') {
313
+ valid.add(entry);
314
+ continue;
315
+ }
316
+ if (entry.startsWith('step-')) {
317
+ const num = parseInt(entry.replace('step-', ''), 10);
318
+ if (!isNaN(num) && num >= 1 && num <= 12) {
319
+ valid.add(`step-${num}`);
320
+ continue;
321
+ }
322
+ }
323
+ throw new Error(`Invalid debug target: "${entry}"`);
324
+ }
325
+ return valid;
326
+ }
327
+ function writeContextSnapshot(root, outDir) {
328
+ const contextDir = path.join(outDir, 'context');
329
+ fs.mkdirSync(contextDir, { recursive: true });
330
+ const entries = [];
331
+ const skillPath = path.join(root, '.claude', 'skills', 'codeyam-editor', 'SKILL.md');
332
+ const skillFallback = path.join(__dirname, '..', '..', 'templates', 'codeyam-editor.md');
333
+ const skillSource = fs.existsSync(skillPath) ? skillPath : skillFallback;
334
+ const skillDest = path.join(contextDir, 'codeyam-editor-skill.md');
335
+ fs.copyFileSync(skillSource, skillDest);
336
+ entries.push({
337
+ label: 'codeyam-editor skill',
338
+ source: skillSource,
339
+ file: path.relative(outDir, skillDest),
340
+ status: fs.existsSync(skillPath) ? 'installed' : 'template',
341
+ });
342
+ const claudePath = path.join(root, 'CLAUDE.md');
343
+ if (fs.existsSync(claudePath)) {
344
+ const dest = path.join(contextDir, 'CLAUDE.md');
345
+ fs.copyFileSync(claudePath, dest);
346
+ entries.push({
347
+ label: 'CLAUDE.md',
348
+ source: claudePath,
349
+ file: path.relative(outDir, dest),
350
+ status: 'project',
351
+ });
352
+ }
353
+ else {
354
+ const fallback = path.join(__dirname, '..', '..', 'templates', 'codeyam-editor-claude.md');
355
+ if (fs.existsSync(fallback)) {
356
+ const dest = path.join(contextDir, 'CLAUDE.md');
357
+ fs.copyFileSync(fallback, dest);
358
+ entries.push({
359
+ label: 'CLAUDE.md',
360
+ source: fallback,
361
+ file: path.relative(outDir, dest),
362
+ status: 'template',
363
+ });
364
+ }
365
+ else {
366
+ entries.push({
367
+ label: 'CLAUDE.md',
368
+ file: path.relative(outDir, path.join(contextDir, 'CLAUDE.md')),
369
+ status: 'missing',
370
+ });
371
+ }
372
+ }
373
+ const contextPath = path.join(root, '.codeyam', 'editor-mode-context.md');
374
+ if (fs.existsSync(contextPath)) {
375
+ const dest = path.join(contextDir, 'editor-mode-context.md');
376
+ fs.copyFileSync(contextPath, dest);
377
+ entries.push({
378
+ label: 'editor-mode-context.md',
379
+ source: contextPath,
380
+ file: path.relative(outDir, dest),
381
+ status: 'project',
382
+ });
383
+ }
384
+ else {
385
+ entries.push({
386
+ label: 'editor-mode-context.md',
387
+ file: path.relative(outDir, path.join(contextDir, 'editor-mode-context.md')),
388
+ status: 'missing',
389
+ });
390
+ }
391
+ return entries;
392
+ }
393
+ // ─── Setup (no args, no project) ──────────────────────────────────────
394
+ function printSetup(root) {
395
+ const port = getServerPort();
396
+ logEvent(root, 'setup');
397
+ console.log();
398
+ console.log(chalk.bold.cyan('━━━ Editor Mode: Project Setup ━━━'));
399
+ console.log();
400
+ console.log("No project detected. Let's get started.");
401
+ console.log();
402
+ console.log(chalk.bold('Checklist:'));
403
+ checkbox('Read `.codeyam/editor-mode-context.md` for session state');
404
+ checkbox('Ask the user what they want to build');
405
+ console.log();
406
+ console.log(chalk.bold.red('━━━ STOP ━━━'));
407
+ console.log();
408
+ console.log(chalk.red('Ask the user what they want to build, then run:'));
409
+ console.log();
410
+ console.log(chalk.green(' ') + chalk.bold('codeyam editor 1 --feature "Feature Name"'));
411
+ console.log(chalk.dim(' Replace "Feature Name" with a short title for what the user described.'));
412
+ console.log(chalk.dim(' Step 1 will guide you through planning and getting user confirmation before any code is written.'));
413
+ console.log();
414
+ }
415
+ // ─── Cycle overview (no args, has project) ────────────────────────────
416
+ function printCycleOverview(root, state) {
417
+ logEvent(root, 'overview', state ? { feature: state.feature, step: state.step } : {});
418
+ console.log();
419
+ console.log(chalk.bold.cyan('━━━ Editor Mode: Feature Cycle ━━━'));
420
+ console.log();
421
+ if (state) {
422
+ console.log(chalk.yellow(`Current: Step ${state.step} (${state.label}) — "${state.feature}"`));
423
+ console.log();
424
+ console.log(chalk.green('Continue with: ') +
425
+ chalk.bold(`codeyam editor ${state.step}`));
426
+ console.log(chalk.dim('Or run ') +
427
+ chalk.bold('codeyam editor 1') +
428
+ chalk.dim(' to start a new feature'));
429
+ }
430
+ else {
431
+ console.log('Each feature follows 12 steps. You MUST run each command in order:');
432
+ console.log();
433
+ console.log(` ${chalk.bold.yellow(' 1')} ${chalk.bold('Plan')} — Plan the feature, confirm with user`);
434
+ console.log(` ${chalk.bold.yellow(' 2')} ${chalk.bold('Prototype')} — Build a working prototype fast`);
435
+ console.log(` ${chalk.bold.yellow(' 3')} ${chalk.bold('Confirm')} — Confirm prototype with user`);
436
+ console.log(` ${chalk.bold.yellow(' 4')} ${chalk.bold('Deconstruct')} — Read code, plan all extractions`);
437
+ console.log(` ${chalk.bold.yellow(' 5')} ${chalk.bold('Extract')} — TDD extraction of functions + components`);
438
+ console.log(` ${chalk.bold.yellow(' 6')} ${chalk.bold('Glossary')} — Record functions in glossary`);
439
+ console.log(` ${chalk.bold.yellow(' 7')} ${chalk.bold('Analyze')} — Analyze and verify components`);
440
+ console.log(` ${chalk.bold.yellow(' 8')} ${chalk.bold('App Scenarios')} — Create app-level scenarios`);
441
+ console.log(` ${chalk.bold.yellow(' 9')} ${chalk.bold('User Scenarios')} — Create user-persona scenarios`);
442
+ console.log(` ${chalk.bold.yellow('10')} ${chalk.bold('Verify')} — Review screenshots, check for errors`);
443
+ console.log(` ${chalk.bold.yellow('11')} ${chalk.bold('Journal')} — Create/update journal entry`);
444
+ console.log(` ${chalk.bold.yellow('12')} ${chalk.bold('Review')} — Present summary, get approval`);
445
+ console.log();
446
+ console.log(chalk.green('Start now: ') + chalk.bold('codeyam editor 1'));
447
+ }
448
+ console.log();
449
+ }
450
+ // ─── Step 1: Plan ─────────────────────────────────────────────────────
451
+ function printStep1(root, feature) {
452
+ const prevState = readState(root);
453
+ const isResuming = prevState?.step === 1;
454
+ if (!isResuming) {
455
+ clearState(root);
456
+ }
457
+ // If feature is provided, save initial state so step 2 can pick it up
458
+ if (feature) {
459
+ const now = new Date().toISOString();
460
+ writeState(root, {
461
+ feature,
462
+ step: 1,
463
+ label: STEP_LABELS[1],
464
+ startedAt: isResuming ? prevState.startedAt : now,
465
+ featureStartedAt: isResuming ? prevState.featureStartedAt : now,
466
+ });
467
+ }
468
+ logEvent(root, 'step', { step: 1, label: 'Plan', feature });
469
+ stepHeader(1, 'Plan', feature);
470
+ if (isResuming) {
471
+ printResumptionHeader(1);
472
+ }
473
+ console.log('Plan the feature before writing ANY code.');
474
+ console.log();
475
+ console.log(chalk.bold('Checklist:'));
476
+ checkbox('Read `.codeyam/glossary.json` for reusable functions/components');
477
+ checkbox('Ask the user what they want to build (if not already described)');
478
+ checkbox('Ask clarifying questions using `AskUserQuestion` with selectable options');
479
+ console.log(chalk.dim(' Use AskUserQuestion for EVERY clarifying question — give 2-4 concrete options the user can pick from.'));
480
+ console.log(chalk.dim(' Focus on what the USER will see and do, not on databases, APIs, or components.'));
481
+ console.log(chalk.dim(' Do NOT ask about tech stack, frameworks, libraries, or implementation details — only ask about user-facing choices.'));
482
+ console.log(chalk.dim(' Good: "What should happen when there are no results?" → options: "Show empty state message", "Show suggestions"'));
483
+ console.log(chalk.dim(' Bad: Free-form text asking "What do you think about the data model?"'));
484
+ console.log(chalk.dim(' You can ask up to 4 questions at once. Bundle related questions into a single AskUserQuestion call.'));
485
+ checkbox("Summarize what you'll build in plain language the user can verify against their vision");
486
+ console.log();
487
+ console.log(chalk.bold('Present a selection menu to the user (use AskUserQuestion):'));
488
+ console.log(chalk.green(' "Looks good, start building!"') +
489
+ chalk.dim(' — proceed to step 2'));
490
+ console.log(chalk.yellow(' "I\'d like some changes"') +
491
+ chalk.dim(' — user describes changes, you revise the plan, then re-present'));
492
+ console.log();
493
+ console.log(chalk.dim('This step is for understanding user goals and getting buy-in. Code comes in Step 2.'));
494
+ console.log();
495
+ console.log(chalk.bold.red('━━━ STOP ━━━'));
496
+ console.log();
497
+ console.log(chalk.red('Complete each checklist item above before proceeding to the next step.'));
498
+ console.log();
499
+ console.log(chalk.yellow('Wait for user confirmation before moving on.'));
500
+ console.log();
501
+ console.log(chalk.bold.yellow('Present the following progress tracker to the user (copy it verbatim):'));
502
+ printProgressTracker(1);
503
+ console.log();
504
+ console.log(chalk.yellow('For the CURRENT step (→), show each checklist item with ✓ (done) or ✗ (skipped + reason).'));
505
+ console.log(chalk.yellow('If any items are ✗, explain why and ask if the user wants to address them.'));
506
+ console.log();
507
+ console.log(chalk.green('When done, run: ') +
508
+ chalk.bold('codeyam editor 2 --feature "Feature Name"'));
509
+ console.log(chalk.dim(' Replace "Feature Name" with a short title for what you just described.'));
510
+ console.log();
511
+ }
512
+ // ─── Step 2: Prototype ────────────────────────────────────────────────
513
+ function printStep2(root, feature) {
514
+ const port = getServerPort();
515
+ const projectExists = hasProject(root);
516
+ const prevState = readState(root);
517
+ const isResuming = prevState?.step === 2;
518
+ const now = new Date().toISOString();
519
+ writeState(root, {
520
+ feature,
521
+ step: 2,
522
+ label: STEP_LABELS[2],
523
+ startedAt: isResuming ? prevState.startedAt : now,
524
+ featureStartedAt: isResuming ? prevState.featureStartedAt : now,
525
+ });
526
+ logEvent(root, 'step', { step: 2, label: 'Prototype', feature });
527
+ stepHeader(2, 'Prototype', feature);
528
+ if (isResuming) {
529
+ printResumptionHeader(2);
530
+ }
531
+ console.log('Build fast with real data. Prioritize speed over quality.');
532
+ console.log();
533
+ // If no project exists yet, include scaffolding instructions first
534
+ if (!projectExists) {
535
+ const templateDir = path.join(__dirname, '..', '..', 'templates', 'nextjs-prisma-sqlite');
536
+ const hasTemplate = fs.existsSync(templateDir);
537
+ console.log(chalk.bold('Scaffold the project:'));
538
+ if (hasTemplate) {
539
+ checkbox('Copy the project template and install dependencies');
540
+ console.log();
541
+ console.log(chalk.dim(' Copy template (Next.js + Prisma 7 + SQLite, pre-configured):'));
542
+ console.log(chalk.dim(` cp -r ${templateDir}/* .`));
543
+ console.log(chalk.dim(` cp ${templateDir}/.env .`));
544
+ console.log(chalk.dim(` cp ${templateDir}/gitignore .gitignore`));
545
+ console.log(chalk.dim(' npm install'));
546
+ console.log();
547
+ checkbox('Define your data models in `prisma/schema.prisma`');
548
+ console.log(chalk.dim(" Replace the placeholder Todo model with your app's models"));
549
+ console.log();
550
+ checkbox('Push schema and seed the database');
551
+ console.log(chalk.dim(' npm run db:push'));
552
+ console.log(chalk.dim(' # Edit prisma/seed.ts with your seed data, then:'));
553
+ console.log(chalk.dim(' npm run db:seed'));
554
+ console.log();
555
+ console.log(chalk.dim(' See PRISMA_SETUP.md for Prisma patterns and important warnings.'));
556
+ console.log(chalk.dim(' Key: import { prisma } from "@/app/lib/prisma" in API routes.'));
557
+ console.log(chalk.dim(' Key: Seed scripts must use the adapter pattern (see prisma/seed.ts).'));
558
+ }
559
+ else {
560
+ checkbox('Scaffold the project (Next.js App Router) using temp-dir-rsync pattern');
561
+ console.log();
562
+ console.log(chalk.dim(' Scaffolding pattern (avoids .claude/ conflicts):'));
563
+ console.log(chalk.dim(' SCAFFOLD_DIR="/tmp/codeyam-scaffold-$$" && mkdir -p "$SCAFFOLD_DIR"'));
564
+ console.log(chalk.dim(' npx create-next-app@latest "$SCAFFOLD_DIR" --typescript --tailwind --eslint \\'));
565
+ console.log(chalk.dim(' --app --no-src-dir --no-import-alias --no-react-compiler --turbopack'));
566
+ console.log(chalk.dim(' rsync -a --exclude=\'.git\' "$SCAFFOLD_DIR/" . && rm -rf "$SCAFFOLD_DIR"'));
567
+ console.log();
568
+ checkbox('Set up Prisma + SQLite database');
569
+ console.log(chalk.dim(' npm install prisma @prisma/client @prisma/adapter-better-sqlite3 better-sqlite3'));
570
+ console.log(chalk.dim(' npm install -D @types/better-sqlite3'));
571
+ console.log(chalk.dim(' npx prisma init --datasource-provider sqlite'));
572
+ console.log(chalk.dim(' # Define schema, then: npx prisma db push'));
573
+ }
574
+ console.log();
575
+ checkbox('Initialize git so analysis and commits work');
576
+ console.log(chalk.dim(' git init && git add -A && git commit -m "Initial commit"'));
577
+ console.log();
578
+ checkbox('Run `codeyam init --force --keep-server` to detect the project and configure it');
579
+ console.log(chalk.dim(' This auto-detects webapps and configures the start command for analysis'));
580
+ console.log();
581
+ checkbox('Verify `.codeyam/config.json` has `startCommand` in the webapp entry');
582
+ console.log(chalk.dim(' Should look like: "startCommand": { "command": "sh", "args": ["-c", "npm run dev -- --port $PORT"] }'));
583
+ console.log(chalk.dim(' If missing, add it manually. $PORT is replaced at runtime by the analyzer.'));
584
+ console.log();
585
+ checkbox(`Notify CodeYam: \`curl -s -X POST http://localhost:${port}/api/editor-refresh\``);
586
+ console.log();
587
+ console.log(chalk.bold('Build the feature:'));
588
+ }
589
+ console.log(chalk.bold('Checklist:'));
590
+ checkbox('Create/update API routes (real database reads via Prisma)');
591
+ checkbox('Seed the database with demo data');
592
+ checkbox('Build the page/feature UI components');
593
+ checkbox('Verify the dev server shows the changes');
594
+ console.log();
595
+ console.log(chalk.bold('Verify the dev server:'));
596
+ console.log(chalk.dim(` # Get dev server URL: curl -s http://localhost:${port}/api/editor-dev-server`));
597
+ console.log(chalk.dim(' # Check page loads: curl -s -o /dev/null -w "%{http_code}" http://localhost:<dev-port>'));
598
+ console.log(chalk.dim(' # Check API routes: curl -s http://localhost:<dev-port>/api/your-route'));
599
+ console.log();
600
+ console.log(chalk.bold('Verify before proceeding:'));
601
+ console.log(chalk.yellow(' Verify everything works before presenting the prototype to the user.'));
602
+ checkbox('Verify the page loads: curl the dev server URL and confirm HTTP 200 (not an error page)');
603
+ checkbox('Verify API routes return valid JSON: curl each route and confirm no error responses');
604
+ checkbox('Check for broken images: look at any <img> src attributes and verify the assets exist');
605
+ checkbox('Check the dev server terminal output for runtime errors (missing modules, failed imports)');
606
+ console.log(chalk.dim(' If any check fails, fix the issue and re-verify before proceeding.'));
607
+ console.log();
608
+ console.log(chalk.dim('Focus on building the prototype. Scenarios and refactoring happen in later steps.'));
609
+ stopGate(2);
610
+ }
611
+ // ─── Step 3: Confirm ──────────────────────────────────────────────────
612
+ function printStep3(root, feature) {
613
+ const port = getServerPort();
614
+ const prevState = readState(root);
615
+ const isResuming = prevState?.step === 3;
616
+ const now = new Date().toISOString();
617
+ writeState(root, {
618
+ feature,
619
+ step: 3,
620
+ label: STEP_LABELS[3],
621
+ startedAt: isResuming ? prevState.startedAt : now,
622
+ featureStartedAt: prevState?.featureStartedAt || now,
623
+ });
624
+ logEvent(root, 'step', { step: 3, label: 'Confirm', feature });
625
+ stepHeader(3, 'Confirm', feature);
626
+ if (isResuming) {
627
+ printResumptionHeader(3);
628
+ }
629
+ console.log('Summarize what was built and get user confirmation.');
630
+ console.log();
631
+ console.log(chalk.bold('Before presenting — verify everything works:'));
632
+ checkbox(`Refresh the preview: \`curl -s -X POST http://localhost:${port}/api/editor-refresh\``);
633
+ checkbox(`Refresh and check for SSR errors: \`curl -s -X POST http://localhost:${port}/api/dev-mode-preview\` — look at the \`preview\` field for \`healthy: false\``);
634
+ checkbox('Verify API routes return valid data (curl each route)');
635
+ checkbox(`Navigate to each page and check health: \`curl -s -X POST http://localhost:${port}/api/dev-mode-preview -H 'Content-Type: application/json' -d '{"path":"/your-route"}'\``);
636
+ console.log();
637
+ console.log(chalk.bold(' Check for broken images on each page:'));
638
+ checkbox('Get the dev server URL from `curl -s http://localhost:' +
639
+ port +
640
+ '/api/editor-dev-server` (the `url` field)');
641
+ checkbox('For each page: `curl -s <dev-server-url>/your-route` and inspect `<img>` src attributes');
642
+ checkbox('Verify every image src is a valid path (not a missing file, placeholder URL, or broken reference)');
643
+ checkbox('If any images are broken: fix the src (use real assets, placeholders from a CDN, or remove the image)');
644
+ console.log(chalk.yellow(' Do not present to the user until all checks pass. Fix issues first.'));
645
+ console.log();
646
+ console.log(chalk.bold('Then present to the user:'));
647
+ checkbox('Summarize what was built (routes, components, data)');
648
+ checkbox('Show the user the current state of the prototype');
649
+ console.log();
650
+ console.log(chalk.bold('Present a selection menu to the user (use AskUserQuestion):'));
651
+ console.log(chalk.green(' "Yes, this looks right!"') +
652
+ chalk.dim(' — proceed to step 4'));
653
+ console.log(chalk.yellow(' "I\'d like some changes"') +
654
+ chalk.dim(' — user describes changes, you make them, then re-present'));
655
+ console.log();
656
+ console.log(chalk.dim('Wait for user approval before moving on. Refactoring and scenarios happen in later steps.'));
657
+ stopGate(3, { confirm: true });
658
+ }
659
+ // ─── Step 4: Deconstruct ──────────────────────────────────────────────
660
+ function printStep4(root, feature) {
661
+ const prevState = readState(root);
662
+ const isResuming = prevState?.step === 4;
663
+ const now = new Date().toISOString();
664
+ writeState(root, {
665
+ feature,
666
+ step: 4,
667
+ label: STEP_LABELS[4],
668
+ startedAt: isResuming ? prevState.startedAt : now,
669
+ featureStartedAt: prevState?.featureStartedAt || now,
670
+ });
671
+ logEvent(root, 'step', { step: 4, label: 'Deconstruct', feature });
672
+ stepHeader(4, 'Deconstruct', feature);
673
+ if (isResuming) {
674
+ printResumptionHeader(4);
675
+ }
676
+ console.log(chalk.bold('Goal: pages contain ONLY components. Components contain ONLY sub-components.'));
677
+ console.log(chalk.yellow('This step is read and plan only. Code extraction happens in step 5.'));
678
+ console.log();
679
+ console.log(chalk.bold.red('THE RULE: No direct JSX in page files.'));
680
+ console.log(chalk.yellow(' After extraction, a page/route file should import and compose components — nothing else.'));
681
+ console.log(chalk.yellow(' Every distinct visual section in the page is its own component.'));
682
+ console.log(chalk.yellow(' Every component that renders multiple distinct sections should be split into sub-components.'));
683
+ console.log(chalk.yellow(' If a component has N visually distinct parts, it should compose N sub-components.'));
684
+ console.log();
685
+ console.log(chalk.bold('Checklist:'));
686
+ checkbox('Read `.codeyam/glossary.json` — note reusable functions/components');
687
+ checkbox('Read EVERY file created or modified in this session');
688
+ console.log(chalk.yellow(' For EACH file, identify EVERY extractable piece:'));
689
+ console.log(chalk.yellow(' Components: headers, nav, loading states, empty states, error states,'));
690
+ console.log(chalk.yellow(' badges/pills, image containers, card sections, form fields, modals,'));
691
+ console.log(chalk.yellow(' titles, descriptions, rating displays, status indicators, buttons'));
692
+ console.log(chalk.yellow(' Functions: data transforms, calculations, formatting, validation,'));
693
+ console.log(chalk.yellow(' API response shaping, any logic that is not directly about rendering'));
694
+ console.log(chalk.yellow(' Hooks: data fetching, state management, side effects'));
695
+ console.log();
696
+ checkbox('Write a numbered extraction plan listing EVERYTHING you will extract');
697
+ console.log(chalk.yellow(' The end state: every page file is ONLY imports + component composition.'));
698
+ console.log(chalk.yellow(' No raw <div>, <span>, <h1>, <p>, <img>, or <ul> in page files.'));
699
+ console.log(chalk.yellow(' Every visual section in every component is itself a component.'));
700
+ console.log();
701
+ console.log(chalk.yellow(' For each item in the plan, note:'));
702
+ console.log(chalk.yellow(' — What it is (component, function, hook)'));
703
+ console.log(chalk.yellow(' — Where it currently lives (source file + approximate lines)'));
704
+ console.log(chalk.yellow(' — Where it will go (new file path)'));
705
+ console.log();
706
+ console.log(chalk.dim('Present the numbered plan, then proceed to step 5 to execute it.'));
707
+ stopGate(4);
708
+ }
709
+ // ─── Step 5: Extract ──────────────────────────────────────────────────
710
+ function printStep5(root, feature) {
711
+ const prevState = readState(root);
712
+ const isResuming = prevState?.step === 5;
713
+ const now = new Date().toISOString();
714
+ writeState(root, {
715
+ feature,
716
+ step: 5,
717
+ label: STEP_LABELS[5],
718
+ startedAt: isResuming ? prevState.startedAt : now,
719
+ featureStartedAt: prevState?.featureStartedAt || now,
720
+ });
721
+ logEvent(root, 'step', { step: 5, label: 'Extract', feature });
722
+ stepHeader(5, 'Extract', feature);
723
+ if (isResuming) {
724
+ printResumptionHeader(5);
725
+ }
726
+ console.log('Execute your extraction plan from step 4.');
727
+ console.log();
728
+ console.log(chalk.bold('Components:'));
729
+ checkbox('Extract each component from your plan into its own file');
730
+ checkbox('Page/route files must contain ZERO direct JSX — only imported components');
731
+ checkbox('Every component that renders multiple sections must be split into sub-components');
732
+ console.log(chalk.dim(' No tests needed — visual verification happens in step 7'));
733
+ console.log();
734
+ console.log(chalk.bold('Library functions (TDD):'));
735
+ checkbox('For each function: write MULTIPLE failing tests FIRST, then extract to make them pass');
736
+ console.log(chalk.dim(' Cover: typical inputs, edge cases, empty/null inputs, error conditions'));
737
+ console.log(chalk.dim(' Aim for 3-8 test cases per function depending on complexity'));
738
+ checkbox('Place test files next to source: `app/lib/drinks.ts` → `app/lib/drinks.test.ts`');
739
+ console.log(chalk.yellow(' Tests ARE the only coverage for library functions — step 7 only captures component screenshots.'));
740
+ console.log();
741
+ console.log(chalk.bold('Recursive pass:'));
742
+ checkbox('Re-read EVERY new file you just created — extract components from components, functions from functions');
743
+ checkbox('Keep going until every file is a thin shell: just imports and composition');
744
+ console.log(chalk.yellow(' Check: does any file contain raw <div>, <span>, <h1>, <p>, <img>, or <ul>?'));
745
+ console.log(chalk.yellow(' If yes → that JSX section is a component waiting to be extracted.'));
746
+ console.log();
747
+ console.log(chalk.bold('Verify before proceeding:'));
748
+ checkbox('Run all tests and verify they pass');
749
+ checkbox('Page files contain ONLY imports + component composition — no raw HTML tags');
750
+ checkbox('Every component renders ONE thing or composes sub-components — no multi-section JSX');
751
+ console.log(chalk.dim('Reuse glossary functions when they fit naturally. Extract a new function when the use case diverges.'));
752
+ console.log();
753
+ console.log(chalk.dim('Focus on TDD for functions and extraction for components. Scenarios come in later steps.'));
754
+ stopGate(5);
755
+ }
756
+ // ─── Step 6: Glossary ─────────────────────────────────────────────────
757
+ function printStep6(root, feature) {
758
+ const prevState = readState(root);
759
+ const isResuming = prevState?.step === 6;
760
+ const now = new Date().toISOString();
761
+ writeState(root, {
762
+ feature,
763
+ step: 6,
764
+ label: STEP_LABELS[6],
765
+ startedAt: isResuming ? prevState.startedAt : now,
766
+ featureStartedAt: prevState?.featureStartedAt || now,
767
+ });
768
+ logEvent(root, 'step', { step: 6, label: 'Glossary', feature });
769
+ stepHeader(6, 'Glossary', feature);
770
+ if (isResuming) {
771
+ printResumptionHeader(6);
772
+ }
773
+ console.log('Record all new functions/components in `.codeyam/glossary.json`.');
774
+ console.log();
775
+ console.log(chalk.bold('Checklist:'));
776
+ checkbox("Read `.codeyam/glossary.json` (create if it doesn't exist)");
777
+ checkbox('Add an entry for each new function/component extracted in step 5');
778
+ checkbox('Each entry should have: name, filePath, description, parameters, returnType, tags, feature');
779
+ checkbox('For each function with a test file from step 5, set `testFile` to the relative path');
780
+ console.log();
781
+ console.log(chalk.bold('Entry format:'));
782
+ console.log(chalk.dim(' { "name": "calculateTotal", "filePath": "app/utils/pricing.ts",'));
783
+ console.log(chalk.dim(' "description": "Calculates total price including tax and discounts",'));
784
+ console.log(chalk.dim(' "parameters": [{ "name": "items", "type": "CartItem[]" }],'));
785
+ console.log(chalk.dim(' "returnType": "number", "tags": ["pricing"],'));
786
+ console.log(chalk.dim(' "testFile": "app/utils/pricing.test.ts",'));
787
+ console.log(chalk.dim(` "feature": "${feature}", "createdAt": "..." }`));
788
+ console.log();
789
+ console.log(chalk.dim('Focus on updating the glossary. Application code and scenarios come in later steps.'));
790
+ stopGate(6);
791
+ }
792
+ // ─── Step 7: Analyze ──────────────────────────────────────────────────
793
+ function printStep7(root, feature) {
794
+ const port = getServerPort();
795
+ const prevState = readState(root);
796
+ const isResuming = prevState?.step === 7;
797
+ const now = new Date().toISOString();
798
+ writeState(root, {
799
+ feature,
800
+ step: 7,
801
+ label: STEP_LABELS[7],
802
+ startedAt: isResuming ? prevState.startedAt : now,
803
+ featureStartedAt: prevState?.featureStartedAt || now,
804
+ });
805
+ logEvent(root, 'step', { step: 7, label: 'Analyze', feature });
806
+ stepHeader(7, 'Analyze and Verify', feature);
807
+ if (isResuming) {
808
+ printResumptionHeader(7);
809
+ }
810
+ console.log('Verify visual components (via isolation routes) and library functions (via tests).');
811
+ console.log();
812
+ console.log(chalk.bold('Visual Components — Component Isolation:'));
813
+ checkbox('List all files with new/modified visual components from step 5');
814
+ checkbox('Ensure `.gitignore` includes `**/codeyam-isolate*` (add if missing)');
815
+ checkbox('For each visual component:');
816
+ console.log(chalk.dim(' 1. Read the source AND find where it is used in the app to understand:'));
817
+ console.log(chalk.dim(' — Props/interface'));
818
+ console.log(chalk.dim(' — Container width in the real app (e.g. card in a 3-col grid → max-w-sm)'));
819
+ console.log(chalk.dim(' 2. Plan multiple scenarios that exercise the component like tests:'));
820
+ console.log(chalk.dim(' — Default/happy path with typical data'));
821
+ console.log(chalk.dim(' — Edge cases: empty/missing data, long text, maximum items, zero counts'));
822
+ console.log(chalk.dim(' — Different visual states: loading, error, disabled, selected, hover'));
823
+ console.log(chalk.dim(' — Boundary values: single item vs many, min/max ratings, very long names'));
824
+ console.log(chalk.dim(' 3. Create ONE isolation route per component with a scenarios map and ?s= query param:'));
825
+ console.log(chalk.dim(' Remix: app/routes/codeyam-isolate.ComponentName.tsx → /codeyam-isolate/ComponentName'));
826
+ console.log(chalk.dim(' Next.js: app/codeyam-isolate/ComponentName/page.tsx → /codeyam-isolate/ComponentName'));
827
+ console.log(chalk.dim(' The route defines a `scenarios` object mapping scenario names to props,'));
828
+ console.log(chalk.dim(' reads `?s=ScenarioName` from the URL, and renders the component with those props.'));
829
+ console.log(chalk.dim(' Wrap the component in a capture container with id="codeyam-capture":'));
830
+ console.log(chalk.dim(' <div id="codeyam-capture" style={{ display:"inline-block", padding:"20px" }}>'));
831
+ console.log(chalk.dim(' <div style={{ width:"100%", maxWidth:"..." }}> ← match the app\'s container width'));
832
+ console.log(chalk.dim(' e.g. card in a 3-col grid → maxWidth:"24rem", full-width component → omit maxWidth'));
833
+ console.log(chalk.dim(' The screenshot captures just this wrapper, so the component fills the image.'));
834
+ console.log(chalk.dim(' Center the wrapper on the page (flexbox center both axes) and set a page background'));
835
+ console.log(chalk.dim(' color that matches where the component normally appears (e.g. white for light UIs).'));
836
+ console.log(chalk.dim(' 4. Wait 2 seconds for HMR, then register + capture each scenario:'));
837
+ console.log(chalk.dim(` codeyam editor register '{"name":"ComponentName - Scenario",`));
838
+ console.log(chalk.dim(` "componentName":"ComponentName","componentPath":"path/to/file.tsx",`));
839
+ console.log(chalk.dim(` "url":"/codeyam-isolate/ComponentName?s=Scenario",`));
840
+ console.log(chalk.dim(` "mockData":{"routes":{"/api/...":{"body":[...]}}}}'`));
841
+ console.log(chalk.dim(' url is a PATH (starts with /) — the proxy routes it and intercepts API calls'));
842
+ console.log(chalk.dim(' mockData.routes provides data for API calls the component makes internally'));
843
+ console.log(chalk.dim(' (omit mockData if the component has no internal API calls)'));
844
+ console.log(chalk.yellow(' 5. IMPORTANT: Check the register response for `clientErrors` array'));
845
+ console.log(chalk.yellow(' If clientErrors is non-empty → fix the isolation route and re-register'));
846
+ console.log(chalk.yellow(' Fix client errors and re-register before moving on'));
847
+ console.log(chalk.dim(' Isolation routes stay in the project (in .gitignore) so the editor preview can display them'));
848
+ console.log();
849
+ console.log(chalk.bold('Library Functions — run tests:'));
850
+ checkbox('Run ALL test files created in step 5');
851
+ console.log(chalk.dim(' Example: npx vitest run app/lib/drinks.test.ts'));
852
+ checkbox('Verify every test passes');
853
+ checkbox('If any test fails, fix the source code and re-run');
854
+ console.log();
855
+ console.log(chalk.dim('Do not proceed until both component isolations and library tests pass.'));
856
+ console.log();
857
+ checkbox('Run `codeyam editor audit` to verify all components have scenarios and all functions have tests');
858
+ stopGate(7);
859
+ }
860
+ // ─── Step 8: App Scenarios ────────────────────────────────────────────
861
+ function printStep8(root, feature) {
862
+ const port = getServerPort();
863
+ const prevState = readState(root);
864
+ const isResuming = prevState?.step === 8;
865
+ const now = new Date().toISOString();
866
+ writeState(root, {
867
+ feature,
868
+ step: 8,
869
+ label: STEP_LABELS[8],
870
+ startedAt: isResuming ? prevState.startedAt : now,
871
+ featureStartedAt: prevState?.featureStartedAt || now,
872
+ });
873
+ logEvent(root, 'step', { step: 8, label: 'App Scenarios', feature });
874
+ stepHeader(8, 'App Scenarios', feature);
875
+ if (isResuming) {
876
+ printResumptionHeader(8);
877
+ }
878
+ console.log('Create app-level scenarios representing different data states.');
879
+ console.log();
880
+ console.log(chalk.bold('Checklist:'));
881
+ checkbox('Create scenarios for key data states (empty, loaded, error)');
882
+ console.log(chalk.dim(' Each scenario provides data across ALL API routes for that state'));
883
+ console.log(chalk.dim(' Name app scenarios with "App - " prefix: "App - Empty", "App - Full Catalog", "App - API Error"'));
884
+ checkbox('Register each scenario (auto-captures screenshot):');
885
+ console.log(chalk.dim(` codeyam editor register '{"name":"App - Empty","description":"...","mockData":{"routes":{"/api/...":{"body":[...]}}}}'`));
886
+ checkbox('After each registration, check the response for `clientErrors`');
887
+ console.log(chalk.yellow(' If clientErrors is non-empty → fix the issue and re-register the scenario'));
888
+ console.log(chalk.yellow(' Fix client errors and re-register before moving on'));
889
+ console.log();
890
+ console.log(chalk.dim('Focus on creating and registering app-level scenarios. Code fixes happen in step 10 if needed.'));
891
+ stopGate(8);
892
+ }
893
+ // ─── Step 9: User Scenarios ───────────────────────────────────────────
894
+ function printStep9(root, feature) {
895
+ const port = getServerPort();
896
+ const prevState = readState(root);
897
+ const isResuming = prevState?.step === 9;
898
+ const now = new Date().toISOString();
899
+ writeState(root, {
900
+ feature,
901
+ step: 9,
902
+ label: STEP_LABELS[9],
903
+ startedAt: isResuming ? prevState.startedAt : now,
904
+ featureStartedAt: prevState?.featureStartedAt || now,
905
+ });
906
+ logEvent(root, 'step', { step: 9, label: 'User Scenarios', feature });
907
+ stepHeader(9, 'User Scenarios', feature);
908
+ if (isResuming) {
909
+ printResumptionHeader(9);
910
+ }
911
+ console.log('Create per-persona scenarios if the app has users. Skip to step 10 if no users.');
912
+ console.log();
913
+ console.log(chalk.bold('If the app has users:'));
914
+ checkbox('Create scenarios for each user persona (admin, regular user, new user)');
915
+ console.log(chalk.dim(' Each persona scenario provides data across ALL API routes for that user type'));
916
+ checkbox('Register each persona scenario (auto-captures screenshot):');
917
+ console.log(chalk.dim(` codeyam editor register '{"name":"...","description":"...","mockData":{"routes":{"/api/...":{"body":[...]}}}}'`));
918
+ checkbox('After each registration, check the response for `clientErrors`');
919
+ console.log(chalk.yellow(' If clientErrors is non-empty → fix the issue and re-register the scenario'));
920
+ console.log(chalk.yellow(' Fix client errors and re-register before moving on'));
921
+ console.log();
922
+ console.log(chalk.bold('If the app has NO users:'));
923
+ console.log(chalk.dim(' Skip this step and proceed to step 10 (Verify).'));
924
+ console.log();
925
+ console.log(chalk.dim('Focus on creating user-persona scenarios (or skip if no users). Code fixes happen in step 10 if needed.'));
926
+ stopGate(9);
927
+ }
928
+ // ─── Step 10: Verify ──────────────────────────────────────────────────
929
+ function printStep10(root, feature) {
930
+ const port = getServerPort();
931
+ const prevState = readState(root);
932
+ const isResuming = prevState?.step === 10;
933
+ const now = new Date().toISOString();
934
+ writeState(root, {
935
+ feature,
936
+ step: 10,
937
+ label: STEP_LABELS[10],
938
+ startedAt: isResuming ? prevState.startedAt : now,
939
+ featureStartedAt: prevState?.featureStartedAt || now,
940
+ });
941
+ logEvent(root, 'step', { step: 10, label: 'Verify', feature });
942
+ stepHeader(10, 'Verify', feature);
943
+ if (isResuming) {
944
+ printResumptionHeader(10);
945
+ }
946
+ console.log('Verify component isolation screenshots, editor scenarios, and library tests.');
947
+ console.log();
948
+ console.log(chalk.bold('Component isolation screenshots — verify:'));
949
+ checkbox('Review component screenshots in the App tab (grouped under Components)');
950
+ checkbox('If any screenshot looks wrong, fix the component code');
951
+ console.log(chalk.yellow(' After fixing a visual component, re-register the affected scenarios:'));
952
+ console.log(chalk.dim(` codeyam editor register '{"name":"ComponentName - Scenario",...}'`));
953
+ console.log();
954
+ console.log(chalk.bold('Editor scenarios (App tab) — visual + error check:'));
955
+ checkbox(`Refresh the preview: \`curl -s -X POST http://localhost:${port}/api/editor-refresh\``);
956
+ checkbox('Click through each app-level and user-persona scenario in the preview');
957
+ checkbox(`Check for client-side errors: \`curl -s http://localhost:${port}/api/editor-client-errors\``);
958
+ console.log(chalk.yellow(' If `hasErrors` is true: list each scenario with errors, fix the source code,'));
959
+ console.log(chalk.yellow(' re-register the affected scenarios, and re-check until hasErrors is false'));
960
+ console.log(chalk.dim(' Common errors: React errors, failed fetches, undefined references, hydration mismatches'));
961
+ checkbox('Verify no broken images in any scenario screenshots');
962
+ console.log();
963
+ console.log(chalk.bold('Library functions — test check:'));
964
+ checkbox('Re-run all test files from step 5 to confirm they still pass');
965
+ console.log(chalk.dim(' Example: npx vitest run app/lib/drinks.test.ts'));
966
+ checkbox('If any test fails, fix the source code and re-run');
967
+ console.log();
968
+ console.log(chalk.dim('Focus on fixing issues. All component screenshots, scenarios, and tests must be clean before proceeding.'));
969
+ stopGate(10);
970
+ }
971
+ // ─── Step 11: Journal ─────────────────────────────────────────────────
972
+ function printStep11(root, feature) {
973
+ const port = getServerPort();
974
+ const prevState = readState(root);
975
+ const isResuming = prevState?.step === 11;
976
+ const now = new Date().toISOString();
977
+ writeState(root, {
978
+ feature,
979
+ step: 11,
980
+ label: STEP_LABELS[11],
981
+ startedAt: isResuming ? prevState.startedAt : now,
982
+ featureStartedAt: prevState?.featureStartedAt || now,
983
+ });
984
+ logEvent(root, 'step', { step: 11, label: 'Journal', feature });
985
+ stepHeader(11, 'Journal', feature);
986
+ if (isResuming) {
987
+ printResumptionHeader(11);
988
+ }
989
+ console.log('Create or update the journal entry for this feature.');
990
+ console.log();
991
+ console.log(chalk.bold('Checklist:'));
992
+ checkbox('Write a concise description of what was built (2-3 sentences)');
993
+ checkbox(`First time at step 11 — create journal entry with ALL session screenshots:`);
994
+ console.log(chalk.dim(` curl -s -X POST http://localhost:${port}/api/editor-journal-entry \\`));
995
+ console.log(chalk.dim(` -H 'Content-Type: application/json' \\`));
996
+ console.log(chalk.dim(` -d '{"title":"...","type":"feature","description":"...","includeSessionScenarios":true}'`));
997
+ console.log(chalk.dim(' includeSessionScenarios auto-discovers component + app + user persona screenshots'));
998
+ checkbox(`Returning after changes — update the existing journal entry:`);
999
+ console.log(chalk.dim(` curl -s -X PATCH http://localhost:${port}/api/editor-journal-update \\`));
1000
+ console.log(chalk.dim(` -H 'Content-Type: application/json' \\`));
1001
+ console.log(chalk.dim(` -d '{"time":"<journal entry time>","description":"<updated>","includeSessionScenarios":true}'`));
1002
+ console.log();
1003
+ console.log(chalk.dim('Focus on creating or updating the journal entry. Summary and review happen in step 12.'));
1004
+ stopGate(11);
1005
+ }
1006
+ // ─── Step 12: Review ──────────────────────────────────────────────────
1007
+ function printStep12(root, feature) {
1008
+ const port = getServerPort();
1009
+ const prevState = readState(root);
1010
+ const isResuming = prevState?.step === 12;
1011
+ const now = new Date().toISOString();
1012
+ writeState(root, {
1013
+ feature,
1014
+ step: 12,
1015
+ label: STEP_LABELS[12],
1016
+ startedAt: isResuming ? prevState.startedAt : now,
1017
+ featureStartedAt: prevState?.featureStartedAt || now,
1018
+ });
1019
+ logEvent(root, 'step', { step: 12, label: 'Review', feature });
1020
+ stepHeader(12, 'Review', feature);
1021
+ if (isResuming) {
1022
+ printResumptionHeader(12);
1023
+ }
1024
+ console.log('Verify everything, then present the scenario table to the user.');
1025
+ console.log();
1026
+ console.log(chalk.bold('Phase 1 — Verify (do all of this silently):'));
1027
+ checkbox(`Refresh the preview: \`curl -s -X POST http://localhost:${port}/api/dev-mode-preview\``);
1028
+ checkbox('Verify each component has screenshots in the App tab (grouped under Components)');
1029
+ checkbox('If any are missing, re-register them using `codeyam editor register`');
1030
+ checkbox(`Check for client errors: \`curl -s http://localhost:${port}/api/editor-client-errors\``);
1031
+ checkbox('If `hasErrors` is true, fix them and re-capture affected scenarios');
1032
+ checkbox('Run `codeyam editor audit` to verify completeness of scenarios and tests');
1033
+ checkbox('Do not proceed until all checks pass');
1034
+ console.log();
1035
+ console.log(chalk.bold('Phase 2 — Present to the user:'));
1036
+ checkbox('Write a 1-2 sentence summary of what was built');
1037
+ checkbox('Report test count and audit status (one line)');
1038
+ checkbox('Switch the active scenario to the best demo state for the feature:');
1039
+ console.log(chalk.dim(` curl -s -X POST http://localhost:${port}/api/dev-mode-preview \\`));
1040
+ console.log(chalk.dim(` -H 'Content-Type: application/json' -d '{"scenarioSlug":"...","scenarioId":"..."}'`));
1041
+ checkbox(`Show the results panel: \`curl -s -X POST http://localhost:${port}/api/editor-show-results\``);
1042
+ console.log(chalk.dim(' This opens a visual panel below the terminal showing all scenarios with screenshots.'));
1043
+ console.log(chalk.dim(' The user can click scenarios to switch the live preview.'));
1044
+ console.log();
1045
+ console.log(chalk.bold('Phase 3 — Present a selection menu to the user (use AskUserQuestion):'));
1046
+ console.log(chalk.green(' "Save & commit"') +
1047
+ chalk.dim(' — git commit all changes and record in journal'));
1048
+ console.log(chalk.yellow(' "I\'d like to make some changes"') +
1049
+ chalk.dim(' — describe changes, then re-verify'));
1050
+ console.log();
1051
+ console.log(chalk.bold('If the user chooses "Save & commit":'));
1052
+ checkbox(`Git commit using the journal description: \`curl -s -X POST http://localhost:${port}/api/editor-commit -H 'Content-Type: application/json' -d '{"message":"feat: <title>\\n\\n<journal description>"}'\``);
1053
+ console.log(chalk.dim(' The commit message body MUST match the journal description exactly'));
1054
+ checkbox(`Update journal with commit SHA: \`curl -s -X PATCH http://localhost:${port}/api/editor-journal-update -H 'Content-Type: application/json' -d '{"time":"<journal entry time>","commitSha":"<sha>","commitMessage":"feat: <title>"}'\``);
1055
+ console.log(chalk.green(' Then run: ') +
1056
+ chalk.bold('codeyam editor 1') +
1057
+ chalk.green(' to start the next feature'));
1058
+ console.log();
1059
+ console.log(chalk.bold('If the user chooses "Make changes":'));
1060
+ checkbox('Ask what changes the user wants');
1061
+ checkbox('Make the requested changes');
1062
+ console.log(chalk.yellow(' Then run: ') +
1063
+ chalk.bold(`codeyam editor change "${feature}"`) +
1064
+ chalk.yellow(' — this prints a post-change checklist to re-register scenarios,'));
1065
+ console.log(chalk.yellow(' re-run tests, update journal screenshots, and loop back to this review step.'));
1066
+ console.log(chalk.red.bold(' IMPORTANT: You MUST run the change command. Do not skip this or try to re-verify manually.'));
1067
+ console.log();
1068
+ console.log(chalk.dim('Complete all phases in order: summary, screenshot verification, user menu.'));
1069
+ stopGate(12, { confirm: true });
1070
+ }
1071
+ // ─── Command definition ───────────────────────────────────────────────
1072
+ // ─── Analyze-imports subcommand ────────────────────────────────────────
1073
+ /**
1074
+ * `codeyam editor analyze-imports`
1075
+ *
1076
+ * Runs data-structure-only analysis for all glossary entities, then outputs
1077
+ * an import graph and entity data structures as JSON to stdout.
1078
+ */
1079
+ async function handleAnalyzeImports() {
1080
+ const root = getProjectRoot();
1081
+ // Read glossary
1082
+ const glossaryPath = path.join(root, '.codeyam', 'glossary.json');
1083
+ if (!fs.existsSync(glossaryPath)) {
1084
+ console.error(chalk.red('Error: .codeyam/glossary.json not found.'));
1085
+ console.error(chalk.dim(' Run codeyam editor 6 to create the glossary first.'));
1086
+ process.exit(1);
1087
+ }
1088
+ let glossaryEntries;
1089
+ try {
1090
+ glossaryEntries = JSON.parse(fs.readFileSync(glossaryPath, 'utf8'));
1091
+ }
1092
+ catch {
1093
+ console.error(chalk.red('Error: Could not parse .codeyam/glossary.json.'));
1094
+ process.exit(1);
1095
+ }
1096
+ if (!Array.isArray(glossaryEntries) || glossaryEntries.length === 0) {
1097
+ console.error(chalk.red('Error: glossary.json is empty.'));
1098
+ process.exit(1);
1099
+ }
1100
+ const filePaths = glossaryEntries.map((e) => e.filePath);
1101
+ const entityNames = glossaryEntries.map((e) => e.name);
1102
+ const progress = new ProgressReporter();
1103
+ // Run data-structure-only analysis for all entities
1104
+ progress.start('Running import analysis for all glossary entities...');
1105
+ try {
1106
+ await runAnalysisForEntities({
1107
+ projectRoot: root,
1108
+ filePaths,
1109
+ entityNames,
1110
+ progress,
1111
+ onlyDataStructure: true,
1112
+ });
1113
+ }
1114
+ catch (err) {
1115
+ progress.fail('Analysis failed');
1116
+ const msg = err instanceof Error ? err.message : String(err);
1117
+ console.error(chalk.red(`Error: ${msg}`));
1118
+ process.exit(1);
1119
+ }
1120
+ progress.succeed('Analysis complete');
1121
+ // Load entities WITH metadata from database
1122
+ progress.start('Loading entity metadata...');
1123
+ await initializeEnvironment();
1124
+ const entities = await loadEntities({});
1125
+ if (!entities || entities.length === 0) {
1126
+ progress.fail('No entities found in database');
1127
+ process.exit(1);
1128
+ }
1129
+ // Deduplicate to latest versions
1130
+ const latestByKey = new Map();
1131
+ for (const entity of entities) {
1132
+ const key = `${entity.name}::${entity.filePath}`;
1133
+ const existing = latestByKey.get(key);
1134
+ if (!existing ||
1135
+ (entity.createdAt &&
1136
+ existing.createdAt &&
1137
+ entity.createdAt > existing.createdAt)) {
1138
+ latestByKey.set(key, entity);
1139
+ }
1140
+ }
1141
+ const entityNameSet = new Set(entityNames);
1142
+ const latestEntities = [...latestByKey.values()].filter((e) => entityNameSet.has(e.name));
1143
+ // Build import graph from importedExports metadata
1144
+ const imports = {};
1145
+ const entityData = {};
1146
+ // Also load analyses for data structures
1147
+ const entityShas = latestEntities.map((e) => e.sha);
1148
+ const analyses = await loadAnalyses({ entityShas });
1149
+ const analysisMap = new Map();
1150
+ if (analyses) {
1151
+ for (const a of analyses) {
1152
+ if (!analysisMap.has(a.entitySha) ||
1153
+ (a.createdAt &&
1154
+ (!analysisMap.get(a.entitySha).createdAt ||
1155
+ a.createdAt > analysisMap.get(a.entitySha).createdAt))) {
1156
+ analysisMap.set(a.entitySha, a);
1157
+ }
1158
+ }
1159
+ }
1160
+ for (const entity of latestEntities) {
1161
+ const importedExports = entity.metadata?.importedExports || [];
1162
+ const importedNames = importedExports
1163
+ .map((ie) => ie.name)
1164
+ .filter((name) => entityNameSet.has(name));
1165
+ if (importedNames.length > 0) {
1166
+ imports[entity.name] = importedNames;
1167
+ }
1168
+ // Collect entity data with analysis data structures
1169
+ const analysis = analysisMap.get(entity.sha);
1170
+ const analysisMetadata = analysis?.metadata;
1171
+ entityData[entity.name] = {
1172
+ filePath: entity.filePath || '',
1173
+ entityType: entity.entityType || 'visual',
1174
+ dataForMocks: analysisMetadata?.scenariosDataStructure?.dataForMocks,
1175
+ dependencySchemas: analysisMetadata?.mergedDataStructure?.dependencySchemas,
1176
+ };
1177
+ }
1178
+ progress.succeed('Done');
1179
+ // Output combined JSON
1180
+ const output = { imports, entities: entityData };
1181
+ console.log(JSON.stringify(output, null, 2));
1182
+ }
1183
+ // ─── Register subcommand ──────────────────────────────────────────────
1184
+ /**
1185
+ * `codeyam editor register '{"name":"...","componentName":"...",...}'`
1186
+ *
1187
+ * Thin CLI wrapper around POST /api/editor-register-scenario.
1188
+ * Auto-approved via `Bash(codeyam:*)` — no manual approval needed.
1189
+ */
1190
+ async function handleRegister(jsonArg) {
1191
+ if (!jsonArg) {
1192
+ console.error(chalk.red('Error: JSON argument required.'));
1193
+ console.error(chalk.dim(' Usage: codeyam editor register \'{"name":"DrinkCard - Default","componentName":"DrinkCard","url":"/codeyam-isolate/DrinkCard?s=Default"}\''));
1194
+ process.exit(1);
1195
+ }
1196
+ let body;
1197
+ try {
1198
+ body = JSON.parse(jsonArg);
1199
+ }
1200
+ catch {
1201
+ console.error(chalk.red('Error: Invalid JSON.'));
1202
+ console.error(chalk.dim(` Received: ${jsonArg.slice(0, 200)}`));
1203
+ process.exit(1);
1204
+ }
1205
+ const port = getServerPort();
1206
+ const url = `http://localhost:${port}/api/editor-register-scenario`;
1207
+ try {
1208
+ const res = await fetch(url, {
1209
+ method: 'POST',
1210
+ headers: { 'Content-Type': 'application/json' },
1211
+ body: JSON.stringify(body),
1212
+ });
1213
+ const data = await res.json();
1214
+ console.log(JSON.stringify(data, null, 2));
1215
+ if (!res.ok) {
1216
+ process.exit(1);
1217
+ }
1218
+ }
1219
+ catch (error) {
1220
+ const msg = error instanceof Error ? error.message : String(error);
1221
+ console.error(chalk.red(`Error: Could not reach editor server at ${url}`));
1222
+ console.error(chalk.dim(` ${msg}`));
1223
+ console.error(chalk.dim(' Is the editor running? Start it with: codeyam editor'));
1224
+ process.exit(1);
1225
+ }
1226
+ }
1227
+ // ─── Dependents subcommand ────────────────────────────────────────────
1228
+ /**
1229
+ * `codeyam editor dependents <EntityName>`
1230
+ *
1231
+ * Walks the importedBy reverse dependency tree to find all ancestors of a
1232
+ * given entity — i.e., every component or page that transitively imports it.
1233
+ * Used after code changes to determine what needs recapturing.
1234
+ */
1235
+ async function handleDependents(entityName) {
1236
+ if (!entityName) {
1237
+ console.error(chalk.red('Error: Entity name required.'));
1238
+ console.error(chalk.dim(' Usage: codeyam editor dependents DrinkCard'));
1239
+ process.exit(1);
1240
+ }
1241
+ const progress = new ProgressReporter();
1242
+ progress.start('Loading entities from database...');
1243
+ await initializeEnvironment();
1244
+ const allEntities = await loadEntities({});
1245
+ if (!allEntities || allEntities.length === 0) {
1246
+ progress.fail('No entities found in database');
1247
+ console.error(chalk.dim(' Run codeyam editor analyze-imports first to populate entity data.'));
1248
+ process.exit(1);
1249
+ }
1250
+ // Find the target entity by name (case-insensitive match)
1251
+ const targetEntities = allEntities.filter((e) => e.name.toLowerCase() === entityName.toLowerCase());
1252
+ if (targetEntities.length === 0) {
1253
+ progress.fail(`Entity "${entityName}" not found in database`);
1254
+ const names = [...new Set(allEntities.map((e) => e.name))].sort();
1255
+ console.error(chalk.dim(` Available entities: ${names.join(', ')}`));
1256
+ process.exit(1);
1257
+ }
1258
+ progress.succeed('Entities loaded');
1259
+ // Build lookup: entityName -> Set<entityName> of entities that import it.
1260
+ // Each entity's metadata.importedBy is the pre-computed reverse graph:
1261
+ // { [filePath]: { [importerName]: { shas: string[] } } }
1262
+ const importedByName = new Map();
1263
+ for (const entity of allEntities) {
1264
+ const importedBy = entity.metadata?.importedBy;
1265
+ if (!importedBy || typeof importedBy !== 'object')
1266
+ continue;
1267
+ const importers = new Set();
1268
+ for (const filePath of Object.keys(importedBy)) {
1269
+ for (const importerName of Object.keys(importedBy[filePath])) {
1270
+ importers.add(importerName);
1271
+ }
1272
+ }
1273
+ if (importers.size > 0) {
1274
+ importedByName.set(entity.name, importers);
1275
+ }
1276
+ }
1277
+ // BFS walk up the dependency tree from the changed entity
1278
+ const visited = new Set();
1279
+ const result = [];
1280
+ const queue = [
1281
+ { name: entityName, depth: 0 },
1282
+ ];
1283
+ visited.add(entityName.toLowerCase());
1284
+ // Collect entity types for display
1285
+ const entityTypes = new Map();
1286
+ for (const e of allEntities) {
1287
+ if (!entityTypes.has(e.name)) {
1288
+ entityTypes.set(e.name, e.entityType || 'unknown');
1289
+ }
1290
+ }
1291
+ while (queue.length > 0) {
1292
+ const { name, depth } = queue.shift();
1293
+ result.push({
1294
+ name,
1295
+ entityType: entityTypes.get(name) || 'unknown',
1296
+ depth,
1297
+ });
1298
+ // Find all entities that import this one
1299
+ const importers = importedByName.get(name);
1300
+ if (!importers)
1301
+ continue;
1302
+ for (const importerName of importers) {
1303
+ if (visited.has(importerName.toLowerCase()))
1304
+ continue;
1305
+ visited.add(importerName.toLowerCase());
1306
+ queue.push({ name: importerName, depth: depth + 1 });
1307
+ }
1308
+ }
1309
+ // Output
1310
+ if (result.length <= 1) {
1311
+ console.log(chalk.yellow(`No dependents found for "${entityName}".`));
1312
+ console.log(chalk.dim(' This entity is not imported by any other known entities.'));
1313
+ console.log(chalk.dim(' Run codeyam editor analyze-imports to populate import data.'));
1314
+ return;
1315
+ }
1316
+ console.log(chalk.bold(`Dependency tree for ${entityName} (${result.length} entities):`));
1317
+ console.log();
1318
+ for (const entry of result) {
1319
+ const indent = ' '.repeat(entry.depth);
1320
+ const prefix = entry.depth === 0 ? chalk.cyan('●') : chalk.dim('├──');
1321
+ const label = entry.depth === 0
1322
+ ? chalk.cyan(`${entry.name} (changed)`)
1323
+ : chalk.white(entry.name);
1324
+ const type = chalk.dim(`[${entry.entityType}]`);
1325
+ console.log(`${indent}${prefix} ${label} ${type}`);
1326
+ }
1327
+ console.log();
1328
+ console.log(chalk.dim('All listed entities need their scenarios recaptured after changes.'));
1329
+ }
1330
+ // ─── Change subcommand ───────────────────────────────────────────────
1331
+ /**
1332
+ * `codeyam editor change <feature>`
1333
+ *
1334
+ * Prints a condensed post-change checklist that guides Claude through
1335
+ * re-verifying after user-requested modifications. This is the "change
1336
+ * loop" — it replaces the freeform "make changes" path with structured
1337
+ * instructions that always loop back to step 12 review.
1338
+ */
1339
+ function handleChange(feature) {
1340
+ const root = getProjectRoot();
1341
+ if (!feature) {
1342
+ // Try to read feature from state
1343
+ const state = readState(root);
1344
+ if (state?.feature) {
1345
+ feature = state.feature;
1346
+ }
1347
+ else {
1348
+ console.error(chalk.red('Error: Feature name required.'));
1349
+ console.error(chalk.dim(' Usage: codeyam editor change "My Feature"'));
1350
+ process.exit(1);
1351
+ }
1352
+ }
1353
+ const port = getServerPort();
1354
+ console.log();
1355
+ console.log(chalk.bold.cyan('━━━ Change Loop ━━━'));
1356
+ console.log(chalk.dim(`Feature: ${feature}`));
1357
+ console.log();
1358
+ console.log('The user has requested changes. Follow this checklist after making them.');
1359
+ console.log();
1360
+ console.log(chalk.bold('1. Re-register affected component scenarios:'));
1361
+ checkbox('For each component you modified, re-register ALL its scenarios');
1362
+ console.log(chalk.dim(` codeyam editor register '{"name":"ComponentName - ScenarioName","description":"...","componentName":"ComponentName","componentPath":"app/components/ComponentName.tsx"}'`));
1363
+ checkbox('For any NEW components, create isolation routes and register scenarios');
1364
+ console.log();
1365
+ console.log(chalk.bold('2. Re-run affected tests:'));
1366
+ checkbox('Re-run test files for any functions you modified');
1367
+ console.log(chalk.dim(' Example: npx vitest run app/lib/drinks.test.ts'));
1368
+ checkbox('If any test fails, fix the source code and re-run');
1369
+ console.log();
1370
+ console.log(chalk.bold('3. Re-capture app-level scenarios:'));
1371
+ checkbox('If component changes affect app-level pages, re-register affected app scenarios');
1372
+ checkbox(`Use \`codeyam editor dependents ComponentName\` to find what needs recapturing`);
1373
+ console.log();
1374
+ console.log(chalk.bold('4. Verify completeness:'));
1375
+ checkbox(`Refresh the preview: \`curl -s -X POST http://localhost:${port}/api/dev-mode-preview\``);
1376
+ checkbox(`Navigate to key pages to verify changes: \`curl -s -X POST http://localhost:${port}/api/dev-mode-preview -H 'Content-Type: application/json' -d '{"path":"/your-route"}'\``);
1377
+ checkbox('Run `codeyam editor audit` — all checks must pass');
1378
+ checkbox(`Check for client-side errors: \`curl -s http://localhost:${port}/api/editor-client-errors\``);
1379
+ checkbox('Fix any errors, then re-register affected scenarios');
1380
+ console.log();
1381
+ console.log(chalk.bold('5. Update the journal:'));
1382
+ checkbox(`Update journal entry with new screenshots: \`curl -s -X PATCH http://localhost:${port}/api/editor-journal-update -H 'Content-Type: application/json' -d '{"time":"<journal entry time>","description":"<updated>","includeSessionScenarios":true}'\``);
1383
+ console.log(chalk.dim(' includeSessionScenarios refreshes ALL screenshots to reflect the changes'));
1384
+ console.log();
1385
+ console.log(chalk.bold.green('When all checks pass, run: ') +
1386
+ chalk.bold(`codeyam editor 12`));
1387
+ console.log(chalk.dim(' This re-enters the review step to present the updated summary to the user.'));
1388
+ console.log();
1389
+ }
1390
+ // ─── Audit subcommand ────────────────────────────────────────────────
1391
+ /**
1392
+ * `codeyam editor audit`
1393
+ *
1394
+ * Fetches the /api/editor-audit endpoint and prints a checklist showing
1395
+ * which glossary components have registered scenarios and which functions
1396
+ * have test files. Exits with code 1 if anything is missing.
1397
+ */
1398
+ async function handleAudit() {
1399
+ const port = getServerPort();
1400
+ const url = `http://localhost:${port}/api/editor-audit`;
1401
+ let data;
1402
+ try {
1403
+ const res = await fetch(url);
1404
+ if (!res.ok) {
1405
+ console.error(chalk.red(`Error: Audit endpoint returned ${res.status}`));
1406
+ process.exit(1);
1407
+ }
1408
+ data = await res.json();
1409
+ }
1410
+ catch (err) {
1411
+ console.error(chalk.red('Error: Could not reach the CodeYam server. Is it running?'));
1412
+ console.error(chalk.dim(` ${err.message}`));
1413
+ process.exit(1);
1414
+ }
1415
+ const { components, functions, summary } = data;
1416
+ console.log();
1417
+ console.log(chalk.bold.cyan('━━━ Editor Audit ━━━'));
1418
+ console.log();
1419
+ // Components
1420
+ if (components.length > 0) {
1421
+ console.log(chalk.bold('Components (scenarios):'));
1422
+ for (const c of components) {
1423
+ const icon = c.status === 'ok' ? chalk.green('✓') : chalk.red('✗');
1424
+ const count = c.status === 'ok'
1425
+ ? chalk.dim(` (${c.scenarioCount} scenario${c.scenarioCount !== 1 ? 's' : ''})`)
1426
+ : chalk.red(' — no scenarios registered');
1427
+ console.log(` ${icon} ${c.name}${count}`);
1428
+ }
1429
+ console.log();
1430
+ }
1431
+ // Functions
1432
+ if (functions.length > 0) {
1433
+ console.log(chalk.bold('Functions (test files):'));
1434
+ for (const f of functions) {
1435
+ const icon = f.status === 'ok' ? chalk.green('✓') : chalk.red('✗');
1436
+ const detail = f.status === 'ok'
1437
+ ? chalk.dim(` (${f.testFile})`)
1438
+ : f.testFile
1439
+ ? chalk.red(` — test file missing: ${f.testFile}`)
1440
+ : chalk.red(' — no test file specified');
1441
+ console.log(` ${icon} ${f.name}${detail}`);
1442
+ }
1443
+ console.log();
1444
+ }
1445
+ // Summary
1446
+ const allOk = summary.allPassing;
1447
+ if (allOk) {
1448
+ console.log(chalk.green.bold('All checks passed!') +
1449
+ chalk.dim(` (${summary.totalComponents} component${summary.totalComponents !== 1 ? 's' : ''}, ${summary.totalFunctions} function${summary.totalFunctions !== 1 ? 's' : ''})`));
1450
+ }
1451
+ else {
1452
+ const parts = [];
1453
+ if (summary.componentsMissing > 0) {
1454
+ parts.push(`${summary.componentsMissing} component${summary.componentsMissing !== 1 ? 's' : ''} missing scenarios`);
1455
+ }
1456
+ if (summary.functionsMissing > 0) {
1457
+ parts.push(`${summary.functionsMissing} function${summary.functionsMissing !== 1 ? 's' : ''} missing tests`);
1458
+ }
1459
+ console.log(chalk.red.bold('Audit failed: ') + parts.join(', '));
1460
+ }
1461
+ console.log();
1462
+ if (!allOk) {
1463
+ process.exit(1);
1464
+ }
1465
+ }
1466
+ // ─── Scenarios subcommand ─────────────────────────────────────────────
1467
+ async function handleScenarios() {
1468
+ const port = getServerPort();
1469
+ const url = `http://localhost:${port}/api/editor-scenarios`;
1470
+ let data;
1471
+ try {
1472
+ const res = await fetch(url);
1473
+ if (!res.ok) {
1474
+ console.error(chalk.red(`Error: Scenarios endpoint returned ${res.status}`));
1475
+ process.exit(1);
1476
+ }
1477
+ data = await res.json();
1478
+ }
1479
+ catch (err) {
1480
+ console.error(chalk.red('Error: Could not reach the CodeYam server. Is it running?'));
1481
+ console.error(chalk.dim(` ${err.message}`));
1482
+ process.exit(1);
1483
+ }
1484
+ const scenarios = data.scenarios;
1485
+ if (scenarios.length === 0) {
1486
+ console.log();
1487
+ console.log(chalk.yellow('No scenarios found for this feature session.'));
1488
+ console.log();
1489
+ return;
1490
+ }
1491
+ // Group by componentName (null → "Uncategorized")
1492
+ const groups = new Map();
1493
+ for (const s of scenarios) {
1494
+ const key = s.componentName || 'Uncategorized';
1495
+ if (!groups.has(key))
1496
+ groups.set(key, []);
1497
+ groups.get(key).push(s);
1498
+ }
1499
+ // Strip component prefix from names (e.g. "DrinkCard - Default" → "Default")
1500
+ function stripPrefix(name, componentName) {
1501
+ if (!componentName)
1502
+ return name;
1503
+ const prefix = `${componentName} - `;
1504
+ return name.startsWith(prefix) ? name.slice(prefix.length) : name;
1505
+ }
1506
+ // Calculate column widths
1507
+ let maxCompLen = 'Component'.length;
1508
+ let maxScenLen = 'Scenario'.length;
1509
+ for (const [comp, items] of groups) {
1510
+ maxCompLen = Math.max(maxCompLen, comp.length);
1511
+ for (const s of items) {
1512
+ const display = stripPrefix(s.name, s.componentName);
1513
+ maxScenLen = Math.max(maxScenLen, display.length);
1514
+ }
1515
+ }
1516
+ const pad = (str, len) => str + ' '.repeat(Math.max(0, len - str.length));
1517
+ // Build OSC 8 hyperlink (display length = visible text only)
1518
+ const osc8 = (url, text) => `\x1b]8;;${url}\x07${text}\x1b]8;;\x07`;
1519
+ // Print table
1520
+ console.log();
1521
+ console.log(chalk.bold.cyan('━━━ Scenario Table ━━━'));
1522
+ console.log();
1523
+ const divComp = '─'.repeat(maxCompLen + 2);
1524
+ const divScen = '─'.repeat(maxScenLen + 2);
1525
+ // Header
1526
+ console.log(`┌${divComp}┬${divScen}┐`);
1527
+ console.log(`│ ${chalk.bold(pad('Component', maxCompLen))} │ ${chalk.bold(pad('Scenario', maxScenLen))} │`);
1528
+ console.log(`├${divComp}┼${divScen}┤`);
1529
+ // Rows
1530
+ let groupIndex = 0;
1531
+ for (const [comp, items] of groups) {
1532
+ if (groupIndex > 0) {
1533
+ console.log(`├${divComp}┼${divScen}┤`);
1534
+ }
1535
+ for (let i = 0; i < items.length; i++) {
1536
+ const s = items[i];
1537
+ const compCell = i === 0 ? chalk.bold(pad(comp, maxCompLen)) : pad('', maxCompLen);
1538
+ const display = stripPrefix(s.name, s.componentName);
1539
+ const linked = osc8(s.link, display);
1540
+ // linked has invisible escape chars; pad based on display length
1541
+ const scenPad = ' '.repeat(Math.max(0, maxScenLen - display.length));
1542
+ console.log(`│ ${compCell} │ ${linked}${scenPad} │`);
1543
+ }
1544
+ groupIndex++;
1545
+ }
1546
+ // Footer
1547
+ console.log(`└${divComp}┴${divScen}┘`);
1548
+ console.log();
1549
+ const total = scenarios.length;
1550
+ const groupCount = groups.size;
1551
+ console.log(chalk.dim(`${total} scenario${total !== 1 ? 's' : ''} across ${groupCount} component${groupCount !== 1 ? 's' : ''}`));
1552
+ console.log();
1553
+ }
1554
+ // ─── Debug subcommand ────────────────────────────────────────────────
1555
+ function handleEditorDebug(args) {
1556
+ const root = getProjectRoot();
1557
+ const feature = args.feature || 'Sample Feature';
1558
+ const includeContext = args.includeContext !== false;
1559
+ let targets;
1560
+ try {
1561
+ targets = parseDebugTargets(args.target);
1562
+ }
1563
+ catch (err) {
1564
+ const msg = err instanceof Error ? err.message : String(err);
1565
+ console.error(chalk.red(`Error: ${msg}`));
1566
+ process.exit(1);
1567
+ }
1568
+ const includeResume = typeof args.resume === 'boolean' ? args.resume : true;
1569
+ const includeNormal = typeof args.resume === 'boolean' ? !args.resume : true;
1570
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
1571
+ const outputDir = args.output
1572
+ ? path.resolve(args.output)
1573
+ : path.join(root, '.codeyam', 'logs', 'editor-debug', timestamp);
1574
+ fs.mkdirSync(outputDir, { recursive: true });
1575
+ const contextEntries = includeContext
1576
+ ? writeContextSnapshot(root, outputDir)
1577
+ : [];
1578
+ const scenarios = [];
1579
+ const wants = (id) => (targets ? targets.has(id) : true);
1580
+ if (wants('setup')) {
1581
+ scenarios.push({
1582
+ id: 'setup',
1583
+ title: 'Setup (no project)',
1584
+ render: () => withTempRoot(false, (tempRoot) => captureOutput(() => printSetup(tempRoot))),
1585
+ });
1586
+ }
1587
+ if (wants('overview')) {
1588
+ scenarios.push({
1589
+ id: 'overview',
1590
+ title: 'Cycle overview (project, no state)',
1591
+ render: () => withTempRoot(true, (tempRoot) => captureOutput(() => printCycleOverview(tempRoot, null))),
1592
+ });
1593
+ }
1594
+ if (wants('overview-with-state')) {
1595
+ scenarios.push({
1596
+ id: 'overview-with-state',
1597
+ title: 'Cycle overview (project, with state)',
1598
+ render: () => withTempRoot(true, (tempRoot) => captureOutput(() => printCycleOverview(tempRoot, makeState(4, feature)))),
1599
+ });
1600
+ }
1601
+ const stepFns = {
1602
+ 1: (r, f) => printStep1(r, f),
1603
+ 2: printStep2,
1604
+ 3: printStep3,
1605
+ 4: printStep4,
1606
+ 5: printStep5,
1607
+ 6: printStep6,
1608
+ 7: printStep7,
1609
+ 8: printStep8,
1610
+ 9: printStep9,
1611
+ 10: printStep10,
1612
+ 11: printStep11,
1613
+ 12: printStep12,
1614
+ };
1615
+ for (let step = 1; step <= 12; step++) {
1616
+ const stepId = `step-${step}`;
1617
+ if (!wants(stepId))
1618
+ continue;
1619
+ if (includeNormal) {
1620
+ scenarios.push({
1621
+ id: stepId,
1622
+ title: `Step ${step} (${STEP_LABELS[step]})`,
1623
+ render: () => withTempRoot(true, (tempRoot) => captureOutput(() => stepFns[step](tempRoot, feature))),
1624
+ });
1625
+ if (step === 1 && !args.feature) {
1626
+ scenarios.push({
1627
+ id: 'step-1-no-feature',
1628
+ title: 'Step 1 (Plan) — no feature provided',
1629
+ render: () => withTempRoot(true, (tempRoot) => captureOutput(() => printStep1(tempRoot, undefined))),
1630
+ });
1631
+ }
1632
+ if (step === 2) {
1633
+ scenarios.push({
1634
+ id: 'step-2-scaffold',
1635
+ title: 'Step 2 (Prototype) — scaffold flow (no project)',
1636
+ render: () => withTempRoot(false, (tempRoot) => captureOutput(() => printStep2(tempRoot, feature))),
1637
+ });
1638
+ }
1639
+ }
1640
+ if (includeResume) {
1641
+ scenarios.push({
1642
+ id: `${stepId}-resume`,
1643
+ title: `Step ${step} (${STEP_LABELS[step]}) — resuming`,
1644
+ render: () => withTempRoot(true, (tempRoot) => {
1645
+ writeState(tempRoot, makeState(step, feature));
1646
+ return captureOutput(() => stepFns[step](tempRoot, feature));
1647
+ }),
1648
+ });
1649
+ }
1650
+ }
1651
+ const indexLines = [
1652
+ '# CodeYam Editor Debug Bundle',
1653
+ '',
1654
+ `Generated: ${new Date().toISOString()}`,
1655
+ `Feature: "${feature}"`,
1656
+ `Resume variants: ${includeResume ? 'included' : 'skipped'}`,
1657
+ 'Note: Output files preserve ANSI color codes (as printed to the terminal).',
1658
+ '',
1659
+ ];
1660
+ if (includeContext) {
1661
+ indexLines.push('## Context snapshot');
1662
+ if (contextEntries.length === 0) {
1663
+ indexLines.push('- (none)');
1664
+ }
1665
+ else {
1666
+ for (const entry of contextEntries) {
1667
+ const source = entry.source ? ` ← ${entry.source}` : '';
1668
+ indexLines.push(`- ${entry.label}: ${entry.file} (${entry.status})${source}`);
1669
+ }
1670
+ }
1671
+ indexLines.push('');
1672
+ }
1673
+ indexLines.push('## Scenarios');
1674
+ for (const scenario of scenarios) {
1675
+ const fileName = `${scenario.id}.txt`;
1676
+ const output = scenario.render();
1677
+ fs.writeFileSync(path.join(outputDir, fileName), output, 'utf8');
1678
+ indexLines.push(`- ${scenario.title}: ${fileName}`);
1679
+ }
1680
+ fs.writeFileSync(path.join(outputDir, 'index.md'), indexLines.join('\n'), 'utf8');
1681
+ console.log();
1682
+ console.log(chalk.bold.cyan('━━━ Editor Debug Bundle ━━━'));
1683
+ console.log();
1684
+ console.log(chalk.green('Wrote debug bundle to: ') + chalk.bold(outputDir));
1685
+ console.log(chalk.dim(' Open index.md for the full list of scenario outputs.'));
1686
+ console.log();
1687
+ }
1688
+ // ─── Command definition ───────────────────────────────────────────────
1689
+ const editorCommand = {
1690
+ command: 'editor [step] [json]',
1691
+ describe: 'Editor mode guided workflow',
1692
+ builder: (yargs) => {
1693
+ const stepDescription = IS_INTERNAL_BUILD
1694
+ ? 'Step number (1-12) or subcommand (register, analyze-imports, dependents, audit, scenarios, change, debug)'
1695
+ : 'Step number (1-12) or subcommand (register, analyze-imports, dependents, audit, scenarios, change)';
1696
+ let builder = yargs
1697
+ .positional('step', {
1698
+ type: 'string',
1699
+ describe: stepDescription,
1700
+ })
1701
+ .positional('json', {
1702
+ type: 'string',
1703
+ describe: 'JSON argument for register subcommand',
1704
+ })
1705
+ .option('feature', {
1706
+ type: 'string',
1707
+ describe: 'Feature name (required for step 2)',
1708
+ });
1709
+ if (IS_INTERNAL_BUILD) {
1710
+ builder = builder
1711
+ .option('target', {
1712
+ type: 'string',
1713
+ describe: 'Debug target (setup, overview, overview-with-state, step-1..step-12, or comma-separated list)',
1714
+ })
1715
+ .option('resume', {
1716
+ type: 'boolean',
1717
+ describe: 'Debug: only render resume variants (use --no-resume for only normal)',
1718
+ })
1719
+ .option('include-context', {
1720
+ type: 'boolean',
1721
+ default: true,
1722
+ describe: 'Debug: include CLAUDE.md, skill, and editor-mode-context snapshots',
1723
+ })
1724
+ .option('output', {
1725
+ type: 'string',
1726
+ describe: 'Debug: output directory for the bundle',
1727
+ });
1728
+ }
1729
+ return builder;
1730
+ },
1731
+ handler: async (argv) => {
1732
+ const root = getProjectRoot();
1733
+ // Subcommand: codeyam editor register '{"name":"..."}'
1734
+ if (argv.step === 'register') {
1735
+ await handleRegister(argv.json || '');
1736
+ return;
1737
+ }
1738
+ // Subcommand: codeyam editor analyze-imports
1739
+ if (argv.step === 'analyze-imports') {
1740
+ await handleAnalyzeImports();
1741
+ return;
1742
+ }
1743
+ // Subcommand: codeyam editor dependents <EntityName>
1744
+ if (argv.step === 'dependents') {
1745
+ await handleDependents(argv.json || '');
1746
+ return;
1747
+ }
1748
+ // Subcommand: codeyam editor audit
1749
+ if (argv.step === 'audit') {
1750
+ await handleAudit();
1751
+ return;
1752
+ }
1753
+ // Subcommand: codeyam editor scenarios
1754
+ if (argv.step === 'scenarios') {
1755
+ await handleScenarios();
1756
+ return;
1757
+ }
1758
+ // Subcommand: codeyam editor change <feature>
1759
+ if (argv.step === 'change') {
1760
+ handleChange(argv.json || '');
1761
+ return;
1762
+ }
1763
+ // Subcommand: codeyam editor debug [--target ...]
1764
+ if (argv.step === 'debug') {
1765
+ if (!IS_INTERNAL_BUILD) {
1766
+ console.error(chalk.red('Error: "codeyam editor debug" is internal-only.'));
1767
+ process.exit(1);
1768
+ }
1769
+ await handleEditorDebug(argv);
1770
+ return;
1771
+ }
1772
+ const step = argv.step ? parseInt(argv.step, 10) : undefined;
1773
+ if (step != null && (isNaN(step) || step < 1 || step > 12)) {
1774
+ console.error(chalk.red(`Error: Invalid step "${argv.step}". Must be 1-12.`));
1775
+ process.exit(1);
1776
+ }
1777
+ if (step == null) {
1778
+ // No step specified: setup or overview
1779
+ if (!hasProject(root)) {
1780
+ printSetup(root);
1781
+ }
1782
+ else {
1783
+ const state = readState(root);
1784
+ printCycleOverview(root, state);
1785
+ }
1786
+ return;
1787
+ }
1788
+ const state = readState(root);
1789
+ switch (step) {
1790
+ case 1: {
1791
+ const feature = argv.feature || undefined;
1792
+ printStep1(root, feature);
1793
+ break;
1794
+ }
1795
+ case 2: {
1796
+ const feature = argv.feature || state?.feature;
1797
+ if (!feature) {
1798
+ console.error(chalk.red('Error: --feature "Feature Name" is required for step 2.'));
1799
+ console.error(chalk.dim(' Usage: codeyam editor 2 --feature "Drink Rating System"'));
1800
+ process.exit(1);
1801
+ }
1802
+ printStep2(root, feature);
1803
+ break;
1804
+ }
1805
+ case 3:
1806
+ case 4:
1807
+ case 5:
1808
+ case 6:
1809
+ case 7:
1810
+ case 8:
1811
+ case 9:
1812
+ case 10:
1813
+ case 11:
1814
+ case 12: {
1815
+ const feature = argv.feature || state?.feature;
1816
+ if (!feature) {
1817
+ console.error(chalk.red('Error: No feature in progress. Run codeyam editor 1 first.'));
1818
+ process.exit(1);
1819
+ }
1820
+ const stepFns = {
1821
+ 3: printStep3,
1822
+ 4: printStep4,
1823
+ 5: printStep5,
1824
+ 6: printStep6,
1825
+ 7: printStep7,
1826
+ 8: printStep8,
1827
+ 9: printStep9,
1828
+ 10: printStep10,
1829
+ 11: printStep11,
1830
+ 12: printStep12,
1831
+ };
1832
+ stepFns[step](root, feature);
1833
+ break;
1834
+ }
1835
+ }
1836
+ },
1837
+ };
1838
+ export default editorCommand;
1839
+ //# sourceMappingURL=editor.js.map