convex 1.34.0 → 1.35.0

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 (607) hide show
  1. package/CHANGELOG.md +98 -43
  2. package/dist/browser.bundle.js +13 -10
  3. package/dist/browser.bundle.js.map +3 -3
  4. package/dist/cjs/browser/index-node.js +3 -1
  5. package/dist/cjs/browser/index.js +3 -1
  6. package/dist/cjs/browser/index.js.map +2 -2
  7. package/dist/cjs/browser/query_options.js.map +2 -2
  8. package/dist/cjs/browser/sync/authentication_manager.js +4 -1
  9. package/dist/cjs/browser/sync/authentication_manager.js.map +2 -2
  10. package/dist/cjs/browser/sync/web_socket_manager.js +1 -7
  11. package/dist/cjs/browser/sync/web_socket_manager.js.map +2 -2
  12. package/dist/cjs/cli/aiFiles.js +39 -20
  13. package/dist/cjs/cli/aiFiles.js.map +3 -3
  14. package/dist/cjs/cli/codegen_templates/readme.js +14 -1
  15. package/dist/cjs/cli/codegen_templates/readme.js.map +2 -2
  16. package/dist/cjs/cli/configure.js +34 -32
  17. package/dist/cjs/cli/configure.js.map +2 -2
  18. package/dist/cjs/cli/deploy.js +7 -8
  19. package/dist/cjs/cli/deploy.js.map +2 -2
  20. package/dist/cjs/cli/deploymentCreate.js +225 -40
  21. package/dist/cjs/cli/deploymentCreate.js.map +3 -3
  22. package/dist/cjs/cli/deploymentSelect.js +14 -13
  23. package/dist/cjs/cli/deploymentSelect.js.map +2 -2
  24. package/dist/cjs/cli/dev.js +30 -11
  25. package/dist/cjs/cli/dev.js.map +2 -2
  26. package/dist/cjs/cli/docs.js +1 -1
  27. package/dist/cjs/cli/docs.js.map +2 -2
  28. package/dist/cjs/cli/init.js +1 -1
  29. package/dist/cjs/cli/init.js.map +2 -2
  30. package/dist/cjs/cli/lib/aiFiles/agentsmd.js +73 -0
  31. package/dist/cjs/cli/lib/aiFiles/agentsmd.js.map +7 -0
  32. package/dist/cjs/cli/lib/aiFiles/claudemd.js +73 -0
  33. package/dist/cjs/cli/lib/aiFiles/claudemd.js.map +7 -0
  34. package/dist/cjs/cli/lib/aiFiles/cursorrules.js +48 -0
  35. package/dist/cjs/cli/lib/aiFiles/cursorrules.js.map +7 -0
  36. package/dist/cjs/cli/lib/aiFiles/guidelinesmd.js +58 -0
  37. package/dist/cjs/cli/lib/aiFiles/guidelinesmd.js.map +7 -0
  38. package/dist/cjs/cli/lib/aiFiles/index.js +215 -0
  39. package/dist/cjs/cli/lib/aiFiles/index.js.map +7 -0
  40. package/dist/cjs/cli/lib/aiFiles/paths.js.map +7 -0
  41. package/dist/cjs/cli/lib/aiFiles/skills.js +196 -0
  42. package/dist/cjs/cli/lib/aiFiles/skills.js.map +7 -0
  43. package/dist/cjs/cli/lib/aiFiles/state.js +96 -0
  44. package/dist/cjs/cli/lib/aiFiles/state.js.map +7 -0
  45. package/dist/cjs/cli/lib/aiFiles/status.js +198 -0
  46. package/dist/cjs/cli/lib/aiFiles/status.js.map +7 -0
  47. package/dist/cjs/cli/lib/aiFiles/utils.js +128 -0
  48. package/dist/cjs/cli/lib/aiFiles/utils.js.map +7 -0
  49. package/dist/cjs/cli/lib/api.js +70 -7
  50. package/dist/cjs/cli/lib/api.js.map +2 -2
  51. package/dist/cjs/cli/lib/command.js +10 -6
  52. package/dist/cjs/cli/lib/command.js.map +2 -2
  53. package/dist/cjs/cli/lib/config.js +43 -7
  54. package/dist/cjs/cli/lib/config.js.map +3 -3
  55. package/dist/cjs/cli/lib/deploy2.js +9 -26
  56. package/dist/cjs/cli/lib/deploy2.js.map +2 -2
  57. package/dist/cjs/cli/lib/deployApi/componentDefinition.js +4 -1
  58. package/dist/cjs/cli/lib/deployApi/componentDefinition.js.map +2 -2
  59. package/dist/cjs/cli/lib/deploymentSelection.js +45 -2
  60. package/dist/cjs/cli/lib/deploymentSelection.js.map +2 -2
  61. package/dist/cjs/cli/lib/deploymentSelector.js +1 -0
  62. package/dist/cjs/cli/lib/deploymentSelector.js.map +2 -2
  63. package/dist/cjs/cli/lib/dev.js +162 -117
  64. package/dist/cjs/cli/lib/dev.js.map +2 -2
  65. package/dist/cjs/cli/lib/env.js +1 -13
  66. package/dist/cjs/cli/lib/env.js.map +2 -2
  67. package/dist/cjs/cli/lib/expiration.js +104 -0
  68. package/dist/cjs/cli/lib/expiration.js.map +7 -0
  69. package/dist/cjs/cli/lib/generatedFunctionLogsApi.js.map +1 -1
  70. package/dist/cjs/cli/lib/init.js +4 -3
  71. package/dist/cjs/cli/lib/init.js.map +2 -2
  72. package/dist/cjs/cli/lib/insights.js +1 -1
  73. package/dist/cjs/cli/lib/insights.js.map +2 -2
  74. package/dist/cjs/cli/lib/localDeployment/anonymous.js +15 -8
  75. package/dist/cjs/cli/lib/localDeployment/anonymous.js.map +2 -2
  76. package/dist/cjs/cli/lib/localDeployment/localDeployment.js +8 -10
  77. package/dist/cjs/cli/lib/localDeployment/localDeployment.js.map +2 -2
  78. package/dist/cjs/cli/lib/localDeployment/run.js +1 -0
  79. package/dist/cjs/cli/lib/localDeployment/run.js.map +2 -2
  80. package/dist/cjs/cli/lib/localDeployment/upgrade.js +2 -2
  81. package/dist/cjs/cli/lib/localDeployment/upgrade.js.map +2 -2
  82. package/dist/cjs/cli/lib/localDeployment/utils.js +9 -0
  83. package/dist/cjs/cli/lib/localDeployment/utils.js.map +2 -2
  84. package/dist/cjs/cli/lib/mcp/tools/status.js +1 -1
  85. package/dist/cjs/cli/lib/mcp/tools/status.js.map +2 -2
  86. package/dist/cjs/cli/lib/updates.js +12 -13
  87. package/dist/cjs/cli/lib/updates.js.map +2 -2
  88. package/dist/cjs/cli/lib/usage.js +2 -1
  89. package/dist/cjs/cli/lib/usage.js.map +2 -2
  90. package/dist/cjs/cli/lib/utils/prompts.js +2 -1
  91. package/dist/cjs/cli/lib/utils/prompts.js.map +2 -2
  92. package/dist/cjs/cli/lib/utils/utils.js +46 -20
  93. package/dist/cjs/cli/lib/utils/utils.js.map +3 -3
  94. package/dist/cjs/cli/lib/versionApi.js +7 -4
  95. package/dist/cjs/cli/lib/versionApi.js.map +2 -2
  96. package/dist/cjs/cli/lib/workos/workos.js +4 -6
  97. package/dist/cjs/cli/lib/workos/workos.js.map +2 -2
  98. package/dist/cjs/index.js +1 -1
  99. package/dist/cjs/index.js.map +1 -1
  100. package/dist/cjs/react/client.js +43 -6
  101. package/dist/cjs/react/client.js.map +2 -2
  102. package/dist/cjs/react/index.js +2 -0
  103. package/dist/cjs/react/index.js.map +2 -2
  104. package/dist/cjs/react-clerk/ConvexProviderWithClerk.js.map +1 -1
  105. package/dist/cjs/server/api.js.map +2 -2
  106. package/dist/cjs/server/components/definition.js.map +1 -1
  107. package/dist/cjs/server/components/index.js +40 -4
  108. package/dist/cjs/server/components/index.js.map +2 -2
  109. package/dist/cjs/server/data_model.js.map +1 -1
  110. package/dist/cjs/server/impl/meta_impl.js +78 -0
  111. package/dist/cjs/server/impl/meta_impl.js.map +7 -0
  112. package/dist/cjs/server/impl/registration_impl.js +16 -11
  113. package/dist/cjs/server/impl/registration_impl.js.map +2 -2
  114. package/dist/cjs/server/index.js.map +2 -2
  115. package/dist/cjs/server/meta.js +17 -0
  116. package/dist/cjs/server/meta.js.map +7 -0
  117. package/dist/cjs/server/registration.js.map +1 -1
  118. package/dist/cjs-types/browser/index.d.ts +1 -0
  119. package/dist/cjs-types/browser/index.d.ts.map +1 -1
  120. package/dist/cjs-types/browser/query_options.d.ts +12 -9
  121. package/dist/cjs-types/browser/query_options.d.ts.map +1 -1
  122. package/dist/cjs-types/browser/sync/authentication_manager.d.ts.map +1 -1
  123. package/dist/cjs-types/browser/sync/web_socket_manager.d.ts.map +1 -1
  124. package/dist/cjs-types/cli/aiFiles.d.ts.map +1 -1
  125. package/dist/cjs-types/cli/codegen_templates/readme.d.ts.map +1 -1
  126. package/dist/cjs-types/cli/configure.d.ts.map +1 -1
  127. package/dist/cjs-types/cli/configure.test.d.ts +2 -0
  128. package/dist/cjs-types/cli/configure.test.d.ts.map +1 -0
  129. package/dist/cjs-types/cli/deploy.d.ts.map +1 -1
  130. package/dist/cjs-types/cli/deploymentCreate.d.ts +1 -0
  131. package/dist/cjs-types/cli/deploymentCreate.d.ts.map +1 -1
  132. package/dist/cjs-types/cli/deploymentSelect.d.ts +2 -1
  133. package/dist/cjs-types/cli/deploymentSelect.d.ts.map +1 -1
  134. package/dist/cjs-types/cli/dev.d.ts +3 -1
  135. package/dist/cjs-types/cli/dev.d.ts.map +1 -1
  136. package/dist/cjs-types/cli/lib/aiFiles/agentsmd.d.ts +19 -0
  137. package/dist/cjs-types/cli/lib/aiFiles/agentsmd.d.ts.map +1 -0
  138. package/dist/cjs-types/cli/lib/aiFiles/agentsmd.test.d.ts +2 -0
  139. package/dist/cjs-types/cli/lib/aiFiles/agentsmd.test.d.ts.map +1 -0
  140. package/dist/cjs-types/cli/lib/aiFiles/claudemd.d.ts +19 -0
  141. package/dist/cjs-types/cli/lib/aiFiles/claudemd.d.ts.map +1 -0
  142. package/dist/cjs-types/cli/lib/aiFiles/claudemd.test.d.ts +2 -0
  143. package/dist/cjs-types/cli/lib/aiFiles/claudemd.test.d.ts.map +1 -0
  144. package/dist/cjs-types/cli/lib/aiFiles/cursorrules.d.ts +10 -0
  145. package/dist/cjs-types/cli/lib/aiFiles/cursorrules.d.ts.map +1 -0
  146. package/dist/cjs-types/cli/lib/aiFiles/guidelinesmd.d.ts +12 -0
  147. package/dist/cjs-types/cli/lib/aiFiles/guidelinesmd.d.ts.map +1 -0
  148. package/dist/cjs-types/cli/lib/aiFiles/guidelinesmd.test.d.ts +2 -0
  149. package/dist/cjs-types/cli/lib/aiFiles/guidelinesmd.test.d.ts.map +1 -0
  150. package/dist/cjs-types/cli/lib/aiFiles/index.d.ts +42 -0
  151. package/dist/cjs-types/cli/lib/aiFiles/index.d.ts.map +1 -0
  152. package/dist/cjs-types/cli/lib/aiFiles/index.test.d.ts.map +1 -0
  153. package/dist/cjs-types/cli/lib/aiFiles/integration.test.d.ts.map +1 -0
  154. package/dist/cjs-types/cli/lib/{ai → aiFiles}/paths.d.ts +4 -0
  155. package/dist/cjs-types/cli/lib/aiFiles/paths.d.ts.map +1 -0
  156. package/dist/cjs-types/cli/lib/aiFiles/prompt.test.d.ts.map +1 -0
  157. package/dist/cjs-types/cli/lib/aiFiles/skills.d.ts +20 -0
  158. package/dist/cjs-types/cli/lib/aiFiles/skills.d.ts.map +1 -0
  159. package/dist/cjs-types/cli/lib/aiFiles/state.d.ts +38 -0
  160. package/dist/cjs-types/cli/lib/aiFiles/state.d.ts.map +1 -0
  161. package/dist/cjs-types/cli/lib/aiFiles/state.test.d.ts +2 -0
  162. package/dist/cjs-types/cli/lib/aiFiles/state.test.d.ts.map +1 -0
  163. package/dist/cjs-types/cli/lib/aiFiles/status.d.ts +6 -0
  164. package/dist/cjs-types/cli/lib/aiFiles/status.d.ts.map +1 -0
  165. package/dist/cjs-types/cli/lib/aiFiles/utils.d.ts +56 -0
  166. package/dist/cjs-types/cli/lib/aiFiles/utils.d.ts.map +1 -0
  167. package/dist/cjs-types/cli/lib/aiFiles/utils.test.d.ts +2 -0
  168. package/dist/cjs-types/cli/lib/aiFiles/utils.test.d.ts.map +1 -0
  169. package/dist/cjs-types/cli/lib/api.d.ts +3 -3
  170. package/dist/cjs-types/cli/lib/api.d.ts.map +1 -1
  171. package/dist/cjs-types/cli/lib/command.d.ts +2 -1
  172. package/dist/cjs-types/cli/lib/command.d.ts.map +1 -1
  173. package/dist/cjs-types/cli/lib/config.d.ts +18 -6
  174. package/dist/cjs-types/cli/lib/config.d.ts.map +1 -1
  175. package/dist/cjs-types/cli/lib/deploy2.d.ts +5 -2
  176. package/dist/cjs-types/cli/lib/deploy2.d.ts.map +1 -1
  177. package/dist/cjs-types/cli/lib/deployApi/componentDefinition.d.ts +27 -12
  178. package/dist/cjs-types/cli/lib/deployApi/componentDefinition.d.ts.map +1 -1
  179. package/dist/cjs-types/cli/lib/deployApi/definitionConfig.d.ts +24 -24
  180. package/dist/cjs-types/cli/lib/deployApi/modules.d.ts +14 -14
  181. package/dist/cjs-types/cli/lib/deployApi/startPush.d.ts +61 -52
  182. package/dist/cjs-types/cli/lib/deployApi/startPush.d.ts.map +1 -1
  183. package/dist/cjs-types/cli/lib/deploymentSelection.d.ts.map +1 -1
  184. package/dist/cjs-types/cli/lib/deploymentSelector.d.ts +2 -0
  185. package/dist/cjs-types/cli/lib/deploymentSelector.d.ts.map +1 -1
  186. package/dist/cjs-types/cli/lib/dev.d.ts.map +1 -1
  187. package/dist/cjs-types/cli/lib/env.d.ts +0 -4
  188. package/dist/cjs-types/cli/lib/env.d.ts.map +1 -1
  189. package/dist/cjs-types/cli/lib/expiration.d.ts +35 -0
  190. package/dist/cjs-types/cli/lib/expiration.d.ts.map +1 -0
  191. package/dist/cjs-types/cli/lib/expiration.test.d.ts +2 -0
  192. package/dist/cjs-types/cli/lib/expiration.test.d.ts.map +1 -0
  193. package/dist/cjs-types/cli/lib/generatedFunctionLogsApi.d.ts +16 -1
  194. package/dist/cjs-types/cli/lib/generatedFunctionLogsApi.d.ts.map +1 -1
  195. package/dist/cjs-types/cli/lib/init.d.ts.map +1 -1
  196. package/dist/cjs-types/cli/lib/localDeployment/anonymous.d.ts.map +1 -1
  197. package/dist/cjs-types/cli/lib/localDeployment/localDeployment.d.ts.map +1 -1
  198. package/dist/cjs-types/cli/lib/localDeployment/run.d.ts +15 -0
  199. package/dist/cjs-types/cli/lib/localDeployment/run.d.ts.map +1 -1
  200. package/dist/cjs-types/cli/lib/localDeployment/upgrade.d.ts.map +1 -1
  201. package/dist/cjs-types/cli/lib/localDeployment/utils.d.ts +7 -0
  202. package/dist/cjs-types/cli/lib/localDeployment/utils.d.ts.map +1 -1
  203. package/dist/cjs-types/cli/lib/mcp/requestContext.d.ts +3 -3
  204. package/dist/cjs-types/cli/lib/mcp/tools/insights.d.ts +2 -2
  205. package/dist/cjs-types/cli/lib/updates.d.ts +4 -3
  206. package/dist/cjs-types/cli/lib/updates.d.ts.map +1 -1
  207. package/dist/cjs-types/cli/lib/usage.d.ts.map +1 -1
  208. package/dist/cjs-types/cli/lib/utils/prompts.d.ts +1 -0
  209. package/dist/cjs-types/cli/lib/utils/prompts.d.ts.map +1 -1
  210. package/dist/cjs-types/cli/lib/utils/utils.d.ts +16 -2
  211. package/dist/cjs-types/cli/lib/utils/utils.d.ts.map +1 -1
  212. package/dist/cjs-types/cli/lib/versionApi.d.ts +7 -1
  213. package/dist/cjs-types/cli/lib/versionApi.d.ts.map +1 -1
  214. package/dist/cjs-types/cli/lib/workos/workos.d.ts.map +1 -1
  215. package/dist/cjs-types/index.d.ts +1 -1
  216. package/dist/cjs-types/react/client.d.ts +54 -2
  217. package/dist/cjs-types/react/client.d.ts.map +1 -1
  218. package/dist/cjs-types/react/index.d.ts +7 -2
  219. package/dist/cjs-types/react/index.d.ts.map +1 -1
  220. package/dist/cjs-types/react/use_query_object_options.test.d.ts +5 -0
  221. package/dist/cjs-types/react/use_query_object_options.test.d.ts.map +1 -0
  222. package/dist/cjs-types/react/use_query_result.test.d.ts +5 -0
  223. package/dist/cjs-types/react/use_query_result.test.d.ts.map +1 -0
  224. package/dist/cjs-types/react-clerk/ConvexProviderWithClerk.d.ts +1 -1
  225. package/dist/cjs-types/server/api.d.ts +5 -1
  226. package/dist/cjs-types/server/api.d.ts.map +1 -1
  227. package/dist/cjs-types/server/components/definition.d.ts +1 -0
  228. package/dist/cjs-types/server/components/definition.d.ts.map +1 -1
  229. package/dist/cjs-types/server/components/index.d.ts +5 -1
  230. package/dist/cjs-types/server/components/index.d.ts.map +1 -1
  231. package/dist/cjs-types/server/data_model.d.ts +2 -1
  232. package/dist/cjs-types/server/data_model.d.ts.map +1 -1
  233. package/dist/cjs-types/server/impl/meta_impl.d.ts +5 -0
  234. package/dist/cjs-types/server/impl/meta_impl.d.ts.map +1 -0
  235. package/dist/cjs-types/server/impl/registration_impl.d.ts.map +1 -1
  236. package/dist/cjs-types/server/index.d.ts +1 -0
  237. package/dist/cjs-types/server/index.d.ts.map +1 -1
  238. package/dist/cjs-types/server/meta.d.ts +72 -0
  239. package/dist/cjs-types/server/meta.d.ts.map +1 -0
  240. package/dist/cjs-types/server/registration.d.ts.map +1 -1
  241. package/dist/cli.bundle.cjs +2446 -1933
  242. package/dist/cli.bundle.cjs.map +4 -4
  243. package/dist/esm/browser/index-node.js +1 -0
  244. package/dist/esm/browser/index.js +1 -0
  245. package/dist/esm/browser/index.js.map +2 -2
  246. package/dist/esm/browser/query_options.js.map +2 -2
  247. package/dist/esm/browser/sync/authentication_manager.js +4 -1
  248. package/dist/esm/browser/sync/authentication_manager.js.map +2 -2
  249. package/dist/esm/browser/sync/web_socket_manager.js +1 -7
  250. package/dist/esm/browser/sync/web_socket_manager.js.map +2 -2
  251. package/dist/esm/cli/aiFiles.js +41 -23
  252. package/dist/esm/cli/aiFiles.js.map +2 -2
  253. package/dist/esm/cli/codegen_templates/readme.js +14 -1
  254. package/dist/esm/cli/codegen_templates/readme.js.map +2 -2
  255. package/dist/esm/cli/configure.js +35 -33
  256. package/dist/esm/cli/configure.js.map +2 -2
  257. package/dist/esm/cli/deploy.js +11 -10
  258. package/dist/esm/cli/deploy.js.map +2 -2
  259. package/dist/esm/cli/deploymentCreate.js +238 -42
  260. package/dist/esm/cli/deploymentCreate.js.map +2 -2
  261. package/dist/esm/cli/deploymentSelect.js +13 -12
  262. package/dist/esm/cli/deploymentSelect.js.map +2 -2
  263. package/dist/esm/cli/dev.js +34 -13
  264. package/dist/esm/cli/dev.js.map +2 -2
  265. package/dist/esm/cli/docs.js +1 -1
  266. package/dist/esm/cli/docs.js.map +2 -2
  267. package/dist/esm/cli/init.js +2 -2
  268. package/dist/esm/cli/init.js.map +2 -2
  269. package/dist/esm/cli/lib/aiFiles/agentsmd.js +56 -0
  270. package/dist/esm/cli/lib/aiFiles/agentsmd.js.map +7 -0
  271. package/dist/esm/cli/lib/aiFiles/claudemd.js +56 -0
  272. package/dist/esm/cli/lib/aiFiles/claudemd.js.map +7 -0
  273. package/dist/esm/cli/lib/aiFiles/cursorrules.js +16 -0
  274. package/dist/esm/cli/lib/aiFiles/cursorrules.js.map +7 -0
  275. package/dist/esm/cli/lib/aiFiles/guidelinesmd.js +35 -0
  276. package/dist/esm/cli/lib/aiFiles/guidelinesmd.js.map +7 -0
  277. package/dist/esm/cli/lib/aiFiles/index.js +193 -0
  278. package/dist/esm/cli/lib/aiFiles/index.js.map +7 -0
  279. package/dist/esm/cli/lib/aiFiles/paths.js.map +7 -0
  280. package/dist/esm/cli/lib/aiFiles/skills.js +163 -0
  281. package/dist/esm/cli/lib/aiFiles/skills.js.map +7 -0
  282. package/dist/esm/cli/lib/aiFiles/state.js +60 -0
  283. package/dist/esm/cli/lib/aiFiles/state.js.map +7 -0
  284. package/dist/esm/cli/lib/aiFiles/status.js +178 -0
  285. package/dist/esm/cli/lib/aiFiles/status.js.map +7 -0
  286. package/dist/esm/cli/lib/aiFiles/utils.js +97 -0
  287. package/dist/esm/cli/lib/aiFiles/utils.js.map +7 -0
  288. package/dist/esm/cli/lib/api.js +70 -7
  289. package/dist/esm/cli/lib/api.js.map +2 -2
  290. package/dist/esm/cli/lib/command.js +10 -6
  291. package/dist/esm/cli/lib/command.js.map +2 -2
  292. package/dist/esm/cli/lib/config.js +41 -6
  293. package/dist/esm/cli/lib/config.js.map +2 -2
  294. package/dist/esm/cli/lib/deploy2.js +13 -26
  295. package/dist/esm/cli/lib/deploy2.js.map +2 -2
  296. package/dist/esm/cli/lib/deployApi/componentDefinition.js +4 -1
  297. package/dist/esm/cli/lib/deployApi/componentDefinition.js.map +2 -2
  298. package/dist/esm/cli/lib/deploymentSelection.js +46 -2
  299. package/dist/esm/cli/lib/deploymentSelection.js.map +2 -2
  300. package/dist/esm/cli/lib/deploymentSelector.js +1 -0
  301. package/dist/esm/cli/lib/deploymentSelector.js.map +2 -2
  302. package/dist/esm/cli/lib/dev.js +162 -118
  303. package/dist/esm/cli/lib/dev.js.map +2 -2
  304. package/dist/esm/cli/lib/env.js +0 -11
  305. package/dist/esm/cli/lib/env.js.map +2 -2
  306. package/dist/esm/cli/lib/expiration.js +80 -0
  307. package/dist/esm/cli/lib/expiration.js.map +7 -0
  308. package/dist/esm/cli/lib/init.js +4 -3
  309. package/dist/esm/cli/lib/init.js.map +2 -2
  310. package/dist/esm/cli/lib/insights.js +1 -1
  311. package/dist/esm/cli/lib/insights.js.map +2 -2
  312. package/dist/esm/cli/lib/localDeployment/anonymous.js +16 -9
  313. package/dist/esm/cli/lib/localDeployment/anonymous.js.map +2 -2
  314. package/dist/esm/cli/lib/localDeployment/localDeployment.js +9 -11
  315. package/dist/esm/cli/lib/localDeployment/localDeployment.js.map +2 -2
  316. package/dist/esm/cli/lib/localDeployment/run.js +1 -1
  317. package/dist/esm/cli/lib/localDeployment/run.js.map +2 -2
  318. package/dist/esm/cli/lib/localDeployment/upgrade.js +2 -2
  319. package/dist/esm/cli/lib/localDeployment/upgrade.js.map +2 -2
  320. package/dist/esm/cli/lib/localDeployment/utils.js +8 -0
  321. package/dist/esm/cli/lib/localDeployment/utils.js.map +2 -2
  322. package/dist/esm/cli/lib/mcp/tools/status.js +1 -1
  323. package/dist/esm/cli/lib/mcp/tools/status.js.map +2 -2
  324. package/dist/esm/cli/lib/updates.js +14 -12
  325. package/dist/esm/cli/lib/updates.js.map +2 -2
  326. package/dist/esm/cli/lib/usage.js +2 -1
  327. package/dist/esm/cli/lib/usage.js.map +2 -2
  328. package/dist/esm/cli/lib/utils/prompts.js +2 -1
  329. package/dist/esm/cli/lib/utils/prompts.js.map +2 -2
  330. package/dist/esm/cli/lib/utils/utils.js +45 -20
  331. package/dist/esm/cli/lib/utils/utils.js.map +3 -3
  332. package/dist/esm/cli/lib/versionApi.js +7 -4
  333. package/dist/esm/cli/lib/versionApi.js.map +2 -2
  334. package/dist/esm/cli/lib/workos/workos.js +4 -6
  335. package/dist/esm/cli/lib/workos/workos.js.map +2 -2
  336. package/dist/esm/index.js +1 -1
  337. package/dist/esm/index.js.map +1 -1
  338. package/dist/esm/react/client.js +43 -6
  339. package/dist/esm/react/client.js.map +2 -2
  340. package/dist/esm/react/index.js +1 -0
  341. package/dist/esm/react/index.js.map +2 -2
  342. package/dist/esm/react-clerk/ConvexProviderWithClerk.js.map +1 -1
  343. package/dist/esm/server/api.js.map +2 -2
  344. package/dist/esm/server/components/index.js +40 -4
  345. package/dist/esm/server/components/index.js.map +2 -2
  346. package/dist/esm/server/impl/meta_impl.js +54 -0
  347. package/dist/esm/server/impl/meta_impl.js.map +7 -0
  348. package/dist/esm/server/impl/registration_impl.js +20 -11
  349. package/dist/esm/server/impl/registration_impl.js.map +2 -2
  350. package/dist/esm/server/index.js.map +2 -2
  351. package/dist/esm/server/meta.js +2 -0
  352. package/dist/esm/server/meta.js.map +7 -0
  353. package/dist/esm-types/browser/index.d.ts +1 -0
  354. package/dist/esm-types/browser/index.d.ts.map +1 -1
  355. package/dist/esm-types/browser/query_options.d.ts +12 -9
  356. package/dist/esm-types/browser/query_options.d.ts.map +1 -1
  357. package/dist/esm-types/browser/sync/authentication_manager.d.ts.map +1 -1
  358. package/dist/esm-types/browser/sync/web_socket_manager.d.ts.map +1 -1
  359. package/dist/esm-types/cli/aiFiles.d.ts.map +1 -1
  360. package/dist/esm-types/cli/codegen_templates/readme.d.ts.map +1 -1
  361. package/dist/esm-types/cli/configure.d.ts.map +1 -1
  362. package/dist/esm-types/cli/configure.test.d.ts +2 -0
  363. package/dist/esm-types/cli/configure.test.d.ts.map +1 -0
  364. package/dist/esm-types/cli/deploy.d.ts.map +1 -1
  365. package/dist/esm-types/cli/deploymentCreate.d.ts +1 -0
  366. package/dist/esm-types/cli/deploymentCreate.d.ts.map +1 -1
  367. package/dist/esm-types/cli/deploymentSelect.d.ts +2 -1
  368. package/dist/esm-types/cli/deploymentSelect.d.ts.map +1 -1
  369. package/dist/esm-types/cli/dev.d.ts +3 -1
  370. package/dist/esm-types/cli/dev.d.ts.map +1 -1
  371. package/dist/esm-types/cli/lib/aiFiles/agentsmd.d.ts +19 -0
  372. package/dist/esm-types/cli/lib/aiFiles/agentsmd.d.ts.map +1 -0
  373. package/dist/esm-types/cli/lib/aiFiles/agentsmd.test.d.ts +2 -0
  374. package/dist/esm-types/cli/lib/aiFiles/agentsmd.test.d.ts.map +1 -0
  375. package/dist/esm-types/cli/lib/aiFiles/claudemd.d.ts +19 -0
  376. package/dist/esm-types/cli/lib/aiFiles/claudemd.d.ts.map +1 -0
  377. package/dist/esm-types/cli/lib/aiFiles/claudemd.test.d.ts +2 -0
  378. package/dist/esm-types/cli/lib/aiFiles/claudemd.test.d.ts.map +1 -0
  379. package/dist/esm-types/cli/lib/aiFiles/cursorrules.d.ts +10 -0
  380. package/dist/esm-types/cli/lib/aiFiles/cursorrules.d.ts.map +1 -0
  381. package/dist/esm-types/cli/lib/aiFiles/guidelinesmd.d.ts +12 -0
  382. package/dist/esm-types/cli/lib/aiFiles/guidelinesmd.d.ts.map +1 -0
  383. package/dist/esm-types/cli/lib/aiFiles/guidelinesmd.test.d.ts +2 -0
  384. package/dist/esm-types/cli/lib/aiFiles/guidelinesmd.test.d.ts.map +1 -0
  385. package/dist/esm-types/cli/lib/aiFiles/index.d.ts +42 -0
  386. package/dist/esm-types/cli/lib/aiFiles/index.d.ts.map +1 -0
  387. package/dist/esm-types/cli/lib/aiFiles/index.test.d.ts.map +1 -0
  388. package/dist/esm-types/cli/lib/aiFiles/integration.test.d.ts.map +1 -0
  389. package/dist/esm-types/cli/lib/{ai → aiFiles}/paths.d.ts +4 -0
  390. package/dist/esm-types/cli/lib/aiFiles/paths.d.ts.map +1 -0
  391. package/dist/esm-types/cli/lib/aiFiles/prompt.test.d.ts.map +1 -0
  392. package/dist/esm-types/cli/lib/aiFiles/skills.d.ts +20 -0
  393. package/dist/esm-types/cli/lib/aiFiles/skills.d.ts.map +1 -0
  394. package/dist/esm-types/cli/lib/aiFiles/state.d.ts +38 -0
  395. package/dist/esm-types/cli/lib/aiFiles/state.d.ts.map +1 -0
  396. package/dist/esm-types/cli/lib/aiFiles/state.test.d.ts +2 -0
  397. package/dist/esm-types/cli/lib/aiFiles/state.test.d.ts.map +1 -0
  398. package/dist/esm-types/cli/lib/aiFiles/status.d.ts +6 -0
  399. package/dist/esm-types/cli/lib/aiFiles/status.d.ts.map +1 -0
  400. package/dist/esm-types/cli/lib/aiFiles/utils.d.ts +56 -0
  401. package/dist/esm-types/cli/lib/aiFiles/utils.d.ts.map +1 -0
  402. package/dist/esm-types/cli/lib/aiFiles/utils.test.d.ts +2 -0
  403. package/dist/esm-types/cli/lib/aiFiles/utils.test.d.ts.map +1 -0
  404. package/dist/esm-types/cli/lib/api.d.ts +3 -3
  405. package/dist/esm-types/cli/lib/api.d.ts.map +1 -1
  406. package/dist/esm-types/cli/lib/command.d.ts +2 -1
  407. package/dist/esm-types/cli/lib/command.d.ts.map +1 -1
  408. package/dist/esm-types/cli/lib/config.d.ts +18 -6
  409. package/dist/esm-types/cli/lib/config.d.ts.map +1 -1
  410. package/dist/esm-types/cli/lib/deploy2.d.ts +5 -2
  411. package/dist/esm-types/cli/lib/deploy2.d.ts.map +1 -1
  412. package/dist/esm-types/cli/lib/deployApi/componentDefinition.d.ts +27 -12
  413. package/dist/esm-types/cli/lib/deployApi/componentDefinition.d.ts.map +1 -1
  414. package/dist/esm-types/cli/lib/deployApi/definitionConfig.d.ts +24 -24
  415. package/dist/esm-types/cli/lib/deployApi/modules.d.ts +14 -14
  416. package/dist/esm-types/cli/lib/deployApi/startPush.d.ts +61 -52
  417. package/dist/esm-types/cli/lib/deployApi/startPush.d.ts.map +1 -1
  418. package/dist/esm-types/cli/lib/deploymentSelection.d.ts.map +1 -1
  419. package/dist/esm-types/cli/lib/deploymentSelector.d.ts +2 -0
  420. package/dist/esm-types/cli/lib/deploymentSelector.d.ts.map +1 -1
  421. package/dist/esm-types/cli/lib/dev.d.ts.map +1 -1
  422. package/dist/esm-types/cli/lib/env.d.ts +0 -4
  423. package/dist/esm-types/cli/lib/env.d.ts.map +1 -1
  424. package/dist/esm-types/cli/lib/expiration.d.ts +35 -0
  425. package/dist/esm-types/cli/lib/expiration.d.ts.map +1 -0
  426. package/dist/esm-types/cli/lib/expiration.test.d.ts +2 -0
  427. package/dist/esm-types/cli/lib/expiration.test.d.ts.map +1 -0
  428. package/dist/esm-types/cli/lib/generatedFunctionLogsApi.d.ts +16 -1
  429. package/dist/esm-types/cli/lib/generatedFunctionLogsApi.d.ts.map +1 -1
  430. package/dist/esm-types/cli/lib/init.d.ts.map +1 -1
  431. package/dist/esm-types/cli/lib/localDeployment/anonymous.d.ts.map +1 -1
  432. package/dist/esm-types/cli/lib/localDeployment/localDeployment.d.ts.map +1 -1
  433. package/dist/esm-types/cli/lib/localDeployment/run.d.ts +15 -0
  434. package/dist/esm-types/cli/lib/localDeployment/run.d.ts.map +1 -1
  435. package/dist/esm-types/cli/lib/localDeployment/upgrade.d.ts.map +1 -1
  436. package/dist/esm-types/cli/lib/localDeployment/utils.d.ts +7 -0
  437. package/dist/esm-types/cli/lib/localDeployment/utils.d.ts.map +1 -1
  438. package/dist/esm-types/cli/lib/mcp/requestContext.d.ts +3 -3
  439. package/dist/esm-types/cli/lib/mcp/tools/insights.d.ts +2 -2
  440. package/dist/esm-types/cli/lib/updates.d.ts +4 -3
  441. package/dist/esm-types/cli/lib/updates.d.ts.map +1 -1
  442. package/dist/esm-types/cli/lib/usage.d.ts.map +1 -1
  443. package/dist/esm-types/cli/lib/utils/prompts.d.ts +1 -0
  444. package/dist/esm-types/cli/lib/utils/prompts.d.ts.map +1 -1
  445. package/dist/esm-types/cli/lib/utils/utils.d.ts +16 -2
  446. package/dist/esm-types/cli/lib/utils/utils.d.ts.map +1 -1
  447. package/dist/esm-types/cli/lib/versionApi.d.ts +7 -1
  448. package/dist/esm-types/cli/lib/versionApi.d.ts.map +1 -1
  449. package/dist/esm-types/cli/lib/workos/workos.d.ts.map +1 -1
  450. package/dist/esm-types/index.d.ts +1 -1
  451. package/dist/esm-types/react/client.d.ts +54 -2
  452. package/dist/esm-types/react/client.d.ts.map +1 -1
  453. package/dist/esm-types/react/index.d.ts +7 -2
  454. package/dist/esm-types/react/index.d.ts.map +1 -1
  455. package/dist/esm-types/react/use_query_object_options.test.d.ts +5 -0
  456. package/dist/esm-types/react/use_query_object_options.test.d.ts.map +1 -0
  457. package/dist/esm-types/react/use_query_result.test.d.ts +5 -0
  458. package/dist/esm-types/react/use_query_result.test.d.ts.map +1 -0
  459. package/dist/esm-types/react-clerk/ConvexProviderWithClerk.d.ts +1 -1
  460. package/dist/esm-types/server/api.d.ts +5 -1
  461. package/dist/esm-types/server/api.d.ts.map +1 -1
  462. package/dist/esm-types/server/components/definition.d.ts +1 -0
  463. package/dist/esm-types/server/components/definition.d.ts.map +1 -1
  464. package/dist/esm-types/server/components/index.d.ts +5 -1
  465. package/dist/esm-types/server/components/index.d.ts.map +1 -1
  466. package/dist/esm-types/server/data_model.d.ts +2 -1
  467. package/dist/esm-types/server/data_model.d.ts.map +1 -1
  468. package/dist/esm-types/server/impl/meta_impl.d.ts +5 -0
  469. package/dist/esm-types/server/impl/meta_impl.d.ts.map +1 -0
  470. package/dist/esm-types/server/impl/registration_impl.d.ts.map +1 -1
  471. package/dist/esm-types/server/index.d.ts +1 -0
  472. package/dist/esm-types/server/index.d.ts.map +1 -1
  473. package/dist/esm-types/server/meta.d.ts +72 -0
  474. package/dist/esm-types/server/meta.d.ts.map +1 -0
  475. package/dist/esm-types/server/registration.d.ts.map +1 -1
  476. package/dist/react.bundle.js +55 -15
  477. package/dist/react.bundle.js.map +3 -3
  478. package/package.json +11 -7
  479. package/schemas/convex.schema.json +22 -3
  480. package/src/browser/index.ts +3 -0
  481. package/src/browser/query_options.test.ts +0 -9
  482. package/src/browser/query_options.ts +36 -15
  483. package/src/browser/sync/authentication_manager.ts +9 -4
  484. package/src/browser/sync/client_node.test.ts +125 -0
  485. package/src/browser/sync/web_socket_manager.ts +1 -7
  486. package/src/cli/aiFiles.ts +56 -33
  487. package/src/cli/codegen_templates/readme.ts +14 -1
  488. package/src/cli/configure.test.ts +138 -0
  489. package/src/cli/configure.ts +62 -55
  490. package/src/cli/deploy.ts +12 -9
  491. package/src/cli/deploymentCreate.test.ts +349 -14
  492. package/src/cli/deploymentCreate.ts +268 -41
  493. package/src/cli/deploymentSelect.test.ts +136 -27
  494. package/src/cli/deploymentSelect.ts +50 -41
  495. package/src/cli/deploymentSelection.test.ts +399 -37
  496. package/src/cli/dev.ts +49 -14
  497. package/src/cli/docs.ts +1 -1
  498. package/src/cli/init.ts +2 -2
  499. package/src/cli/lib/{ai → aiFiles}/MANUAL_TESTING.md +6 -2
  500. package/src/cli/lib/aiFiles/agentsmd.test.ts +133 -0
  501. package/src/cli/lib/aiFiles/agentsmd.ts +81 -0
  502. package/src/cli/lib/aiFiles/claudemd.test.ts +92 -0
  503. package/src/cli/lib/aiFiles/claudemd.ts +81 -0
  504. package/src/cli/lib/aiFiles/cursorrules.ts +25 -0
  505. package/src/cli/lib/aiFiles/guidelinesmd.test.ts +50 -0
  506. package/src/cli/lib/aiFiles/guidelinesmd.ts +49 -0
  507. package/src/cli/lib/{ai → aiFiles}/index.test.ts +343 -516
  508. package/src/cli/lib/aiFiles/index.ts +297 -0
  509. package/src/cli/lib/{ai → aiFiles}/integration.test.ts +195 -158
  510. package/src/cli/lib/{ai → aiFiles}/paths.ts +5 -0
  511. package/src/cli/lib/{ai → aiFiles}/prompt.test.ts +79 -31
  512. package/src/cli/lib/aiFiles/skills.ts +243 -0
  513. package/src/cli/lib/aiFiles/state.test.ts +280 -0
  514. package/src/cli/lib/aiFiles/state.ts +82 -0
  515. package/src/cli/lib/aiFiles/status.ts +246 -0
  516. package/src/cli/lib/aiFiles/utils.test.ts +50 -0
  517. package/src/cli/lib/aiFiles/utils.ts +191 -0
  518. package/src/cli/lib/api.ts +88 -7
  519. package/src/cli/lib/command.ts +18 -8
  520. package/src/cli/lib/config.test.ts +185 -8
  521. package/src/cli/lib/config.ts +73 -12
  522. package/src/cli/lib/deploy2.ts +14 -27
  523. package/src/cli/lib/deployApi/componentDefinition.ts +4 -1
  524. package/src/cli/lib/deploymentSelection.ts +59 -6
  525. package/src/cli/lib/deploymentSelector.test.ts +6 -0
  526. package/src/cli/lib/deploymentSelector.ts +2 -0
  527. package/src/cli/lib/dev.ts +202 -153
  528. package/src/cli/lib/env.ts +0 -15
  529. package/src/cli/lib/expiration.test.ts +159 -0
  530. package/src/cli/lib/expiration.ts +124 -0
  531. package/src/cli/lib/generatedFunctionLogsApi.ts +16 -1
  532. package/src/cli/lib/init.ts +6 -2
  533. package/src/cli/lib/insights.ts +1 -1
  534. package/src/cli/lib/localDeployment/anonymous.ts +19 -9
  535. package/src/cli/lib/localDeployment/localDeployment.ts +9 -11
  536. package/src/cli/lib/localDeployment/run.ts +1 -1
  537. package/src/cli/lib/localDeployment/upgrade.ts +12 -10
  538. package/src/cli/lib/localDeployment/utils.ts +12 -0
  539. package/src/cli/lib/mcp/tools/status.ts +1 -1
  540. package/src/cli/lib/updates.test.ts +97 -60
  541. package/src/cli/lib/updates.ts +17 -15
  542. package/src/cli/lib/usage.ts +3 -1
  543. package/src/cli/lib/utils/prompts.ts +2 -0
  544. package/src/cli/lib/utils/utils.test.ts +6 -6
  545. package/src/cli/lib/utils/utils.ts +66 -27
  546. package/src/cli/lib/versionApi.test.ts +13 -10
  547. package/src/cli/lib/versionApi.ts +13 -5
  548. package/src/cli/lib/workos/workos.ts +4 -5
  549. package/src/index.ts +1 -1
  550. package/src/react/client.test.tsx +65 -0
  551. package/src/react/client.ts +129 -13
  552. package/src/react/index.ts +9 -1
  553. package/src/react/use_query_object_options.test.ts +50 -0
  554. package/src/react/use_query_result.test.ts +41 -0
  555. package/src/react-clerk/ConvexProviderWithClerk.test.tsx +1 -1
  556. package/src/react-clerk/ConvexProviderWithClerk.tsx +1 -1
  557. package/src/server/api.ts +5 -1
  558. package/src/server/components/definition.ts +3 -0
  559. package/src/server/components/index.ts +62 -5
  560. package/src/server/data_model.ts +2 -1
  561. package/src/server/impl/meta_impl.ts +74 -0
  562. package/src/server/impl/registration_impl.ts +21 -9
  563. package/src/server/index.ts +8 -0
  564. package/src/server/meta.ts +76 -0
  565. package/src/server/registration.ts +10 -0
  566. package/src/server/schema.test.ts +78 -1
  567. package/dist/cjs/cli/lib/ai/config.js +0 -144
  568. package/dist/cjs/cli/lib/ai/config.js.map +0 -7
  569. package/dist/cjs/cli/lib/ai/index.js +0 -704
  570. package/dist/cjs/cli/lib/ai/index.js.map +0 -7
  571. package/dist/cjs/cli/lib/ai/paths.js.map +0 -7
  572. package/dist/cjs-types/cli/lib/ai/config.d.ts +0 -50
  573. package/dist/cjs-types/cli/lib/ai/config.d.ts.map +0 -1
  574. package/dist/cjs-types/cli/lib/ai/config.test.d.ts +0 -2
  575. package/dist/cjs-types/cli/lib/ai/config.test.d.ts.map +0 -1
  576. package/dist/cjs-types/cli/lib/ai/index.d.ts +0 -56
  577. package/dist/cjs-types/cli/lib/ai/index.d.ts.map +0 -1
  578. package/dist/cjs-types/cli/lib/ai/index.test.d.ts.map +0 -1
  579. package/dist/cjs-types/cli/lib/ai/integration.test.d.ts.map +0 -1
  580. package/dist/cjs-types/cli/lib/ai/paths.d.ts.map +0 -1
  581. package/dist/cjs-types/cli/lib/ai/prompt.test.d.ts.map +0 -1
  582. package/dist/esm/cli/lib/ai/config.js +0 -109
  583. package/dist/esm/cli/lib/ai/config.js.map +0 -7
  584. package/dist/esm/cli/lib/ai/index.js +0 -684
  585. package/dist/esm/cli/lib/ai/index.js.map +0 -7
  586. package/dist/esm/cli/lib/ai/paths.js.map +0 -7
  587. package/dist/esm-types/cli/lib/ai/config.d.ts +0 -50
  588. package/dist/esm-types/cli/lib/ai/config.d.ts.map +0 -1
  589. package/dist/esm-types/cli/lib/ai/config.test.d.ts +0 -2
  590. package/dist/esm-types/cli/lib/ai/config.test.d.ts.map +0 -1
  591. package/dist/esm-types/cli/lib/ai/index.d.ts +0 -56
  592. package/dist/esm-types/cli/lib/ai/index.d.ts.map +0 -1
  593. package/dist/esm-types/cli/lib/ai/index.test.d.ts.map +0 -1
  594. package/dist/esm-types/cli/lib/ai/integration.test.d.ts.map +0 -1
  595. package/dist/esm-types/cli/lib/ai/paths.d.ts.map +0 -1
  596. package/dist/esm-types/cli/lib/ai/prompt.test.d.ts.map +0 -1
  597. package/src/cli/lib/ai/config.test.ts +0 -338
  598. package/src/cli/lib/ai/config.ts +0 -159
  599. package/src/cli/lib/ai/index.ts +0 -1006
  600. /package/dist/cjs/cli/lib/{ai → aiFiles}/paths.js +0 -0
  601. /package/dist/cjs-types/cli/lib/{ai → aiFiles}/index.test.d.ts +0 -0
  602. /package/dist/cjs-types/cli/lib/{ai → aiFiles}/integration.test.d.ts +0 -0
  603. /package/dist/cjs-types/cli/lib/{ai → aiFiles}/prompt.test.d.ts +0 -0
  604. /package/dist/esm/cli/lib/{ai → aiFiles}/paths.js +0 -0
  605. /package/dist/esm-types/cli/lib/{ai → aiFiles}/index.test.d.ts +0 -0
  606. /package/dist/esm-types/cli/lib/{ai → aiFiles}/integration.test.d.ts +0 -0
  607. /package/dist/esm-types/cli/lib/{ai → aiFiles}/prompt.test.d.ts +0 -0
@@ -1,5 +1,10 @@
1
1
  import path from "path";
2
2
 
3
+ export type AiFilesPaths = {
4
+ projectDir: string;
5
+ convexDir: string;
6
+ };
7
+
3
8
  const AI_FILES_PARENT_DIR = "_generated";
4
9
  const AI_FILES_DIR = "ai";
5
10
 
@@ -1,11 +1,21 @@
1
1
  import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
2
- import { PassThrough, Writable } from "stream";
3
2
  import fs from "fs";
4
3
  import os from "os";
5
4
  import path from "path";
6
5
  import type { Context } from "../../../bundler/context.js";
6
+ import {
7
+ AGENTS_MD_END_MARKER,
8
+ AGENTS_MD_START_MARKER,
9
+ } from "../../codegen_templates/agentsmd.js";
7
10
 
8
- let testInput: PassThrough;
11
+ const { mockPromptYesNo } = vi.hoisted(() => {
12
+ return { mockPromptYesNo: vi.fn() };
13
+ });
14
+
15
+ vi.mock("@sentry/node", () => ({
16
+ captureException: vi.fn(),
17
+ captureMessage: vi.fn(),
18
+ }));
9
19
 
10
20
  vi.mock("../../../bundler/log.js", () => ({
11
21
  logMessage: vi.fn(),
@@ -16,10 +26,13 @@ vi.mock("../versionApi.js", () => ({
16
26
  downloadGuidelines: vi.fn(async () => "prompt test guidelines content"),
17
27
  fetchAgentSkillsSha: vi.fn(async () => "prompt-test-sha"),
18
28
  getVersion: vi.fn(async () => ({
19
- message: null,
20
- guidelinesHash: "prompt-test-guidelines-hash",
21
- agentSkillsSha: "prompt-test-agent-skills-sha",
22
- disableSkillsCli: false,
29
+ kind: "ok",
30
+ data: {
31
+ message: null,
32
+ guidelinesHash: "prompt-test-guidelines-hash",
33
+ agentSkillsSha: "prompt-test-agent-skills-sha",
34
+ disableSkillsCli: false,
35
+ },
23
36
  })),
24
37
  }));
25
38
 
@@ -35,22 +48,15 @@ vi.mock("child_process", () => ({
35
48
  },
36
49
  }));
37
50
 
38
- vi.mock("@inquirer/confirm", async (importOriginal) => {
39
- const actual = await importOriginal<typeof import("@inquirer/confirm")>();
51
+ vi.mock("../utils/prompts.js", async (importOriginal) => {
52
+ const actual = await importOriginal<typeof import("../utils/prompts.js")>();
40
53
  return {
41
54
  ...actual,
42
- default: (config: any, context: any) => {
43
- const output = new Writable({
44
- write(_c, _e, cb) {
45
- cb();
46
- },
47
- });
48
- return actual.default(config, { ...context, input: testInput, output });
49
- },
55
+ promptYesNo: mockPromptYesNo,
50
56
  };
51
57
  });
52
58
 
53
- import { maybeSetupAiFiles } from "./index.js";
59
+ import { attemptSetupAiFiles } from "./index.js";
54
60
 
55
61
  function makeTmpDir(): string {
56
62
  return fs.mkdtempSync(`${os.tmpdir()}${path.sep}`);
@@ -92,7 +98,7 @@ describe("maybeSetupAiFiles interactive prompt", () => {
92
98
  fs.writeFileSync(path.join(convexDir, "schema.ts"), "");
93
99
  originalIsTTY = process.stdin.isTTY;
94
100
  process.stdin.isTTY = true;
95
- testInput = new PassThrough();
101
+ mockPromptYesNo.mockResolvedValue(true);
96
102
  });
97
103
 
98
104
  afterEach(() => {
@@ -103,11 +109,9 @@ describe("maybeSetupAiFiles interactive prompt", () => {
103
109
  });
104
110
 
105
111
  test("user accepts prompt: AI files are installed", async () => {
106
- const result = maybeSetupAiFiles(fakeCtx, convexDir, tmpDir);
112
+ mockPromptYesNo.mockResolvedValue(true);
107
113
 
108
- // Simulate pressing Enter to accept the default (yes)
109
- testInput.emit("keypress", null, { name: "enter" });
110
- await result;
114
+ await attemptSetupAiFiles({ ctx: fakeCtx, convexDir, projectDir: tmpDir });
111
115
 
112
116
  expect(fs.existsSync(guidelinesPath())).toBe(true);
113
117
  expect(fs.existsSync(statePath())).toBe(true);
@@ -119,13 +123,9 @@ describe("maybeSetupAiFiles interactive prompt", () => {
119
123
  });
120
124
 
121
125
  test("user declines prompt: no config and no AI files are written", async () => {
122
- const result = maybeSetupAiFiles(fakeCtx, convexDir, tmpDir);
126
+ mockPromptYesNo.mockResolvedValue(false);
123
127
 
124
- // Type "n" then Enter to decline
125
- testInput.write("n");
126
- testInput.emit("keypress", null, { name: "n" });
127
- testInput.emit("keypress", null, { name: "enter" });
128
- await result;
128
+ await attemptSetupAiFiles({ ctx: fakeCtx, convexDir, projectDir: tmpDir });
129
129
 
130
130
  expect(fs.existsSync(guidelinesPath())).toBe(false);
131
131
  expect(fs.existsSync(path.join(tmpDir, "AGENTS.md"))).toBe(false);
@@ -133,10 +133,10 @@ describe("maybeSetupAiFiles interactive prompt", () => {
133
133
  expect(fs.existsSync(projectConfigPath())).toBe(false);
134
134
  });
135
135
 
136
- test("agent mode skips the prompt and does not install AI files", async () => {
137
- vi.stubEnv("CONVEX_AGENT_MODE", "anonymous");
136
+ test("non-interactive terminal skips the prompt and does not install AI files", async () => {
137
+ process.stdin.isTTY = false;
138
138
 
139
- await maybeSetupAiFiles(fakeCtx, convexDir, tmpDir);
139
+ await attemptSetupAiFiles({ ctx: fakeCtx, convexDir, projectDir: tmpDir });
140
140
 
141
141
  expect(fs.existsSync(guidelinesPath())).toBe(false);
142
142
  expect(fs.existsSync(statePath())).toBe(false);
@@ -144,4 +144,52 @@ describe("maybeSetupAiFiles interactive prompt", () => {
144
144
  expect(fs.existsSync(path.join(tmpDir, "CLAUDE.md"))).toBe(false);
145
145
  expect(fs.existsSync(projectConfigPath())).toBe(false);
146
146
  });
147
+
148
+ test("existing state file updates AI files without prompting", async () => {
149
+ const stateDir = path.join(convexDir, "_generated", "ai");
150
+ fs.mkdirSync(stateDir, { recursive: true });
151
+ fs.writeFileSync(
152
+ path.join(stateDir, "ai-files.state.json"),
153
+ JSON.stringify(
154
+ {
155
+ guidelinesHash: "hash",
156
+ agentsMdSectionHash: "hash",
157
+ claudeMdHash: "hash",
158
+ agentSkillsSha: "sha",
159
+ installedSkillNames: [],
160
+ },
161
+ null,
162
+ 2,
163
+ ),
164
+ );
165
+
166
+ await attemptSetupAiFiles({ ctx: fakeCtx, convexDir, projectDir: tmpDir });
167
+
168
+ expect(fs.existsSync(path.join(stateDir, "ai-files.state.json"))).toBe(
169
+ true,
170
+ );
171
+ expect(fs.existsSync(guidelinesPath())).toBe(true);
172
+ expect(fs.readFileSync(guidelinesPath(), "utf8")).toBe(
173
+ "prompt test guidelines content",
174
+ );
175
+ });
176
+
177
+ test("existing AGENTS.md managed section rebuilds state without prompting", async () => {
178
+ fs.writeFileSync(
179
+ path.join(tmpDir, "AGENTS.md"),
180
+ [
181
+ "# Team notes",
182
+ "",
183
+ AGENTS_MD_START_MARKER,
184
+ "Managed section",
185
+ AGENTS_MD_END_MARKER,
186
+ "",
187
+ ].join("\n"),
188
+ );
189
+
190
+ await attemptSetupAiFiles({ ctx: fakeCtx, convexDir, projectDir: tmpDir });
191
+
192
+ expect(fs.existsSync(statePath())).toBe(true);
193
+ expect(fs.existsSync(guidelinesPath())).toBe(true);
194
+ });
147
195
  });
@@ -0,0 +1,243 @@
1
+ import child_process from "child_process";
2
+ import path from "path";
3
+ // eslint-disable-next-line no-restricted-imports
4
+ import { promises as fs } from "fs";
5
+ import { chalkStderr } from "chalk";
6
+ import { logMessage } from "../../../bundler/log.js";
7
+ import { getVersion, fetchAgentSkillsSha } from "../versionApi.js";
8
+ import { type AiFilesState } from "./state.js";
9
+ import { exhaustiveCheck, iife, readFileOrNull } from "./utils.js";
10
+
11
+ import { type AiFilesProjectConfig } from "../config.js";
12
+
13
+ /**
14
+ * Read the frontmatter `name:` values from skills installed by the skills CLI.
15
+ */
16
+ async function readInstalledSkillNames(projectDir: string): Promise<string[]> {
17
+ const skillsDir = path.join(projectDir, ".agents", "skills");
18
+ const entries = await iife(async () => {
19
+ try {
20
+ const dirents = await fs.readdir(skillsDir, { withFileTypes: true });
21
+ return dirents
22
+ .filter((d) => d.isDirectory() || d.isSymbolicLink())
23
+ .map((d) => d.name);
24
+ } catch {
25
+ return [] as string[];
26
+ }
27
+ });
28
+ if (entries.length === 0) return [];
29
+
30
+ const names: string[] = [];
31
+ for (const entry of entries) {
32
+ const skillMdPath = path.join(skillsDir, entry, "SKILL.md");
33
+ const content = await readFileOrNull(skillMdPath);
34
+ if (content === null) continue;
35
+ const match = content.match(/^---[\s\S]*?^name:\s*(.+?)\s*$/m);
36
+ if (match) {
37
+ names.push(match[1]);
38
+ }
39
+ }
40
+ return names;
41
+ }
42
+
43
+ /**
44
+ * Resolve the configured agent list, falling back to defaults.
45
+ */
46
+ function configuredSkillAgents(
47
+ aiFilesConfig?: AiFilesProjectConfig | undefined,
48
+ ): string[] {
49
+ // We default to the two most popular agents for now, "codex" installs to `.agents` which also
50
+ // covers cursor and many other tools. See: https://github.com/vercel-labs/skills?tab=readme-ov-file#supported-agents
51
+ const defaultAgents = ["claude-code", "codex"];
52
+ return aiFilesConfig?.skills?.agents ?? defaultAgents;
53
+ }
54
+
55
+ /**
56
+ * Runs `npx skills add get-convex/agent-skills --yes` in the given directory.
57
+ * Returns true on success, false if the process fails or cannot be started.
58
+ */
59
+ function runSkillsAdd(cwd: string, agents: string[]): Promise<boolean> {
60
+ const args = ["add", "get-convex/agent-skills", "--yes"];
61
+ for (const agent of agents) {
62
+ args.push("--agent", agent);
63
+ }
64
+ return runSkillsCommand(cwd, args);
65
+ }
66
+
67
+ /**
68
+ * Runs `npx skills remove <name...> --yes` to surgically remove only the
69
+ * Convex-managed skills, leaving any skills from other sources intact.
70
+ */
71
+ function runSkillsRemove({
72
+ cwd,
73
+ skillNames,
74
+ }: {
75
+ cwd: string;
76
+ skillNames: string[];
77
+ }): Promise<boolean> {
78
+ return runSkillsCommand(cwd, ["remove", ...skillNames, "--yes"]);
79
+ }
80
+
81
+ /**
82
+ * This function exists so we have a way to disable skills installs without pushing a new
83
+ * version of the convex CLI
84
+ */
85
+ async function shouldRunSkillsCli(): Promise<boolean> {
86
+ const versionData = await getVersion();
87
+
88
+ if (versionData.kind === "error") return true;
89
+
90
+ if (versionData.kind === "ok") {
91
+ if (versionData.data.disableSkillsCli) {
92
+ logMessage(chalkStderr.yellow(`Agent skills are temporarily disabled.`));
93
+ return false;
94
+ }
95
+ return true;
96
+ }
97
+
98
+ return exhaustiveCheck(versionData);
99
+ }
100
+
101
+ /**
102
+ * Remove the skills-lock.json file if it only contains skills that we
103
+ * are removing. The `npx skills remove` command leaves the lockfile behind
104
+ * even when it's logically empty.
105
+ */
106
+ async function removeSkillsLockIfEmpty({
107
+ projectDir,
108
+ removedSkillNames,
109
+ }: {
110
+ projectDir: string;
111
+ removedSkillNames: string[];
112
+ }): Promise<boolean> {
113
+ const lockPath = path.join(projectDir, "skills-lock.json");
114
+ try {
115
+ const content = await fs.readFile(lockPath, "utf8");
116
+ const lock = JSON.parse(content);
117
+
118
+ if (
119
+ !lock ||
120
+ typeof lock !== "object" ||
121
+ !lock.skills ||
122
+ typeof lock.skills !== "object"
123
+ ) {
124
+ return false;
125
+ }
126
+
127
+ const remainingSkills = Object.keys(lock.skills).filter(
128
+ (name) => !removedSkillNames.includes(name),
129
+ );
130
+
131
+ if (remainingSkills.length === 0) {
132
+ await fs.unlink(lockPath);
133
+ return true;
134
+ }
135
+ return false;
136
+ } catch {
137
+ return false;
138
+ }
139
+ }
140
+
141
+ /**
142
+ * Install Convex agent skills and record the SHA and names into the state.
143
+ * Handles the kill-switch check and all logging internally.
144
+ */
145
+ export async function installSkills({
146
+ projectDir,
147
+ state,
148
+ aiFilesConfig,
149
+ }: {
150
+ projectDir: string;
151
+ state: AiFilesState;
152
+ aiFilesConfig?: AiFilesProjectConfig | undefined;
153
+ }): Promise<void> {
154
+ if (!(await shouldRunSkillsCli())) return;
155
+ const agents = configuredSkillAgents(aiFilesConfig);
156
+ if (agents.length === 0) return;
157
+
158
+ logMessage("Installing Convex agent skills...");
159
+ const skillsOk = await runSkillsAdd(projectDir, agents);
160
+ if (!skillsOk) {
161
+ logMessage(
162
+ chalkStderr.yellow(
163
+ "Could not install agent skills. You can retry manually with: npx skills add get-convex/agent-skills",
164
+ ),
165
+ );
166
+ return;
167
+ }
168
+
169
+ const sha = await fetchAgentSkillsSha();
170
+ if (sha) state.agentSkillsSha = sha;
171
+
172
+ const names = await readInstalledSkillNames(projectDir);
173
+ if (names.length > 0) state.installedSkillNames = names;
174
+
175
+ logMessage(`${chalkStderr.green("✔")} Skills installed`);
176
+ }
177
+
178
+ /**
179
+ * Remove Convex-managed agent skills and clean up the lock file if empty.
180
+ * Returns true if any removal occurred.
181
+ */
182
+ export async function removeInstalledSkills({
183
+ projectDir,
184
+ skillNames,
185
+ }: {
186
+ projectDir: string;
187
+ skillNames: string[];
188
+ }): Promise<boolean> {
189
+ if (skillNames.length === 0) return false;
190
+ if (!(await shouldRunSkillsCli())) return false;
191
+
192
+ logMessage(`Removing Convex agent skills: ${skillNames.join(", ")}`);
193
+ const skillsOk = await runSkillsRemove({ cwd: projectDir, skillNames });
194
+ if (!skillsOk) {
195
+ logMessage(
196
+ chalkStderr.yellow(
197
+ "Could not remove agent skills automatically. Remove them manually with: npx skills remove",
198
+ ),
199
+ );
200
+ return false;
201
+ }
202
+
203
+ const lockRemoved = await removeSkillsLockIfEmpty({
204
+ projectDir,
205
+ removedSkillNames: skillNames,
206
+ });
207
+
208
+ if (lockRemoved)
209
+ logMessage(`${chalkStderr.green("✔")} Deleted skills-lock.json.`);
210
+
211
+ return true;
212
+ }
213
+
214
+ function runSkillsCommand(cwd: string, args: string[]): Promise<boolean> {
215
+ return new Promise((resolve) => {
216
+ const proc = child_process.spawn(
217
+ "npx",
218
+ ["--yes", "skills@latest", ...args],
219
+ {
220
+ cwd,
221
+ stdio: "pipe",
222
+ // .cmd files on Windows require shell execution.
223
+ shell: process.platform === "win32",
224
+ },
225
+ );
226
+ let capturedOutput = "";
227
+ proc.stdout?.on("data", (chunk) => {
228
+ capturedOutput += chunk.toString();
229
+ });
230
+ proc.stderr?.on("data", (chunk) => {
231
+ capturedOutput += chunk.toString();
232
+ });
233
+ proc.on("close", (code) => {
234
+ if (code !== 0 && capturedOutput.trim().length > 0) {
235
+ const lines = capturedOutput.trim().split(/\r?\n/);
236
+ const tail = lines.slice(-10).join("\n");
237
+ logMessage(chalkStderr.gray(`skills output (tail):\n${tail}`));
238
+ }
239
+ resolve(code === 0);
240
+ });
241
+ proc.on("error", () => resolve(false));
242
+ });
243
+ }
@@ -0,0 +1,280 @@
1
+ import { describe, test, expect, vi, beforeEach, afterEach } from "vitest";
2
+ import * as Sentry from "@sentry/node";
3
+ import { promises as fs } from "fs";
4
+ import {
5
+ aiFilesStateSchema,
6
+ attemptReadAiState,
7
+ hasAiState,
8
+ readAiStateOrDefault,
9
+ writeAiState,
10
+ } from "./state.js";
11
+
12
+ vi.mock("@sentry/node", () => ({
13
+ captureException: vi.fn(),
14
+ captureMessage: vi.fn(),
15
+ }));
16
+
17
+ vi.mock("fs", () => ({
18
+ promises: {
19
+ readFile: vi.fn(),
20
+ writeFile: vi.fn(),
21
+ mkdir: vi.fn().mockResolvedValue(undefined),
22
+ },
23
+ }));
24
+
25
+ const mockFs = vi.mocked(fs);
26
+ const mockCaptureException = vi.mocked(Sentry.captureException);
27
+
28
+ const dummyConvexDir = "/tmp/test-project/convex";
29
+
30
+ describe("aiFilesStateSchema", () => {
31
+ test("accepts a fully populated valid state object", () => {
32
+ const result = aiFilesStateSchema.safeParse({
33
+ guidelinesHash: "abc123",
34
+ agentsMdSectionHash: "def456",
35
+ claudeMdHash: "ghi789",
36
+ agentSkillsSha: "deadbeef",
37
+ installedSkillNames: ["convex-migrations", "convex-perf-review"],
38
+ });
39
+ expect(result.success).toBe(true);
40
+ });
41
+
42
+ test("accepts null hashes", () => {
43
+ const result = aiFilesStateSchema.safeParse({
44
+ guidelinesHash: null,
45
+ agentsMdSectionHash: null,
46
+ claudeMdHash: null,
47
+ agentSkillsSha: null,
48
+ });
49
+ expect(result.success).toBe(true);
50
+ });
51
+
52
+ test("applies default for installedSkillNames when absent", () => {
53
+ const result = aiFilesStateSchema.safeParse({
54
+ guidelinesHash: "abc",
55
+ agentsMdSectionHash: null,
56
+ claudeMdHash: null,
57
+ agentSkillsSha: null,
58
+ });
59
+ expect(result.success).toBe(true);
60
+ if (result.success) {
61
+ expect(result.data.installedSkillNames).toEqual([]);
62
+ }
63
+ });
64
+
65
+ test("rejects a number where a string hash is expected", () => {
66
+ const result = aiFilesStateSchema.safeParse({
67
+ guidelinesHash: 123,
68
+ agentsMdSectionHash: null,
69
+ claudeMdHash: null,
70
+ agentSkillsSha: null,
71
+ });
72
+ expect(result.success).toBe(false);
73
+ });
74
+
75
+ test("rejects missing required fields", () => {
76
+ const result = aiFilesStateSchema.safeParse({
77
+ guidelinesHash: "abc",
78
+ });
79
+ expect(result.success).toBe(false);
80
+ });
81
+ });
82
+
83
+ describe("attemptReadAiState", () => {
84
+ beforeEach(() => vi.clearAllMocks());
85
+ afterEach(() => vi.resetAllMocks());
86
+
87
+ test("returns no-file when the state file does not exist", async () => {
88
+ mockFs.readFile.mockRejectedValue(
89
+ Object.assign(new Error("ENOENT"), { code: "ENOENT" }),
90
+ );
91
+
92
+ const result = await attemptReadAiState(dummyConvexDir);
93
+
94
+ expect(result).toEqual({ kind: "no-file" });
95
+ expect(mockCaptureException).not.toHaveBeenCalled();
96
+ });
97
+
98
+ test("returns no-file when the state file is empty", async () => {
99
+ mockFs.readFile.mockResolvedValueOnce("");
100
+
101
+ const result = await attemptReadAiState(dummyConvexDir);
102
+
103
+ expect(result).toEqual({ kind: "no-file" });
104
+ expect(mockCaptureException).not.toHaveBeenCalled();
105
+ });
106
+
107
+ test("throws when reading the state file fails for reasons other than not found", async () => {
108
+ const error = Object.assign(new Error("EACCES"), { code: "EACCES" });
109
+ mockFs.readFile.mockRejectedValueOnce(error);
110
+
111
+ await expect(attemptReadAiState(dummyConvexDir)).rejects.toBe(error);
112
+ expect(mockCaptureException).not.toHaveBeenCalled();
113
+ });
114
+
115
+ test("returns ok with parsed state", async () => {
116
+ mockFs.readFile.mockResolvedValueOnce(
117
+ JSON.stringify({
118
+ guidelinesHash: "abc",
119
+ agentsMdSectionHash: "def",
120
+ claudeMdHash: null,
121
+ agentSkillsSha: null,
122
+ }),
123
+ );
124
+
125
+ const result = await attemptReadAiState(dummyConvexDir);
126
+
127
+ expect(result).toEqual({
128
+ kind: "ok",
129
+ state: {
130
+ guidelinesHash: "abc",
131
+ agentsMdSectionHash: "def",
132
+ claudeMdHash: null,
133
+ agentSkillsSha: null,
134
+ installedSkillNames: [],
135
+ },
136
+ });
137
+ });
138
+
139
+ test("returns parse-error and captures exception when JSON is invalid", async () => {
140
+ mockFs.readFile.mockResolvedValueOnce("not valid json {{{}");
141
+
142
+ const result = await attemptReadAiState(dummyConvexDir);
143
+
144
+ expect(result.kind).toBe("parse-error");
145
+ expect(mockCaptureException).toHaveBeenCalledWith(expect.any(Error));
146
+ });
147
+
148
+ test("returns parse-error and captures exception when schema validation fails", async () => {
149
+ mockFs.readFile.mockResolvedValueOnce(
150
+ JSON.stringify({
151
+ guidelinesHash: 99,
152
+ agentsMdSectionHash: null,
153
+ }),
154
+ );
155
+
156
+ const result = await attemptReadAiState(dummyConvexDir);
157
+
158
+ expect(result.kind).toBe("parse-error");
159
+ expect(mockCaptureException).toHaveBeenCalledWith(expect.any(Error));
160
+ });
161
+ });
162
+
163
+ describe("readAiStateOrDefault", () => {
164
+ beforeEach(() => vi.clearAllMocks());
165
+ afterEach(() => vi.resetAllMocks());
166
+
167
+ test("returns default state when no state file exists", async () => {
168
+ mockFs.readFile.mockRejectedValue(
169
+ Object.assign(new Error("ENOENT"), { code: "ENOENT" }),
170
+ );
171
+
172
+ const result = await readAiStateOrDefault(dummyConvexDir);
173
+
174
+ expect(result).toEqual({
175
+ guidelinesHash: null,
176
+ agentsMdSectionHash: null,
177
+ claudeMdHash: null,
178
+ agentSkillsSha: null,
179
+ installedSkillNames: [],
180
+ });
181
+ });
182
+
183
+ test("returns default state on parse error", async () => {
184
+ mockFs.readFile.mockResolvedValueOnce("not valid json {{{}");
185
+
186
+ const result = await readAiStateOrDefault(dummyConvexDir);
187
+
188
+ expect(result).toEqual({
189
+ guidelinesHash: null,
190
+ agentsMdSectionHash: null,
191
+ claudeMdHash: null,
192
+ agentSkillsSha: null,
193
+ installedSkillNames: [],
194
+ });
195
+ expect(mockCaptureException).toHaveBeenCalled();
196
+ });
197
+
198
+ test("returns parsed state when state file exists", async () => {
199
+ const stored = {
200
+ guidelinesHash: "abc",
201
+ agentsMdSectionHash: "def",
202
+ claudeMdHash: null,
203
+ agentSkillsSha: "deadbeef",
204
+ };
205
+ mockFs.readFile.mockResolvedValueOnce(JSON.stringify(stored));
206
+
207
+ const result = await readAiStateOrDefault(dummyConvexDir);
208
+
209
+ expect(result).toEqual({
210
+ ...stored,
211
+ installedSkillNames: [],
212
+ });
213
+ });
214
+ });
215
+
216
+ describe("hasAiState", () => {
217
+ beforeEach(() => vi.clearAllMocks());
218
+ afterEach(() => vi.resetAllMocks());
219
+
220
+ test("returns false when state file does not exist", async () => {
221
+ mockFs.readFile.mockRejectedValue(
222
+ Object.assign(new Error("ENOENT"), { code: "ENOENT" }),
223
+ );
224
+
225
+ const result = await hasAiState(dummyConvexDir);
226
+
227
+ expect(result).toBe(false);
228
+ expect(mockCaptureException).not.toHaveBeenCalled();
229
+ });
230
+
231
+ test("returns true when a valid state file exists", async () => {
232
+ mockFs.readFile.mockResolvedValueOnce(
233
+ JSON.stringify({
234
+ guidelinesHash: "abc",
235
+ agentsMdSectionHash: "def",
236
+ claudeMdHash: null,
237
+ agentSkillsSha: null,
238
+ }),
239
+ );
240
+
241
+ const result = await hasAiState(dummyConvexDir);
242
+
243
+ expect(result).toBe(true);
244
+ });
245
+
246
+ test("returns false and captures exception when the state file is invalid", async () => {
247
+ mockFs.readFile.mockResolvedValueOnce("not valid json {{{}");
248
+
249
+ const result = await hasAiState(dummyConvexDir);
250
+
251
+ expect(result).toBe(false);
252
+ expect(mockCaptureException).toHaveBeenCalledWith(expect.any(Error));
253
+ });
254
+ });
255
+
256
+ describe("writeAiState", () => {
257
+ beforeEach(() => vi.clearAllMocks());
258
+ afterEach(() => vi.resetAllMocks());
259
+
260
+ test("writes state file", async () => {
261
+ mockFs.writeFile.mockResolvedValue(undefined);
262
+
263
+ const state = {
264
+ guidelinesHash: "abc",
265
+ agentsMdSectionHash: "def",
266
+ claudeMdHash: null,
267
+ agentSkillsSha: null,
268
+ installedSkillNames: ["convex-migrations"],
269
+ };
270
+
271
+ await writeAiState({ state, convexDir: dummyConvexDir });
272
+
273
+ expect(mockFs.writeFile).toHaveBeenCalledTimes(1);
274
+ expect(mockFs.writeFile).toHaveBeenCalledWith(
275
+ expect.stringContaining("ai-files.state.json"),
276
+ JSON.stringify(state, null, 2) + "\n",
277
+ "utf8",
278
+ );
279
+ });
280
+ });