@codeyam/codeyam-cli 0.1.0-staging.62d4615 → 0.1.0-staging.73a4bf4

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 (285) 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 +1 -1
  4. package/analyzer-template/packages/ai/index.ts +1 -0
  5. package/analyzer-template/packages/ai/src/lib/analyzeScope.ts +14 -0
  6. package/analyzer-template/packages/ai/src/lib/astScopes/processExpression.ts +101 -0
  7. package/analyzer-template/packages/ai/src/lib/astScopes/sharedPatterns.ts +28 -0
  8. package/analyzer-template/packages/ai/src/lib/astScopes/types.ts +6 -0
  9. package/analyzer-template/packages/ai/src/lib/dataStructure/ScopeDataStructure.ts +176 -8
  10. package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/convertDotNotation.ts +70 -13
  11. package/analyzer-template/packages/ai/src/lib/dataStructureChunking.ts +33 -15
  12. package/analyzer-template/packages/ai/src/lib/generateEntityScenarioData.ts +32 -5
  13. package/analyzer-template/packages/ai/src/lib/generateExecutionFlows.ts +38 -2
  14. package/analyzer-template/packages/ai/src/lib/generateExecutionFlowsFromConditionals.ts +359 -142
  15. package/analyzer-template/packages/ai/src/lib/mergeJsonTypeDefinitions.ts +5 -0
  16. package/analyzer-template/packages/ai/src/lib/promptGenerators/collapseNullableObjects.ts +118 -0
  17. package/analyzer-template/packages/ai/src/lib/promptGenerators/generateEntityScenarioDataGenerator.ts +24 -4
  18. package/analyzer-template/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.ts +18 -0
  19. package/analyzer-template/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.ts +50 -25
  20. package/analyzer-template/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.ts +153 -76
  21. package/analyzer-template/packages/database/src/lib/analysisBranchToDb.ts +1 -1
  22. package/analyzer-template/packages/database/src/lib/analysisToDb.ts +1 -1
  23. package/analyzer-template/packages/database/src/lib/branchToDb.ts +1 -1
  24. package/analyzer-template/packages/database/src/lib/commitBranchToDb.ts +1 -1
  25. package/analyzer-template/packages/database/src/lib/commitToDb.ts +1 -1
  26. package/analyzer-template/packages/database/src/lib/fileToDb.ts +1 -1
  27. package/analyzer-template/packages/database/src/lib/kysely/db.ts +6 -0
  28. package/analyzer-template/packages/database/src/lib/kysely/tables/debugReportsTable.ts +1 -1
  29. package/analyzer-template/packages/database/src/lib/kysely/tables/labsRequestsTable.ts +52 -0
  30. package/analyzer-template/packages/database/src/lib/projectToDb.ts +1 -1
  31. package/analyzer-template/packages/database/src/lib/saveFiles.ts +1 -1
  32. package/analyzer-template/packages/database/src/lib/scenarioToDb.ts +1 -1
  33. package/analyzer-template/packages/database/src/lib/userScenarioToDb.ts +1 -1
  34. package/analyzer-template/packages/github/dist/database/src/lib/analysisBranchToDb.js +1 -1
  35. package/analyzer-template/packages/github/dist/database/src/lib/analysisBranchToDb.js.map +1 -1
  36. package/analyzer-template/packages/github/dist/database/src/lib/analysisToDb.js +1 -1
  37. package/analyzer-template/packages/github/dist/database/src/lib/analysisToDb.js.map +1 -1
  38. package/analyzer-template/packages/github/dist/database/src/lib/branchToDb.js +1 -1
  39. package/analyzer-template/packages/github/dist/database/src/lib/branchToDb.js.map +1 -1
  40. package/analyzer-template/packages/github/dist/database/src/lib/commitBranchToDb.js +1 -1
  41. package/analyzer-template/packages/github/dist/database/src/lib/commitBranchToDb.js.map +1 -1
  42. package/analyzer-template/packages/github/dist/database/src/lib/commitToDb.js +1 -1
  43. package/analyzer-template/packages/github/dist/database/src/lib/commitToDb.js.map +1 -1
  44. package/analyzer-template/packages/github/dist/database/src/lib/fileToDb.js +1 -1
  45. package/analyzer-template/packages/github/dist/database/src/lib/fileToDb.js.map +1 -1
  46. package/analyzer-template/packages/github/dist/database/src/lib/kysely/db.d.ts +2 -0
  47. package/analyzer-template/packages/github/dist/database/src/lib/kysely/db.d.ts.map +1 -1
  48. package/analyzer-template/packages/github/dist/database/src/lib/kysely/db.js +3 -0
  49. package/analyzer-template/packages/github/dist/database/src/lib/kysely/db.js.map +1 -1
  50. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/debugReportsTable.d.ts +1 -1
  51. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/labsRequestsTable.d.ts +23 -0
  52. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/labsRequestsTable.d.ts.map +1 -0
  53. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/labsRequestsTable.js +35 -0
  54. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/labsRequestsTable.js.map +1 -0
  55. package/analyzer-template/packages/github/dist/database/src/lib/projectToDb.js +1 -1
  56. package/analyzer-template/packages/github/dist/database/src/lib/projectToDb.js.map +1 -1
  57. package/analyzer-template/packages/github/dist/database/src/lib/saveFiles.js +1 -1
  58. package/analyzer-template/packages/github/dist/database/src/lib/saveFiles.js.map +1 -1
  59. package/analyzer-template/packages/github/dist/database/src/lib/scenarioToDb.js +1 -1
  60. package/analyzer-template/packages/github/dist/database/src/lib/scenarioToDb.js.map +1 -1
  61. package/analyzer-template/packages/github/dist/types/src/types/ProjectMetadata.d.ts +4 -0
  62. package/analyzer-template/packages/github/dist/types/src/types/ProjectMetadata.d.ts.map +1 -1
  63. package/analyzer-template/packages/types/src/types/ProjectMetadata.ts +7 -1
  64. package/analyzer-template/packages/utils/dist/types/src/types/ProjectMetadata.d.ts +4 -0
  65. package/analyzer-template/packages/utils/dist/types/src/types/ProjectMetadata.d.ts.map +1 -1
  66. package/analyzer-template/packages/utils/dist/utils/src/lib/fs/rsyncCopy.d.ts.map +1 -1
  67. package/analyzer-template/packages/utils/dist/utils/src/lib/fs/rsyncCopy.js +93 -2
  68. package/analyzer-template/packages/utils/dist/utils/src/lib/fs/rsyncCopy.js.map +1 -1
  69. package/analyzer-template/packages/utils/src/lib/fs/rsyncCopy.ts +108 -2
  70. package/analyzer-template/project/constructMockCode.ts +2 -2
  71. package/analyzer-template/project/writeMockDataTsx.ts +14 -6
  72. package/background/src/lib/local/createLocalAnalyzer.js +1 -1
  73. package/background/src/lib/local/createLocalAnalyzer.js.map +1 -1
  74. package/background/src/lib/virtualized/project/constructMockCode.js +2 -2
  75. package/background/src/lib/virtualized/project/constructMockCode.js.map +1 -1
  76. package/background/src/lib/virtualized/project/writeMockDataTsx.js +13 -6
  77. package/background/src/lib/virtualized/project/writeMockDataTsx.js.map +1 -1
  78. package/codeyam-cli/scripts/apply-setup.js +1 -1
  79. package/codeyam-cli/src/cli.js +2 -0
  80. package/codeyam-cli/src/cli.js.map +1 -1
  81. package/codeyam-cli/src/codeyam-cli.js +18 -2
  82. package/codeyam-cli/src/codeyam-cli.js.map +1 -1
  83. package/codeyam-cli/src/commands/analyze.js +4 -2
  84. package/codeyam-cli/src/commands/analyze.js.map +1 -1
  85. package/codeyam-cli/src/commands/baseline.js +2 -0
  86. package/codeyam-cli/src/commands/baseline.js.map +1 -1
  87. package/codeyam-cli/src/commands/debug.js +2 -0
  88. package/codeyam-cli/src/commands/debug.js.map +1 -1
  89. package/codeyam-cli/src/commands/default.js +31 -20
  90. package/codeyam-cli/src/commands/default.js.map +1 -1
  91. package/codeyam-cli/src/commands/detect-universal-mocks.js +2 -0
  92. package/codeyam-cli/src/commands/detect-universal-mocks.js.map +1 -1
  93. package/codeyam-cli/src/commands/init.js +49 -257
  94. package/codeyam-cli/src/commands/init.js.map +1 -1
  95. package/codeyam-cli/src/commands/memory.js +9 -9
  96. package/codeyam-cli/src/commands/memory.js.map +1 -1
  97. package/codeyam-cli/src/commands/recapture.js +2 -0
  98. package/codeyam-cli/src/commands/recapture.js.map +1 -1
  99. package/codeyam-cli/src/commands/setup-sandbox.js +2 -0
  100. package/codeyam-cli/src/commands/setup-sandbox.js.map +1 -1
  101. package/codeyam-cli/src/commands/setup-simulations.js +284 -0
  102. package/codeyam-cli/src/commands/setup-simulations.js.map +1 -0
  103. package/codeyam-cli/src/commands/test-startup.js +2 -0
  104. package/codeyam-cli/src/commands/test-startup.js.map +1 -1
  105. package/codeyam-cli/src/commands/verify.js +14 -2
  106. package/codeyam-cli/src/commands/verify.js.map +1 -1
  107. package/codeyam-cli/src/utils/__tests__/setupClaudeCodeSettings.test.js +128 -86
  108. package/codeyam-cli/src/utils/__tests__/setupClaudeCodeSettings.test.js.map +1 -1
  109. package/codeyam-cli/src/utils/analyzer.js +7 -0
  110. package/codeyam-cli/src/utils/analyzer.js.map +1 -1
  111. package/codeyam-cli/src/utils/backgroundServer.js +107 -23
  112. package/codeyam-cli/src/utils/backgroundServer.js.map +1 -1
  113. package/codeyam-cli/src/utils/generateReport.js +2 -2
  114. package/codeyam-cli/src/utils/install-skills.js +43 -63
  115. package/codeyam-cli/src/utils/install-skills.js.map +1 -1
  116. package/codeyam-cli/src/utils/labsAutoCheck.js +19 -0
  117. package/codeyam-cli/src/utils/labsAutoCheck.js.map +1 -0
  118. package/codeyam-cli/src/utils/progress.js +7 -0
  119. package/codeyam-cli/src/utils/progress.js.map +1 -1
  120. package/codeyam-cli/src/utils/requireSimulations.js +10 -0
  121. package/codeyam-cli/src/utils/requireSimulations.js.map +1 -0
  122. package/codeyam-cli/src/utils/ruleReflection/__tests__/contextBuilder.test.js +106 -4
  123. package/codeyam-cli/src/utils/ruleReflection/__tests__/contextBuilder.test.js.map +1 -1
  124. package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/ruleReflectionE2E.test.js +95 -2
  125. package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/ruleReflectionE2E.test.js.map +1 -1
  126. package/codeyam-cli/src/utils/ruleReflection/__tests__/promptBuilder.test.js +37 -5
  127. package/codeyam-cli/src/utils/ruleReflection/__tests__/promptBuilder.test.js.map +1 -1
  128. package/codeyam-cli/src/utils/ruleReflection/contextBuilder.js +23 -3
  129. package/codeyam-cli/src/utils/ruleReflection/contextBuilder.js.map +1 -1
  130. package/codeyam-cli/src/utils/ruleReflection/index.js +2 -2
  131. package/codeyam-cli/src/utils/ruleReflection/index.js.map +1 -1
  132. package/codeyam-cli/src/utils/ruleReflection/promptBuilder.js +11 -0
  133. package/codeyam-cli/src/utils/ruleReflection/promptBuilder.js.map +1 -1
  134. package/codeyam-cli/src/utils/rules/__tests__/ruleState.test.js +23 -23
  135. package/codeyam-cli/src/utils/rules/__tests__/ruleState.test.js.map +1 -1
  136. package/codeyam-cli/src/utils/rules/parser.js +5 -0
  137. package/codeyam-cli/src/utils/rules/parser.js.map +1 -1
  138. package/codeyam-cli/src/utils/rules/ruleState.js +10 -10
  139. package/codeyam-cli/src/utils/rules/ruleState.js.map +1 -1
  140. package/codeyam-cli/src/utils/rules/staleness.js +6 -6
  141. package/codeyam-cli/src/utils/rules/staleness.js.map +1 -1
  142. package/codeyam-cli/src/utils/serverState.js +37 -10
  143. package/codeyam-cli/src/utils/serverState.js.map +1 -1
  144. package/codeyam-cli/src/utils/setupClaudeCodeSettings.js +21 -44
  145. package/codeyam-cli/src/utils/setupClaudeCodeSettings.js.map +1 -1
  146. package/codeyam-cli/src/webserver/app/lib/database.js +14 -3
  147. package/codeyam-cli/src/webserver/app/lib/database.js.map +1 -1
  148. package/codeyam-cli/src/webserver/app/lib/dbNotifier.js.map +1 -1
  149. package/codeyam-cli/src/webserver/backgroundServer.js +50 -0
  150. package/codeyam-cli/src/webserver/backgroundServer.js.map +1 -1
  151. package/codeyam-cli/src/webserver/build/client/assets/CopyButton-D9i_zSlY.js +1 -0
  152. package/codeyam-cli/src/webserver/build/client/assets/{EntityItem-B86KKU7e.js → EntityItem-BLlhOa3C.js} +1 -1
  153. package/codeyam-cli/src/webserver/build/client/assets/{EntityTypeBadge-B5ctlSYt.js → EntityTypeBadge-De5b5pC7.js} +1 -1
  154. package/codeyam-cli/src/webserver/build/client/assets/{EntityTypeIcon-BqY8gDAW.js → EntityTypeIcon-CzdG5I7z.js} +1 -1
  155. package/codeyam-cli/src/webserver/build/client/assets/{InlineSpinner-ClaLpuOo.js → InlineSpinner-Bclf8Hka.js} +1 -1
  156. package/codeyam-cli/src/webserver/build/client/assets/{InteractivePreview-BDhPilK7.js → InteractivePreview-Ce-byqKl.js} +2 -2
  157. package/codeyam-cli/src/webserver/build/client/assets/{LibraryFunctionPreview-VeqEBv9v.js → LibraryFunctionPreview-DEMHrl7v.js} +1 -1
  158. package/codeyam-cli/src/webserver/build/client/assets/{LoadingDots-Bs7Nn1Jr.js → LoadingDots-B1LNGboS.js} +1 -1
  159. package/codeyam-cli/src/webserver/build/client/assets/{LogViewer-Bm3PmcCz.js → LogViewer-B0Ll1DjK.js} +1 -1
  160. package/codeyam-cli/src/webserver/build/client/assets/{ReportIssueModal-C6PKeMYR.js → ReportIssueModal-CVOvmCKb.js} +2 -2
  161. package/codeyam-cli/src/webserver/build/client/assets/{SafeScreenshot-Gq3Ocjo6.js → SafeScreenshot-L0DWHa_L.js} +1 -1
  162. package/codeyam-cli/src/webserver/build/client/assets/{ScenarioViewer-BNLaXBHR.js → ScenarioViewer-D54Mmpwi.js} +2 -2
  163. package/codeyam-cli/src/webserver/build/client/assets/{TruncatedFilePath-CiwXDxLh.js → TruncatedFilePath-C7PFQfXy.js} +1 -1
  164. package/codeyam-cli/src/webserver/build/client/assets/{_index-B3TDXxnk.js → _index-CKTtYlBU.js} +1 -1
  165. package/codeyam-cli/src/webserver/build/client/assets/{activity.(_tab)-DD1r_QU0.js → activity.(_tab)-CdziRIWU.js} +6 -6
  166. package/codeyam-cli/src/webserver/build/client/assets/agent-transcripts-CPXtdaWm.js +17 -0
  167. package/codeyam-cli/src/webserver/build/client/assets/api.labs-unlock-l0sNRNKZ.js +1 -0
  168. package/codeyam-cli/src/webserver/build/client/assets/{book-open-PttOB2SF.js → book-open-Ch8b7GyQ.js} +1 -1
  169. package/codeyam-cli/src/webserver/build/client/assets/{chevron-down-TJp6ofnp.js → chevron-down-vJHJExlT.js} +1 -1
  170. package/codeyam-cli/src/webserver/build/client/assets/{chunk-JZWAC4HX-JE9ZIoBl.js → chunk-JZWAC4HX-BEyX4X6_.js} +7 -7
  171. package/codeyam-cli/src/webserver/build/client/assets/{circle-check-CXhHQYrI.js → circle-check-rwynPZTW.js} +1 -1
  172. package/codeyam-cli/src/webserver/build/client/assets/{copy-6y9ALfGT.js → copy-BBSpeBYf.js} +1 -1
  173. package/codeyam-cli/src/webserver/build/client/assets/{createLucideIcon-Ca9fAY46.js → createLucideIcon-DHVDauuc.js} +1 -1
  174. package/codeyam-cli/src/webserver/build/client/assets/{dev.empty-C5lqplTC.js → dev.empty-B9_ZqelV.js} +1 -1
  175. package/codeyam-cli/src/webserver/build/client/assets/entity._sha._-BOPComvD.js +16 -0
  176. package/codeyam-cli/src/webserver/build/client/assets/{entity._sha.scenarios._scenarioId.fullscreen-CBoafmVs.js → entity._sha.scenarios._scenarioId.fullscreen-Cfw__yQa.js} +1 -1
  177. package/codeyam-cli/src/webserver/build/client/assets/{entity._sha_.create-scenario-DGgZjdFg.js → entity._sha_.create-scenario-BIDUUrI3.js} +1 -1
  178. package/codeyam-cli/src/webserver/build/client/assets/{entity._sha_.edit._scenarioId-38yPijoD.js → entity._sha_.edit._scenarioId-BEqewwtZ.js} +1 -1
  179. package/codeyam-cli/src/webserver/build/client/assets/{entry.client-BSHEfydn.js → entry.client-Dxqz8ygt.js} +1 -1
  180. package/codeyam-cli/src/webserver/build/client/assets/{fileTableUtils-DCPhhSMo.js → fileTableUtils-CYnF5KWN.js} +1 -1
  181. package/codeyam-cli/src/webserver/build/client/assets/{files-Dk8wkAS7.js → files-B_dAq2PQ.js} +1 -1
  182. package/codeyam-cli/src/webserver/build/client/assets/{git-DXnyr8uP.js → git-BHPqH3Ch.js} +1 -1
  183. package/codeyam-cli/src/webserver/build/client/assets/globals-BJGhRykz.css +1 -0
  184. package/codeyam-cli/src/webserver/build/client/assets/{index-CcsFv748.js → index-DgAAopZk.js} +1 -1
  185. package/codeyam-cli/src/webserver/build/client/assets/{index-ChN9-fAY.js → index-viijWaN6.js} +1 -1
  186. package/codeyam-cli/src/webserver/build/client/assets/labs-ChoAe3xq.js +1 -0
  187. package/codeyam-cli/src/webserver/build/client/assets/{loader-circle-CTqLEAGU.js → loader-circle-LGi2eKI5.js} +1 -1
  188. package/codeyam-cli/src/webserver/build/client/assets/manifest-87493a32.js +1 -0
  189. package/codeyam-cli/src/webserver/build/client/assets/memory-D9eA6kTo.js +78 -0
  190. package/codeyam-cli/src/webserver/build/client/assets/{pause-D6vreykR.js → pause-DxJFmMsK.js} +1 -1
  191. package/codeyam-cli/src/webserver/build/client/assets/root-C3r0p_7H.js +62 -0
  192. package/codeyam-cli/src/webserver/build/client/assets/{search-B8VUL8nl.js → search-Cu3QE9E5.js} +1 -1
  193. package/codeyam-cli/src/webserver/build/client/assets/settings-KH9TdArD.js +1 -0
  194. package/codeyam-cli/src/webserver/build/client/assets/{simulations-CPoAg7Zo.js → simulations-D9Fkx0-d.js} +1 -1
  195. package/codeyam-cli/src/webserver/build/client/assets/{terminal-BrCP7uQo.js → terminal-dAhIBEcd.js} +1 -1
  196. package/codeyam-cli/src/webserver/build/client/assets/{triangle-alert-BZz2NjYa.js → triangle-alert-C4CYTEeP.js} +1 -1
  197. package/codeyam-cli/src/webserver/build/client/assets/{useCustomSizes-DNwUduNu.js → useCustomSizes-CLPnITMB.js} +1 -1
  198. package/codeyam-cli/src/webserver/build/client/assets/{useLastLogLine-COky1GVF.js → useLastLogLine-DmGI38Et.js} +1 -1
  199. package/codeyam-cli/src/webserver/build/client/assets/{useReportContext-CpZgwliL.js → useReportContext-BK0S88PB.js} +1 -1
  200. package/codeyam-cli/src/webserver/build/client/assets/{useToast-Bv9JFvUO.js → useToast-CJ-JqR0l.js} +1 -1
  201. package/codeyam-cli/src/webserver/build/server/assets/{index-C0KrUQp-.js → index-CkkmL6r5.js} +1 -1
  202. package/codeyam-cli/src/webserver/build/server/assets/server-build-iBGjHYtO.js +259 -0
  203. package/codeyam-cli/src/webserver/build/server/index.js +1 -1
  204. package/codeyam-cli/src/webserver/build-info.json +5 -5
  205. package/codeyam-cli/templates/{codeyam:debug.md → codeyam-debug.md} +1 -1
  206. package/codeyam-cli/templates/codeyam-diagnose.md +481 -0
  207. package/codeyam-cli/templates/codeyam-memory-hook.sh +14 -14
  208. package/codeyam-cli/templates/{codeyam:memory.md → codeyam-memory.md} +16 -24
  209. package/codeyam-cli/templates/{codeyam:new-rule.md → codeyam-new-rule.md} +1 -1
  210. package/codeyam-cli/templates/{codeyam:setup.md → codeyam-setup.md} +13 -1
  211. package/codeyam-cli/templates/{codeyam:sim.md → codeyam-sim.md} +1 -1
  212. package/codeyam-cli/templates/{codeyam:test.md → codeyam-test.md} +1 -1
  213. package/codeyam-cli/templates/{codeyam:verify.md → codeyam-verify.md} +1 -1
  214. package/codeyam-cli/templates/rule-notification-hook.py +3 -1
  215. package/codeyam-cli/templates/rule-reflection-hook.py +265 -66
  216. package/codeyam-cli/templates/rules-instructions.md +50 -41
  217. package/package.json +9 -9
  218. package/packages/ai/index.js +1 -1
  219. package/packages/ai/index.js.map +1 -1
  220. package/packages/ai/src/lib/analyzeScope.js +14 -0
  221. package/packages/ai/src/lib/analyzeScope.js.map +1 -1
  222. package/packages/ai/src/lib/astScopes/processExpression.js +78 -1
  223. package/packages/ai/src/lib/astScopes/processExpression.js.map +1 -1
  224. package/packages/ai/src/lib/astScopes/sharedPatterns.js +25 -0
  225. package/packages/ai/src/lib/astScopes/sharedPatterns.js.map +1 -1
  226. package/packages/ai/src/lib/dataStructure/ScopeDataStructure.js +128 -7
  227. package/packages/ai/src/lib/dataStructure/ScopeDataStructure.js.map +1 -1
  228. package/packages/ai/src/lib/dataStructure/helpers/convertDotNotation.js +59 -11
  229. package/packages/ai/src/lib/dataStructure/helpers/convertDotNotation.js.map +1 -1
  230. package/packages/ai/src/lib/dataStructureChunking.js +26 -11
  231. package/packages/ai/src/lib/dataStructureChunking.js.map +1 -1
  232. package/packages/ai/src/lib/generateEntityScenarioData.js +22 -3
  233. package/packages/ai/src/lib/generateEntityScenarioData.js.map +1 -1
  234. package/packages/ai/src/lib/generateExecutionFlows.js +16 -2
  235. package/packages/ai/src/lib/generateExecutionFlows.js.map +1 -1
  236. package/packages/ai/src/lib/generateExecutionFlowsFromConditionals.js +242 -81
  237. package/packages/ai/src/lib/generateExecutionFlowsFromConditionals.js.map +1 -1
  238. package/packages/ai/src/lib/mergeJsonTypeDefinitions.js +5 -0
  239. package/packages/ai/src/lib/mergeJsonTypeDefinitions.js.map +1 -1
  240. package/packages/ai/src/lib/promptGenerators/collapseNullableObjects.js +97 -0
  241. package/packages/ai/src/lib/promptGenerators/collapseNullableObjects.js.map +1 -0
  242. package/packages/ai/src/lib/promptGenerators/generateEntityScenarioDataGenerator.js +17 -2
  243. package/packages/ai/src/lib/promptGenerators/generateEntityScenarioDataGenerator.js.map +1 -1
  244. package/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.js +11 -1
  245. package/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.js.map +1 -1
  246. package/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.js +42 -13
  247. package/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.js.map +1 -1
  248. package/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.js +123 -67
  249. package/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.js.map +1 -1
  250. package/packages/database/src/lib/analysisBranchToDb.js +1 -1
  251. package/packages/database/src/lib/analysisBranchToDb.js.map +1 -1
  252. package/packages/database/src/lib/analysisToDb.js +1 -1
  253. package/packages/database/src/lib/analysisToDb.js.map +1 -1
  254. package/packages/database/src/lib/branchToDb.js +1 -1
  255. package/packages/database/src/lib/branchToDb.js.map +1 -1
  256. package/packages/database/src/lib/commitBranchToDb.js +1 -1
  257. package/packages/database/src/lib/commitBranchToDb.js.map +1 -1
  258. package/packages/database/src/lib/commitToDb.js +1 -1
  259. package/packages/database/src/lib/commitToDb.js.map +1 -1
  260. package/packages/database/src/lib/fileToDb.js +1 -1
  261. package/packages/database/src/lib/fileToDb.js.map +1 -1
  262. package/packages/database/src/lib/kysely/db.js +3 -0
  263. package/packages/database/src/lib/kysely/db.js.map +1 -1
  264. package/packages/database/src/lib/kysely/tables/labsRequestsTable.js +35 -0
  265. package/packages/database/src/lib/kysely/tables/labsRequestsTable.js.map +1 -0
  266. package/packages/database/src/lib/projectToDb.js +1 -1
  267. package/packages/database/src/lib/projectToDb.js.map +1 -1
  268. package/packages/database/src/lib/saveFiles.js +1 -1
  269. package/packages/database/src/lib/saveFiles.js.map +1 -1
  270. package/packages/database/src/lib/scenarioToDb.js +1 -1
  271. package/packages/database/src/lib/scenarioToDb.js.map +1 -1
  272. package/packages/utils/src/lib/fs/rsyncCopy.js +93 -2
  273. package/packages/utils/src/lib/fs/rsyncCopy.js.map +1 -1
  274. package/scripts/finalize-analyzer.cjs +8 -76
  275. package/codeyam-cli/src/webserver/build/client/assets/CopyButton-CA3JxPb7.js +0 -1
  276. package/codeyam-cli/src/webserver/build/client/assets/agent-transcripts-DfKzxuoe.js +0 -11
  277. package/codeyam-cli/src/webserver/build/client/assets/entity._sha._-n38keI1k.js +0 -23
  278. package/codeyam-cli/src/webserver/build/client/assets/globals-Bh6jH0cL.css +0 -1
  279. package/codeyam-cli/src/webserver/build/client/assets/labs-BUvfJMNR.js +0 -1
  280. package/codeyam-cli/src/webserver/build/client/assets/manifest-d4e77269.js +0 -1
  281. package/codeyam-cli/src/webserver/build/client/assets/memory-DCHBwHou.js +0 -76
  282. package/codeyam-cli/src/webserver/build/client/assets/root-D6oziHts.js +0 -62
  283. package/codeyam-cli/src/webserver/build/client/assets/settings-B2X7lJgQ.js +0 -1
  284. package/codeyam-cli/src/webserver/build/server/assets/server-build-C2h1v1XD.js +0 -260
  285. package/codeyam-cli/templates/codeyam:diagnose.md +0 -803
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: codeyam:memory
2
+ name: codeyam-memory
3
3
  autoApprove: true
4
4
  description: |
5
5
  Generate and maintain Claude Rules for your codebase based on thorough analysis.
@@ -13,19 +13,14 @@ This skill helps you generate and maintain Claude Rules (`.claude/rules/`) that
13
13
 
14
14
  ## Core Principle: Document Confusion, Not Information
15
15
 
16
- **Good rules** explain things that are NOT obvious from reading the code:
16
+ **Valuable rules** capture knowledge that reading the code alone wouldn't reveal:
17
17
 
18
18
  - Historical context (why code evolved this way)
19
19
  - Hidden relationships (files that must change together)
20
20
  - Gotchas that caused bugs
21
21
  - Non-obvious conventions
22
22
 
23
- **Bad rules** document things Claude can easily ascertain:
24
-
25
- - What functions do (Claude can read the code)
26
- - Type definitions (Claude can see them)
27
- - Directory structure (Claude can explore it)
28
- - Basic patterns (Claude knows common patterns)
23
+ Skip documenting things Claude can determine by reading code: function signatures, type definitions, directory structure, and common patterns.
29
24
 
30
25
  ## When to Use This Skill
31
26
 
@@ -41,7 +36,9 @@ Check if this is the first time running memory.
41
36
 
42
37
  ### 1A. Add Documentation Section to CLAUDE.md
43
38
 
44
- If CLAUDE.md doesn't contain a "When Confused / With Mistakes" section, add close to the top:
39
+ If CLAUDE.md already contains a "Documenting Confusion / Mistakes" section, skip this step entirely.
40
+
41
+ Otherwise, add **only** the section below — do not modify or add any other content to CLAUDE.md. If CLAUDE.md doesn't exist, create it with just a `# Project` heading followed by this section:
45
42
 
46
43
  ```markdown
47
44
  ## Continuous Documentation
@@ -61,6 +58,8 @@ It is very important to document any tribal knowledge, complex architectural dec
61
58
  Please see `.codeyam/rules/instructions.md` for guidance.
62
59
  ```
63
60
 
61
+ **Important:** Do not add project descriptions, architecture summaries, or any other content to CLAUDE.md. Only add the exact section above.
62
+
64
63
  ### 1B. Verify Instructions File
65
64
 
66
65
  Check that `.codeyam/rules/instructions.md` exists (it should be created during `codeyam init`). If missing, copy it from `codeyam-cli/templates/rules-instructions.md`.
@@ -275,7 +274,7 @@ Before generating each rule, verify it passes these tests:
275
274
 
276
275
  **2. Code-derivable check**: Read the files the rule will cover. Could the rule's content be determined by reading those files alone?
277
276
 
278
- - If YES → rule probably not needed (Claude can read the code)
277
+ - If YES → the code is its own documentation prefer keeping rules for non-derivable insights
279
278
  - If NO (historical context, edge cases, non-obvious behavior) → rule is valuable
280
279
 
281
280
  **3. Prevention check**: Would this rule have prevented one of the confusion commits you found?
@@ -301,7 +300,7 @@ This caused a bug where `entity` matched `entityCode` (siblings, not parent-chil
301
300
  - Not code-derivable: Code doesn't explain why boundary checking matters
302
301
  - Prevention: Would prevent future prefix-matching bugs
303
302
 
304
- **❌ Bad rule** (fails tests):
303
+ **Compare with a weaker alternative** (fails the checks):
305
304
 
306
305
  ```markdown
307
306
  ## Running Tests
@@ -309,9 +308,7 @@ This caused a bug where `entity` matched `entityCode` (siblings, not parent-chil
309
308
  Use `pnpm jest` to run tests. Configuration is in `jest.config.ts`.
310
309
  ```
311
310
 
312
- - No confusion evidence (no commits showing people struggled with this)
313
- - Code-derivable: Anyone can see `jest.config.ts` exists
314
- - Doesn't prevent any confusion
311
+ - No confusion evidence, code-derivable, and wouldn't prevent future mistakes
315
312
 
316
313
  ### 5B. Rule File Guidelines
317
314
 
@@ -319,17 +316,13 @@ Use `pnpm jest` to run tests. Configuration is in `jest.config.ts`.
319
316
  - Rule for `src/api/` → `.claude/rules/src/api/architecture.md`
320
317
  - Rule for testing patterns → `.claude/rules/testing-patterns.md`
321
318
 
322
- 2. **Paths must be specific**
323
- - Good: `paths: ['src/api/**/*.ts']`
324
- - Bad: `paths: ['**/*.ts']` (too broad, wastes context)
319
+ 2. **Paths must be specific** — use `paths: ['src/api/**/*.ts']` rather than `'**/*.ts'` (too broad wastes context)
325
320
 
326
321
  3. **Content should explain "why" not just "what"**
327
322
  - Focus on the reasoning, history, or gotcha
328
323
  - Be concise - every word costs context
329
324
 
330
- 4. **Timestamp must be current**
331
- - Use ISO 8601 format: `2026-01-27T15:30:00Z`
332
- - This enables the pre-commit hook enforcement
325
+ 4. **Audit dates live in `.claude/codeyam-rule-state.json`** (managed by `codeyam memory touch`). Keep rule frontmatter limited to `paths`.
333
326
 
334
327
  ### Rule Template
335
328
 
@@ -337,7 +330,6 @@ Use `pnpm jest` to run tests. Configuration is in `jest.config.ts`.
337
330
  ---
338
331
  paths:
339
332
  - 'specific/path/**/*.ts'
340
- timestamp: [CURRENT_ISO_TIMESTAMP]
341
333
  ---
342
334
 
343
335
  ## [Clear, Descriptive Title]
@@ -374,7 +366,7 @@ After generating rules based on your analysis and user answers:
374
366
  5. **Remind the user** to commit the new rules:
375
367
  ```
376
368
  git add .claude/rules/ .codeyam/rules/
377
- git commit -m "Add rules for Claude Code (generated via /codeyam:memory)"
369
+ git commit -m "Add rules for Claude Code (generated via /codeyam-memory)"
378
370
  ```
379
371
 
380
372
  ---
@@ -394,11 +386,11 @@ After generating rules based on your analysis and user answers:
394
386
  The pre-commit hook **blocks commits** when:
395
387
 
396
388
  - Code files matching a rule's `paths` are modified
397
- - The rule's `timestamp` is older than the code changes
389
+ - The rule's `lastAuditedAt` in `.claude/codeyam-rule-state.json` is older than the code changes
398
390
 
399
391
  To proceed:
400
392
 
401
393
  1. Review the flagged rule(s)
402
394
  2. Update content if needed
403
- 3. Update the `timestamp` to current time
395
+ 3. Run `codeyam memory touch` to mark rules as audited in `.claude/codeyam-rule-state.json`
404
396
  4. Stage and commit
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: codeyam:new-rule
2
+ name: codeyam-new-rule
3
3
  autoApprove: true
4
4
  description: |
5
5
  Create a new Claude Rule for documenting codebase patterns.
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: codeyam:setup
2
+ name: codeyam-setup
3
3
  autoApprove: true
4
4
  description: |
5
5
  Use this skill when the user asks to "setup CodeYam" or needs to configure CodeYam for their project.
@@ -52,6 +52,18 @@ codeyam validate-mock .codeyam/universal-mocks/{path-to-your-mock}
52
52
 
53
53
  ## Setup Workflow
54
54
 
55
+ ### Step 0: Ensure Simulation Infrastructure
56
+
57
+ Before configuring the dev server or mocks, ensure the simulation infrastructure is installed.
58
+
59
+ ```bash
60
+ codeyam setup-simulations
61
+ ```
62
+
63
+ This is **idempotent** — if already set up, each step is detected and skipped. On first run it installs analyzer dependencies, Playwright chromium, and creates baseline entities (several minutes). Subsequent runs complete in seconds.
64
+
65
+ If it fails with "No web applications found", the project doesn't support simulations — inform the user and stop.
66
+
55
67
  ### Step 1: Configure Webapp Start Command
56
68
 
57
69
  **ACTION 1:** Read configuration files:
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: codeyam:sim
2
+ name: codeyam-sim
3
3
  autoApprove: true
4
4
  description: |
5
5
  Use this skill to create interactive simulations of components and functions using CodeYam's analysis.
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: codeyam:test
2
+ name: codeyam-test
3
3
  autoApprove: true
4
4
  description: |
5
5
  Use this skill to write comprehensive unit and integration tests using CodeYam's mock generation.
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: codeyam:verify
2
+ name: codeyam-verify
3
3
  autoApprove: true
4
4
  description: |
5
5
  Use this skill after making code changes that impact application functionality.
@@ -7,10 +7,11 @@ in /tmp/claude-rule-markers/ when they create or update rules.
7
7
  This hook checks for those files on each user message, prints them to stdout
8
8
  (which Claude sees as injected context), and deletes them.
9
9
 
10
- Supports three notification files (legacy combined + split agents):
10
+ Supports four notification files (legacy combined + split agents):
11
11
  - rule-notification.md (legacy/backward-compat)
12
12
  - rule-notification-stale.md (stale rules agent)
13
13
  - rule-notification-conversation.md (conversation review agent)
14
+ - rule-notification-interruption.md (interruption review agent)
14
15
  """
15
16
 
16
17
  import os
@@ -21,6 +22,7 @@ NOTIFICATION_FILES = [
21
22
  'rule-notification.md',
22
23
  'rule-notification-stale.md',
23
24
  'rule-notification-conversation.md',
25
+ 'rule-notification-interruption.md',
24
26
  ]
25
27
 
26
28
 
@@ -2,11 +2,13 @@
2
2
  """
3
3
  Rule reflection hook for Claude Code.
4
4
 
5
- Two responsibilities, now split into independent agents:
6
- 1. Check for stale rules (files changed since rule was last reviewed) and prompt review
7
- 2. Review conversation for confusion signals (mistakes, corrections, interruptions)
5
+ Handles two hook events:
6
+ 1. Stop Reviews completed turns for stale rules and conversation confusion signals
7
+ 2. UserPromptSubmit Detects user interruptions (Escape/Ctrl+C) by checking if the
8
+ Stop hook's marker file is stale, then spawns a rule-reflection agent focused on
9
+ the interruption signal
8
10
 
9
- Each fires as a separate `claude -p` invocation so the LLM can focus on one task at a time.
11
+ Each review fires as a separate `claude -p` invocation so the LLM can focus on one task at a time.
10
12
  Stays silent if there's nothing to review.
11
13
 
12
14
  Prompt text lives in templates/prompts/*.txt (single source of truth shared with TypeScript tests).
@@ -16,6 +18,7 @@ import json
16
18
  import os
17
19
  import subprocess
18
20
  import sys
21
+ from datetime import datetime
19
22
  from pathlib import Path
20
23
 
21
24
  MIN_USER_TURNS = 3 # Minimum user turns before checking for confusion
@@ -117,6 +120,33 @@ def read_rule_content(rule_name):
117
120
  return text
118
121
 
119
122
 
123
+ def load_memory_settings():
124
+ """
125
+ Load memory settings from .codeyam/config.json.
126
+ Returns dict with safe defaults when absent or malformed.
127
+ """
128
+ defaults = {
129
+ 'conversationReflection': True,
130
+ 'ruleMaintenance': True,
131
+ 'promptModel': 'haiku',
132
+ }
133
+ try:
134
+ project_dir = os.environ.get('CLAUDE_PROJECT_DIR', os.getcwd())
135
+ config_path = os.path.join(project_dir, '.codeyam', 'config.json')
136
+ with open(config_path, 'r') as f:
137
+ config = json.load(f)
138
+ memory = config.get('memory', {})
139
+ if not isinstance(memory, dict):
140
+ return defaults
141
+ return {
142
+ 'conversationReflection': memory.get('conversationReflection', True),
143
+ 'ruleMaintenance': memory.get('ruleMaintenance', True),
144
+ 'promptModel': memory.get('promptModel', 'haiku'),
145
+ }
146
+ except (IOError, json.JSONDecodeError, KeyError):
147
+ return defaults
148
+
149
+
120
150
  def get_stale_rules():
121
151
  """
122
152
  Run `codeyam memory status` and parse the output to find stale rules.
@@ -154,8 +184,8 @@ def get_stale_rules():
154
184
  # Look for the next few lines for details
155
185
  for j in range(i + 1, min(i + 4, len(lines))):
156
186
  detail = lines[j].strip()
157
- if detail.startswith('Rule timestamp:'):
158
- rule_info['rule_timestamp'] = detail.replace('Rule timestamp:', '').strip()
187
+ if detail.startswith('Last audited:'):
188
+ rule_info['last_audited'] = detail.replace('Last audited:', '').strip()
159
189
  elif detail.startswith('Newest file:'):
160
190
  rule_info['newest_file'] = detail.replace('Newest file:', '').strip()
161
191
  elif detail.startswith('File modified:'):
@@ -250,6 +280,28 @@ def get_conversation_context(transcript_path, last_line):
250
280
  return user_turn_count, conversation_snippets, modified_files, current_line_count
251
281
 
252
282
 
283
+ def has_assistant_messages(transcript_path, start_line):
284
+ """
285
+ Check if there are any assistant messages in the transcript after start_line.
286
+ Used to confirm Claude actually started responding before treating a gap as an interruption.
287
+ """
288
+ try:
289
+ with open(transcript_path, 'r') as f:
290
+ all_lines = f.readlines()
291
+ except IOError:
292
+ return False
293
+
294
+ for line in all_lines[start_line:]:
295
+ try:
296
+ obj = json.loads(line)
297
+ if obj.get('type') == 'assistant':
298
+ return True
299
+ except (json.JSONDecodeError, KeyError):
300
+ continue
301
+
302
+ return False
303
+
304
+
253
305
  def build_stale_rules_context(stale_rules):
254
306
  """Build context content for stale rules review."""
255
307
  parts = []
@@ -261,7 +313,7 @@ def build_stale_rules_context(stale_rules):
261
313
  parts.append("For each rule, review the rule content and the diff of changes, then:")
262
314
  parts.append("1. Determine if the rule content needs updating based on the code changes")
263
315
  parts.append("2. Update the rule if needed")
264
- parts.append("3. ALWAYS update the timestamp (run `codeyam memory touch`)\n")
316
+ parts.append("3. ALWAYS run `codeyam memory touch` to mark rules as audited\n")
265
317
 
266
318
  for rule in stale_rules:
267
319
  parts.append(f"### {rule['name']}")
@@ -273,8 +325,8 @@ def build_stale_rules_context(stale_rules):
273
325
  parts.append(f" Changed file: {rule['newest_file']}")
274
326
  if rule.get('file_modified'):
275
327
  parts.append(f" File modified: {rule['file_modified']}")
276
- if rule.get('rule_timestamp'):
277
- parts.append(f" Rule timestamp: {rule['rule_timestamp']}")
328
+ if rule.get('last_audited'):
329
+ parts.append(f" Last audited: {rule['last_audited']}")
278
330
  if rule.get('diff'):
279
331
  parts.append(f" Changes:")
280
332
  for line in rule['diff'].split('\n'):
@@ -314,7 +366,41 @@ def build_conversation_context(conversation_snippets, modified_files):
314
366
  return '\n'.join(parts)
315
367
 
316
368
 
317
- def spawn_claude_agent(prompt, log_file, project_dir):
369
+ def build_interruption_context(conversation_snippets, follow_up_prompt, modified_files):
370
+ """Build context content for an interrupted session review."""
371
+ parts = []
372
+ parts.append("## Interruption Review\n")
373
+ parts.append(
374
+ "The user interrupted Claude mid-response — a strong signal of confusion or misunderstanding. "
375
+ "Review the interrupted conversation and the user's follow-up to identify rule-worthy learnings.\n"
376
+ )
377
+
378
+ # Load guidance from shared template file
379
+ guidance = (PROMPTS_DIR / 'conversation-guidance.txt').read_text()
380
+ parts.append(guidance)
381
+
382
+ if modified_files:
383
+ parts.append("Files modified this session:")
384
+ for file_path, tool_name in sorted(modified_files):
385
+ parts.append(f"- {file_path} ({tool_name})")
386
+ parts.append("")
387
+
388
+ parts.append("### Session transcript\n")
389
+ summary_lines = []
390
+ for snippet in conversation_snippets:
391
+ role = snippet['role']
392
+ content = snippet['content'].replace('\n', ' ')
393
+ summary_lines.append(f"[{role}]: {content}")
394
+ parts.append('\n'.join(summary_lines))
395
+
396
+ parts.append("")
397
+ parts.append("### User's follow-up after interruption\n")
398
+ parts.append(follow_up_prompt)
399
+
400
+ return '\n'.join(parts)
401
+
402
+
403
+ def spawn_claude_agent(prompt, log_file, project_dir, model='haiku'):
318
404
  """Spawn a detached claude -p agent as a background process."""
319
405
  try:
320
406
  log_fh = open(log_file, 'w')
@@ -322,7 +408,8 @@ def spawn_claude_agent(prompt, log_file, project_dir):
322
408
  env['CODEYAM_RULE_AGENT'] = '1'
323
409
  subprocess.Popen(
324
410
  ['claude', '-p', prompt,
325
- '--model', 'haiku',
411
+ '--model', model,
412
+ '--no-session-persistence',
326
413
  '--output-format', 'stream-json', '--verbose',
327
414
  '--allowedTools', 'Read,Edit,Write,Bash,Glob,Grep'],
328
415
  cwd=project_dir,
@@ -335,21 +422,43 @@ def spawn_claude_agent(prompt, log_file, project_dir):
335
422
  pass # claude CLI not available, skip silently
336
423
 
337
424
 
338
- def main():
339
- # Read hook input from stdin
340
- try:
341
- hook_input = json.load(sys.stdin)
342
- except json.JSONDecodeError:
343
- return
425
+ def read_marker(marker_file):
426
+ """
427
+ Read marker file. Returns (last_line, written_by_stop).
428
+ Format: "<line_count>" or "<line_count> stop" — the suffix distinguishes
429
+ whether the Stop hook wrote this marker (normal completion) vs the
430
+ UserPromptSubmit handler (interruption detection).
431
+ """
432
+ if marker_file.exists():
433
+ try:
434
+ text = marker_file.read_text().strip()
435
+ parts = text.split()
436
+ line_count = int(parts[0])
437
+ was_stop = len(parts) > 1 and parts[1] == 'stop'
438
+ return line_count, was_stop
439
+ except (ValueError, IOError):
440
+ pass
441
+ return 0, False
442
+
443
+
444
+ def write_marker(marker_file, line_count, source='submit'):
445
+ """Write marker with source tag. source is 'stop' or 'submit'."""
446
+ marker_file.write_text(f'{line_count} {source}')
447
+
448
+
449
+ def handle_stop(hook_input):
450
+ """
451
+ Handle the Stop hook event.
452
+ Reviews completed turns for stale rules and conversation confusion signals.
453
+
454
+ Important: the fast work (transcript parsing, marker update, conversation
455
+ agent spawn) runs first. The slow `get_stale_rules()` call (~10s) runs last
456
+ so the hook timeout doesn't kill us before the critical work is done.
457
+ """
458
+ settings = load_memory_settings()
344
459
 
345
460
  session_id = hook_input.get('session_id', '')
346
461
  transcript_path = hook_input.get('transcript_path', '')
347
- stop_hook_active = hook_input.get('stop_hook_active', False)
348
-
349
- # Prevent infinite loops — stop_hook_active covers same-process recursion,
350
- # env var covers spawned subagent sessions triggering the hook on exit
351
- if stop_hook_active or os.environ.get('CODEYAM_RULE_AGENT'):
352
- return
353
462
 
354
463
  if not session_id or not transcript_path:
355
464
  return
@@ -358,58 +467,23 @@ def main():
358
467
  marker_dir.mkdir(exist_ok=True)
359
468
  marker_file = marker_dir / f'{session_id}.marker'
360
469
 
361
- # Read last checked line
362
- last_line = 0
363
- if marker_file.exists():
364
- try:
365
- last_line = int(marker_file.read_text().strip())
366
- except (ValueError, IOError):
367
- last_line = 0
470
+ last_line, _ = read_marker(marker_file)
368
471
 
369
- # Check for stale rules
370
- stale_rules = get_stale_rules()
371
-
372
- # Get conversation context
472
+ # Fast: parse transcript for conversation context
373
473
  user_turn_count, conversation_snippets, modified_files, current_line_count = get_conversation_context(
374
474
  transcript_path, last_line
375
475
  )
376
476
 
377
- # Determine what to include in review
378
- has_stale_rules = len(stale_rules) > 0
379
- has_conversation = len(conversation_snippets) > 0
380
-
381
- # Only fire if there's something to review
382
- if not has_stale_rules and not has_conversation:
383
- return
384
-
385
- # Update marker
386
- marker_file.write_text(str(current_line_count))
477
+ # Update marker immediately so UserPromptSubmit knows Stop ran,
478
+ # even if we get killed during the slow stale rules check below
479
+ write_marker(marker_file, current_line_count, 'stop')
387
480
 
388
481
  project_dir = os.environ.get('CLAUDE_PROJECT_DIR', os.getcwd())
389
-
390
- # Unique suffix per invocation so each Stop produces a distinct transcript
391
- from datetime import datetime
392
482
  invocation_ts = datetime.now().strftime('%Y%m%d-%H%M%S')
393
483
  invocation_id = f'{session_id}-{invocation_ts}'
394
484
 
395
- # Spawn independent agent for stale rules review
396
- if has_stale_rules:
397
- stale_context = build_stale_rules_context(stale_rules)
398
- stale_context_file = marker_dir / f'{invocation_id}-stale.context'
399
- stale_context_file.write_text(stale_context)
400
-
401
- stale_log_file = marker_dir / f'{invocation_id}-stale.log'
402
- stale_notification_file = marker_dir / 'rule-notification-stale.md'
403
- stale_prompt = load_prompt_template(
404
- 'stale-rules-prompt.txt',
405
- CONTEXT_FILE=str(stale_context_file),
406
- NOTIFICATION_FILE=str(stale_notification_file),
407
- PROJECT_DIR=project_dir,
408
- )
409
- spawn_claude_agent(stale_prompt, stale_log_file, project_dir)
410
-
411
- # Spawn independent agent for conversation review
412
- if has_conversation:
485
+ # Fast: spawn conversation review agent first (if enabled)
486
+ if settings['conversationReflection'] and len(conversation_snippets) > 0:
413
487
  conv_context = build_conversation_context(conversation_snippets, modified_files)
414
488
  conv_context_file = marker_dir / f'{invocation_id}-conversation.context'
415
489
  conv_context_file.write_text(conv_context)
@@ -422,7 +496,132 @@ def main():
422
496
  NOTIFICATION_FILE=str(conv_notification_file),
423
497
  PROJECT_DIR=project_dir,
424
498
  )
425
- spawn_claude_agent(conv_prompt, conv_log_file, project_dir)
499
+ spawn_claude_agent(conv_prompt, conv_log_file, project_dir, model=settings['promptModel'])
500
+
501
+ # Slow (~10s): check for stale rules last — if the hook timeout kills us
502
+ # here, the conversation agent and marker are already handled
503
+ if settings['ruleMaintenance']:
504
+ stale_rules = get_stale_rules()
505
+
506
+ if len(stale_rules) > 0:
507
+ stale_context = build_stale_rules_context(stale_rules)
508
+ stale_context_file = marker_dir / f'{invocation_id}-stale.context'
509
+ stale_context_file.write_text(stale_context)
510
+
511
+ stale_log_file = marker_dir / f'{invocation_id}-stale.log'
512
+ stale_notification_file = marker_dir / 'rule-notification-stale.md'
513
+ stale_prompt = load_prompt_template(
514
+ 'stale-rules-prompt.txt',
515
+ CONTEXT_FILE=str(stale_context_file),
516
+ NOTIFICATION_FILE=str(stale_notification_file),
517
+ PROJECT_DIR=project_dir,
518
+ )
519
+ spawn_claude_agent(stale_prompt, stale_log_file, project_dir, model=settings['promptModel'])
520
+
521
+
522
+ def handle_user_prompt_submit(hook_input):
523
+ """
524
+ Handle the UserPromptSubmit hook event.
525
+ Detects whether the previous turn was interrupted by checking if the Stop hook's
526
+ marker file is stale (transcript has lines beyond the marker). If so, spawns a
527
+ rule-reflection agent focused on the interruption.
528
+ """
529
+ settings = load_memory_settings()
530
+
531
+ # Interruption detection is part of conversation reflection
532
+ if not settings['conversationReflection']:
533
+ return
534
+
535
+ session_id = hook_input.get('session_id', '')
536
+ transcript_path = hook_input.get('transcript_path', '')
537
+ follow_up_prompt = hook_input.get('prompt', '')
538
+
539
+ if not session_id or not transcript_path:
540
+ return
541
+
542
+ marker_dir = Path('/tmp/claude-rule-markers')
543
+ marker_dir.mkdir(exist_ok=True)
544
+ marker_file = marker_dir / f'{session_id}.marker'
545
+
546
+ last_line, was_stop = read_marker(marker_file)
547
+
548
+ # If the Stop hook already ran for the previous turn, this is a normal
549
+ # completion — not an interruption. The Stop hook tags the marker with
550
+ # 'stop' when it writes it.
551
+ if was_stop:
552
+ return
553
+
554
+ # Count current transcript lines
555
+ try:
556
+ with open(transcript_path, 'r') as f:
557
+ current_line_count = sum(1 for _ in f)
558
+ except IOError:
559
+ return
560
+
561
+ # Quick exit: if nothing new since the marker, definitely no interruption
562
+ if current_line_count <= last_line:
563
+ return
564
+
565
+ # Verify Claude actually started responding in the unprocessed lines.
566
+ # Guards against false positives on first prompt (no assistant yet) or
567
+ # if the user hit Escape before Claude produced any output.
568
+ if not has_assistant_messages(transcript_path, last_line):
569
+ return
570
+
571
+ # Interruption detected! Build context and spawn agent.
572
+ _, conversation_snippets, modified_files, _ = get_conversation_context(
573
+ transcript_path, last_line
574
+ )
575
+
576
+ if not conversation_snippets:
577
+ return
578
+
579
+ # Update marker so we don't re-process these lines
580
+ write_marker(marker_file, current_line_count, 'submit')
581
+
582
+ project_dir = os.environ.get('CLAUDE_PROJECT_DIR', os.getcwd())
583
+
584
+ invocation_ts = datetime.now().strftime('%Y%m%d-%H%M%S')
585
+ invocation_id = f'{session_id}-{invocation_ts}'
586
+
587
+ interruption_context = build_interruption_context(
588
+ conversation_snippets, follow_up_prompt, modified_files
589
+ )
590
+ context_file = marker_dir / f'{invocation_id}-interruption.context'
591
+ context_file.write_text(interruption_context)
592
+
593
+ log_file = marker_dir / f'{invocation_id}-interruption.log'
594
+ notification_file = marker_dir / 'rule-notification-interruption.md'
595
+ prompt = load_prompt_template(
596
+ 'interruption-prompt.txt',
597
+ CONTEXT_FILE=str(context_file),
598
+ NOTIFICATION_FILE=str(notification_file),
599
+ PROJECT_DIR=project_dir,
600
+ )
601
+ spawn_claude_agent(prompt, log_file, project_dir, model=settings['promptModel'])
602
+
603
+
604
+ def main():
605
+ # Read hook input from stdin
606
+ try:
607
+ hook_input = json.load(sys.stdin)
608
+ except json.JSONDecodeError:
609
+ return
610
+
611
+ stop_hook_active = hook_input.get('stop_hook_active', False)
612
+
613
+ # Prevent infinite loops — stop_hook_active covers same-process recursion,
614
+ # env var covers spawned subagent sessions triggering the hook on exit
615
+ if stop_hook_active or os.environ.get('CODEYAM_RULE_AGENT'):
616
+ return
617
+
618
+ # Detect event type: UserPromptSubmit has a 'prompt' field, Stop does not
619
+ is_user_prompt = 'prompt' in hook_input
620
+ if is_user_prompt:
621
+ handle_user_prompt_submit(hook_input)
622
+ else:
623
+ handle_stop(hook_input)
624
+
426
625
 
427
626
  if __name__ == '__main__':
428
627
  main()