convex 1.34.0 → 1.34.1

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 (243) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/browser.bundle.js +6 -9
  3. package/dist/browser.bundle.js.map +2 -2
  4. package/dist/cjs/browser/sync/authentication_manager.js +4 -1
  5. package/dist/cjs/browser/sync/authentication_manager.js.map +2 -2
  6. package/dist/cjs/browser/sync/web_socket_manager.js +1 -7
  7. package/dist/cjs/browser/sync/web_socket_manager.js.map +2 -2
  8. package/dist/cjs/cli/aiFiles.js +15 -14
  9. package/dist/cjs/cli/aiFiles.js.map +2 -2
  10. package/dist/cjs/cli/configure.js +15 -10
  11. package/dist/cjs/cli/configure.js.map +2 -2
  12. package/dist/cjs/cli/lib/aiFiles/agentsmd.js +69 -0
  13. package/dist/cjs/cli/lib/aiFiles/agentsmd.js.map +7 -0
  14. package/dist/cjs/cli/lib/aiFiles/claudemd.js +69 -0
  15. package/dist/cjs/cli/lib/aiFiles/claudemd.js.map +7 -0
  16. package/dist/cjs/cli/lib/{ai → aiFiles}/config.js +73 -46
  17. package/dist/cjs/cli/lib/aiFiles/config.js.map +7 -0
  18. package/dist/cjs/cli/lib/aiFiles/cursorrules.js +48 -0
  19. package/dist/cjs/cli/lib/aiFiles/cursorrules.js.map +7 -0
  20. package/dist/cjs/cli/lib/aiFiles/guidelinesmd.js +51 -0
  21. package/dist/cjs/cli/lib/aiFiles/guidelinesmd.js.map +7 -0
  22. package/dist/cjs/cli/lib/aiFiles/index.js +231 -0
  23. package/dist/cjs/cli/lib/aiFiles/index.js.map +7 -0
  24. package/dist/cjs/cli/lib/aiFiles/paths.js.map +7 -0
  25. package/dist/cjs/cli/lib/aiFiles/skills.js +180 -0
  26. package/dist/cjs/cli/lib/aiFiles/skills.js.map +7 -0
  27. package/dist/cjs/cli/lib/aiFiles/status.js +195 -0
  28. package/dist/cjs/cli/lib/aiFiles/status.js.map +7 -0
  29. package/dist/cjs/cli/lib/aiFiles/utils.js +111 -0
  30. package/dist/cjs/cli/lib/aiFiles/utils.js.map +7 -0
  31. package/dist/cjs/cli/lib/command.js +6 -1
  32. package/dist/cjs/cli/lib/command.js.map +2 -2
  33. package/dist/cjs/cli/lib/config.js +3 -4
  34. package/dist/cjs/cli/lib/config.js.map +2 -2
  35. package/dist/cjs/cli/lib/localDeployment/anonymous.js +2 -2
  36. package/dist/cjs/cli/lib/localDeployment/anonymous.js.map +2 -2
  37. package/dist/cjs/cli/lib/updates.js +8 -8
  38. package/dist/cjs/cli/lib/updates.js.map +2 -2
  39. package/dist/cjs/cli/lib/versionApi.js +7 -4
  40. package/dist/cjs/cli/lib/versionApi.js.map +2 -2
  41. package/dist/cjs/cli/lib/workos/workos.js +4 -6
  42. package/dist/cjs/cli/lib/workos/workos.js.map +2 -2
  43. package/dist/cjs/index.js +1 -1
  44. package/dist/cjs/index.js.map +1 -1
  45. package/dist/cjs-types/browser/sync/authentication_manager.d.ts.map +1 -1
  46. package/dist/cjs-types/browser/sync/web_socket_manager.d.ts.map +1 -1
  47. package/dist/cjs-types/cli/aiFiles.d.ts.map +1 -1
  48. package/dist/cjs-types/cli/configure.d.ts.map +1 -1
  49. package/dist/cjs-types/cli/lib/aiFiles/agentsmd.d.ts +19 -0
  50. package/dist/cjs-types/cli/lib/aiFiles/agentsmd.d.ts.map +1 -0
  51. package/dist/cjs-types/cli/lib/aiFiles/agentsmd.test.d.ts +2 -0
  52. package/dist/cjs-types/cli/lib/aiFiles/agentsmd.test.d.ts.map +1 -0
  53. package/dist/cjs-types/cli/lib/aiFiles/claudemd.d.ts +19 -0
  54. package/dist/cjs-types/cli/lib/aiFiles/claudemd.d.ts.map +1 -0
  55. package/dist/cjs-types/cli/lib/aiFiles/claudemd.test.d.ts +2 -0
  56. package/dist/cjs-types/cli/lib/aiFiles/claudemd.test.d.ts.map +1 -0
  57. package/dist/cjs-types/cli/lib/aiFiles/config.d.ts +46 -0
  58. package/dist/cjs-types/cli/lib/aiFiles/config.d.ts.map +1 -0
  59. package/dist/cjs-types/cli/lib/aiFiles/config.test.d.ts.map +1 -0
  60. package/dist/cjs-types/cli/lib/aiFiles/cursorrules.d.ts +10 -0
  61. package/dist/cjs-types/cli/lib/aiFiles/cursorrules.d.ts.map +1 -0
  62. package/dist/cjs-types/cli/lib/aiFiles/guidelinesmd.d.ts +12 -0
  63. package/dist/cjs-types/cli/lib/aiFiles/guidelinesmd.d.ts.map +1 -0
  64. package/dist/cjs-types/cli/lib/aiFiles/guidelinesmd.test.d.ts +2 -0
  65. package/dist/cjs-types/cli/lib/aiFiles/guidelinesmd.test.d.ts.map +1 -0
  66. package/dist/cjs-types/cli/lib/aiFiles/index.d.ts +40 -0
  67. package/dist/cjs-types/cli/lib/aiFiles/index.d.ts.map +1 -0
  68. package/dist/cjs-types/cli/lib/aiFiles/index.test.d.ts.map +1 -0
  69. package/dist/cjs-types/cli/lib/aiFiles/integration.test.d.ts.map +1 -0
  70. package/dist/cjs-types/cli/lib/{ai → aiFiles}/paths.d.ts +4 -0
  71. package/dist/cjs-types/cli/lib/aiFiles/paths.d.ts.map +1 -0
  72. package/dist/cjs-types/cli/lib/aiFiles/prompt.test.d.ts.map +1 -0
  73. package/dist/cjs-types/cli/lib/aiFiles/skills.d.ts +18 -0
  74. package/dist/cjs-types/cli/lib/aiFiles/skills.d.ts.map +1 -0
  75. package/dist/cjs-types/cli/lib/aiFiles/status.d.ts +3 -0
  76. package/dist/cjs-types/cli/lib/aiFiles/status.d.ts.map +1 -0
  77. package/dist/cjs-types/cli/lib/aiFiles/utils.d.ts +46 -0
  78. package/dist/cjs-types/cli/lib/aiFiles/utils.d.ts.map +1 -0
  79. package/dist/cjs-types/cli/lib/config.d.ts +1 -0
  80. package/dist/cjs-types/cli/lib/config.d.ts.map +1 -1
  81. package/dist/cjs-types/cli/lib/versionApi.d.ts +7 -1
  82. package/dist/cjs-types/cli/lib/versionApi.d.ts.map +1 -1
  83. package/dist/cjs-types/cli/lib/workos/workos.d.ts.map +1 -1
  84. package/dist/cjs-types/index.d.ts +1 -1
  85. package/dist/cli.bundle.cjs +1605 -1548
  86. package/dist/cli.bundle.cjs.map +4 -4
  87. package/dist/esm/browser/sync/authentication_manager.js +4 -1
  88. package/dist/esm/browser/sync/authentication_manager.js.map +2 -2
  89. package/dist/esm/browser/sync/web_socket_manager.js +1 -7
  90. package/dist/esm/browser/sync/web_socket_manager.js.map +2 -2
  91. package/dist/esm/cli/aiFiles.js +17 -17
  92. package/dist/esm/cli/aiFiles.js.map +2 -2
  93. package/dist/esm/cli/configure.js +15 -10
  94. package/dist/esm/cli/configure.js.map +2 -2
  95. package/dist/esm/cli/lib/aiFiles/agentsmd.js +52 -0
  96. package/dist/esm/cli/lib/aiFiles/agentsmd.js.map +7 -0
  97. package/dist/esm/cli/lib/aiFiles/claudemd.js +52 -0
  98. package/dist/esm/cli/lib/aiFiles/claudemd.js.map +7 -0
  99. package/dist/esm/cli/lib/{ai → aiFiles}/config.js +71 -45
  100. package/dist/esm/cli/lib/aiFiles/config.js.map +7 -0
  101. package/dist/esm/cli/lib/aiFiles/cursorrules.js +16 -0
  102. package/dist/esm/cli/lib/aiFiles/cursorrules.js.map +7 -0
  103. package/dist/esm/cli/lib/aiFiles/guidelinesmd.js +28 -0
  104. package/dist/esm/cli/lib/aiFiles/guidelinesmd.js.map +7 -0
  105. package/dist/esm/cli/lib/aiFiles/index.js +210 -0
  106. package/dist/esm/cli/lib/aiFiles/index.js.map +7 -0
  107. package/dist/esm/cli/lib/aiFiles/paths.js.map +7 -0
  108. package/dist/esm/cli/lib/aiFiles/skills.js +147 -0
  109. package/dist/esm/cli/lib/aiFiles/skills.js.map +7 -0
  110. package/dist/esm/cli/lib/aiFiles/status.js +175 -0
  111. package/dist/esm/cli/lib/aiFiles/status.js.map +7 -0
  112. package/dist/esm/cli/lib/aiFiles/utils.js +82 -0
  113. package/dist/esm/cli/lib/aiFiles/utils.js.map +7 -0
  114. package/dist/esm/cli/lib/command.js +6 -1
  115. package/dist/esm/cli/lib/command.js.map +2 -2
  116. package/dist/esm/cli/lib/config.js +3 -4
  117. package/dist/esm/cli/lib/config.js.map +2 -2
  118. package/dist/esm/cli/lib/localDeployment/anonymous.js +2 -2
  119. package/dist/esm/cli/lib/localDeployment/anonymous.js.map +2 -2
  120. package/dist/esm/cli/lib/updates.js +8 -8
  121. package/dist/esm/cli/lib/updates.js.map +2 -2
  122. package/dist/esm/cli/lib/versionApi.js +7 -4
  123. package/dist/esm/cli/lib/versionApi.js.map +2 -2
  124. package/dist/esm/cli/lib/workos/workos.js +4 -6
  125. package/dist/esm/cli/lib/workos/workos.js.map +2 -2
  126. package/dist/esm/index.js +1 -1
  127. package/dist/esm/index.js.map +1 -1
  128. package/dist/esm-types/browser/sync/authentication_manager.d.ts.map +1 -1
  129. package/dist/esm-types/browser/sync/web_socket_manager.d.ts.map +1 -1
  130. package/dist/esm-types/cli/aiFiles.d.ts.map +1 -1
  131. package/dist/esm-types/cli/configure.d.ts.map +1 -1
  132. package/dist/esm-types/cli/lib/aiFiles/agentsmd.d.ts +19 -0
  133. package/dist/esm-types/cli/lib/aiFiles/agentsmd.d.ts.map +1 -0
  134. package/dist/esm-types/cli/lib/aiFiles/agentsmd.test.d.ts +2 -0
  135. package/dist/esm-types/cli/lib/aiFiles/agentsmd.test.d.ts.map +1 -0
  136. package/dist/esm-types/cli/lib/aiFiles/claudemd.d.ts +19 -0
  137. package/dist/esm-types/cli/lib/aiFiles/claudemd.d.ts.map +1 -0
  138. package/dist/esm-types/cli/lib/aiFiles/claudemd.test.d.ts +2 -0
  139. package/dist/esm-types/cli/lib/aiFiles/claudemd.test.d.ts.map +1 -0
  140. package/dist/esm-types/cli/lib/aiFiles/config.d.ts +46 -0
  141. package/dist/esm-types/cli/lib/aiFiles/config.d.ts.map +1 -0
  142. package/dist/esm-types/cli/lib/aiFiles/config.test.d.ts.map +1 -0
  143. package/dist/esm-types/cli/lib/aiFiles/cursorrules.d.ts +10 -0
  144. package/dist/esm-types/cli/lib/aiFiles/cursorrules.d.ts.map +1 -0
  145. package/dist/esm-types/cli/lib/aiFiles/guidelinesmd.d.ts +12 -0
  146. package/dist/esm-types/cli/lib/aiFiles/guidelinesmd.d.ts.map +1 -0
  147. package/dist/esm-types/cli/lib/aiFiles/guidelinesmd.test.d.ts +2 -0
  148. package/dist/esm-types/cli/lib/aiFiles/guidelinesmd.test.d.ts.map +1 -0
  149. package/dist/esm-types/cli/lib/aiFiles/index.d.ts +40 -0
  150. package/dist/esm-types/cli/lib/aiFiles/index.d.ts.map +1 -0
  151. package/dist/esm-types/cli/lib/aiFiles/index.test.d.ts.map +1 -0
  152. package/dist/esm-types/cli/lib/aiFiles/integration.test.d.ts.map +1 -0
  153. package/dist/esm-types/cli/lib/{ai → aiFiles}/paths.d.ts +4 -0
  154. package/dist/esm-types/cli/lib/aiFiles/paths.d.ts.map +1 -0
  155. package/dist/esm-types/cli/lib/aiFiles/prompt.test.d.ts.map +1 -0
  156. package/dist/esm-types/cli/lib/aiFiles/skills.d.ts +18 -0
  157. package/dist/esm-types/cli/lib/aiFiles/skills.d.ts.map +1 -0
  158. package/dist/esm-types/cli/lib/aiFiles/status.d.ts +3 -0
  159. package/dist/esm-types/cli/lib/aiFiles/status.d.ts.map +1 -0
  160. package/dist/esm-types/cli/lib/aiFiles/utils.d.ts +46 -0
  161. package/dist/esm-types/cli/lib/aiFiles/utils.d.ts.map +1 -0
  162. package/dist/esm-types/cli/lib/config.d.ts +1 -0
  163. package/dist/esm-types/cli/lib/config.d.ts.map +1 -1
  164. package/dist/esm-types/cli/lib/versionApi.d.ts +7 -1
  165. package/dist/esm-types/cli/lib/versionApi.d.ts.map +1 -1
  166. package/dist/esm-types/cli/lib/workos/workos.d.ts.map +1 -1
  167. package/dist/esm-types/index.d.ts +1 -1
  168. package/dist/react.bundle.js +6 -9
  169. package/dist/react.bundle.js.map +2 -2
  170. package/package.json +1 -1
  171. package/schemas/convex.schema.json +7 -1
  172. package/src/browser/sync/authentication_manager.ts +9 -4
  173. package/src/browser/sync/client_node.test.ts +125 -0
  174. package/src/browser/sync/web_socket_manager.ts +1 -7
  175. package/src/cli/aiFiles.ts +20 -27
  176. package/src/cli/configure.ts +17 -11
  177. package/src/cli/deploymentSelection.test.ts +56 -2
  178. package/src/cli/lib/{ai → aiFiles}/MANUAL_TESTING.md +6 -2
  179. package/src/cli/lib/aiFiles/agentsmd.test.ts +133 -0
  180. package/src/cli/lib/aiFiles/agentsmd.ts +77 -0
  181. package/src/cli/lib/aiFiles/claudemd.test.ts +92 -0
  182. package/src/cli/lib/aiFiles/claudemd.ts +77 -0
  183. package/src/cli/lib/{ai → aiFiles}/config.test.ts +181 -59
  184. package/src/cli/lib/{ai → aiFiles}/config.ts +92 -63
  185. package/src/cli/lib/aiFiles/cursorrules.ts +25 -0
  186. package/src/cli/lib/aiFiles/guidelinesmd.test.ts +40 -0
  187. package/src/cli/lib/aiFiles/guidelinesmd.ts +41 -0
  188. package/src/cli/lib/{ai → aiFiles}/index.test.ts +200 -339
  189. package/src/cli/lib/aiFiles/index.ts +303 -0
  190. package/src/cli/lib/{ai → aiFiles}/integration.test.ts +117 -147
  191. package/src/cli/lib/{ai → aiFiles}/paths.ts +5 -0
  192. package/src/cli/lib/{ai → aiFiles}/prompt.test.ts +78 -30
  193. package/src/cli/lib/aiFiles/skills.ts +213 -0
  194. package/src/cli/lib/aiFiles/status.ts +240 -0
  195. package/src/cli/lib/aiFiles/utils.ts +163 -0
  196. package/src/cli/lib/command.ts +6 -1
  197. package/src/cli/lib/config.test.ts +1 -1
  198. package/src/cli/lib/config.ts +6 -5
  199. package/src/cli/lib/localDeployment/anonymous.ts +2 -2
  200. package/src/cli/lib/updates.test.ts +40 -30
  201. package/src/cli/lib/updates.ts +8 -8
  202. package/src/cli/lib/versionApi.test.ts +13 -10
  203. package/src/cli/lib/versionApi.ts +13 -5
  204. package/src/cli/lib/workos/workos.ts +4 -5
  205. package/src/index.ts +1 -1
  206. package/src/values/.claude/settings.local.json +10 -0
  207. package/dist/cjs/cli/lib/ai/config.js.map +0 -7
  208. package/dist/cjs/cli/lib/ai/index.js +0 -704
  209. package/dist/cjs/cli/lib/ai/index.js.map +0 -7
  210. package/dist/cjs/cli/lib/ai/paths.js.map +0 -7
  211. package/dist/cjs-types/cli/lib/ai/config.d.ts +0 -50
  212. package/dist/cjs-types/cli/lib/ai/config.d.ts.map +0 -1
  213. package/dist/cjs-types/cli/lib/ai/config.test.d.ts.map +0 -1
  214. package/dist/cjs-types/cli/lib/ai/index.d.ts +0 -56
  215. package/dist/cjs-types/cli/lib/ai/index.d.ts.map +0 -1
  216. package/dist/cjs-types/cli/lib/ai/index.test.d.ts.map +0 -1
  217. package/dist/cjs-types/cli/lib/ai/integration.test.d.ts.map +0 -1
  218. package/dist/cjs-types/cli/lib/ai/paths.d.ts.map +0 -1
  219. package/dist/cjs-types/cli/lib/ai/prompt.test.d.ts.map +0 -1
  220. package/dist/esm/cli/lib/ai/config.js.map +0 -7
  221. package/dist/esm/cli/lib/ai/index.js +0 -684
  222. package/dist/esm/cli/lib/ai/index.js.map +0 -7
  223. package/dist/esm/cli/lib/ai/paths.js.map +0 -7
  224. package/dist/esm-types/cli/lib/ai/config.d.ts +0 -50
  225. package/dist/esm-types/cli/lib/ai/config.d.ts.map +0 -1
  226. package/dist/esm-types/cli/lib/ai/config.test.d.ts.map +0 -1
  227. package/dist/esm-types/cli/lib/ai/index.d.ts +0 -56
  228. package/dist/esm-types/cli/lib/ai/index.d.ts.map +0 -1
  229. package/dist/esm-types/cli/lib/ai/index.test.d.ts.map +0 -1
  230. package/dist/esm-types/cli/lib/ai/integration.test.d.ts.map +0 -1
  231. package/dist/esm-types/cli/lib/ai/paths.d.ts.map +0 -1
  232. package/dist/esm-types/cli/lib/ai/prompt.test.d.ts.map +0 -1
  233. package/src/cli/lib/ai/index.ts +0 -1006
  234. /package/dist/cjs/cli/lib/{ai → aiFiles}/paths.js +0 -0
  235. /package/dist/cjs-types/cli/lib/{ai → aiFiles}/config.test.d.ts +0 -0
  236. /package/dist/cjs-types/cli/lib/{ai → aiFiles}/index.test.d.ts +0 -0
  237. /package/dist/cjs-types/cli/lib/{ai → aiFiles}/integration.test.d.ts +0 -0
  238. /package/dist/cjs-types/cli/lib/{ai → aiFiles}/prompt.test.d.ts +0 -0
  239. /package/dist/esm/cli/lib/{ai → aiFiles}/paths.js +0 -0
  240. /package/dist/esm-types/cli/lib/{ai → aiFiles}/config.test.d.ts +0 -0
  241. /package/dist/esm-types/cli/lib/{ai → aiFiles}/index.test.d.ts +0 -0
  242. /package/dist/esm-types/cli/lib/{ai → aiFiles}/integration.test.d.ts +0 -0
  243. /package/dist/esm-types/cli/lib/{ai → aiFiles}/prompt.test.d.ts +0 -0
@@ -4,12 +4,12 @@ import os from "os";
4
4
  import path from "path";
5
5
  import {
6
6
  checkAiFilesStaleness,
7
- disableAiFiles,
7
+ safelyAttemptToDisableAiFiles,
8
8
  enableAiFiles,
9
9
  removeAiFiles,
10
- statusAiFiles,
11
- updateAiFiles,
10
+ installAiFiles,
12
11
  } from "./index.js";
12
+ import { statusAiFiles } from "./status.js";
13
13
  import { logMessage } from "../../../bundler/log.js";
14
14
  import { AGENTS_MD_START_MARKER } from "../../codegen_templates/agentsmd.js";
15
15
  import { CLAUDE_MD_START_MARKER } from "../../codegen_templates/claudemd.js";
@@ -22,10 +22,13 @@ vi.mock("../versionApi.js", () => ({
22
22
  downloadGuidelines: vi.fn(async () => "integration guidelines content"),
23
23
  fetchAgentSkillsSha: vi.fn(async () => "integration-sha"),
24
24
  getVersion: vi.fn(async () => ({
25
- message: null,
26
- guidelinesHash: "integration-guidelines-hash",
27
- agentSkillsSha: "integration-agent-skills-sha",
28
- disableSkillsCli: false,
25
+ kind: "ok",
26
+ data: {
27
+ message: null,
28
+ guidelinesHash: "integration-guidelines-hash",
29
+ agentSkillsSha: "integration-agent-skills-sha",
30
+ disableSkillsCli: false,
31
+ },
29
32
  })),
30
33
  }));
31
34
 
@@ -80,7 +83,7 @@ describe("ai-files integration with default convex/ directory", () => {
80
83
  });
81
84
 
82
85
  test("install creates guidelines, state, AGENTS.md, and CLAUDE.md", async () => {
83
- await updateAiFiles(tmpDir, convexDir);
86
+ await installAiFiles({ projectDir: tmpDir, convexDir });
84
87
 
85
88
  expect(fs.existsSync(guidelinesPath())).toBe(true);
86
89
  expect(fs.existsSync(statePath())).toBe(true);
@@ -96,7 +99,7 @@ describe("ai-files integration with default convex/ directory", () => {
96
99
  path.join(tmpDir, "AGENTS.md"),
97
100
  "# My Project\n\nImportant team guidelines here.\n",
98
101
  );
99
- await updateAiFiles(tmpDir, convexDir);
102
+ await installAiFiles({ projectDir: tmpDir, convexDir });
100
103
  const content = fs.readFileSync(path.join(tmpDir, "AGENTS.md"), "utf8");
101
104
  expect(content).toContain("# My Project");
102
105
  expect(content).toContain("Important team guidelines here.");
@@ -111,17 +114,17 @@ describe("ai-files integration with default convex/ directory", () => {
111
114
  path.join(tmpDir, "CLAUDE.md"),
112
115
  "My custom CLAUDE.md content\n",
113
116
  );
114
- await updateAiFiles(tmpDir, convexDir);
117
+ await installAiFiles({ projectDir: tmpDir, convexDir });
115
118
  const content = fs.readFileSync(path.join(tmpDir, "CLAUDE.md"), "utf8");
116
119
  expect(content).toContain("My custom CLAUDE.md content");
117
120
  });
118
121
 
119
122
  test("second update is idempotent", async () => {
120
- await updateAiFiles(tmpDir, convexDir);
123
+ await installAiFiles({ projectDir: tmpDir, convexDir });
121
124
  const firstGuidelines = fs.readFileSync(guidelinesPath(), "utf8");
122
125
  const firstState = fs.readFileSync(statePath(), "utf8");
123
126
 
124
- await updateAiFiles(tmpDir, convexDir);
127
+ await installAiFiles({ projectDir: tmpDir, convexDir });
125
128
 
126
129
  expect(fs.readFileSync(guidelinesPath(), "utf8")).toBe(firstGuidelines);
127
130
  expect(fs.readFileSync(statePath(), "utf8")).toBe(firstState);
@@ -133,36 +136,24 @@ describe("ai-files integration with default convex/ directory", () => {
133
136
  path.join(tmpDir, ".cursor", "rules", "convex_rules.mdc"),
134
137
  "legacy",
135
138
  );
136
- await updateAiFiles(tmpDir, convexDir);
139
+ await installAiFiles({ projectDir: tmpDir, convexDir });
137
140
  expect(
138
141
  fs.existsSync(path.join(tmpDir, ".cursor", "rules", "convex_rules.mdc")),
139
142
  ).toBe(false);
140
143
  });
141
144
 
142
- test("skips locally modified guidelines", async () => {
143
- await updateAiFiles(tmpDir, convexDir);
144
- fs.appendFileSync(guidelinesPath(), "\n## My custom note\n");
145
- const state = readJson(statePath());
146
- state.guidelinesHash = "deliberately-stale-hash";
147
- fs.writeFileSync(statePath(), JSON.stringify(state, null, 2) + "\n");
148
-
149
- await updateAiFiles(tmpDir, convexDir);
150
-
151
- expect(fs.readFileSync(guidelinesPath(), "utf8")).toContain(
152
- "My custom note",
153
- );
154
- expect(vi.mocked(logMessage)).toHaveBeenCalledWith(
155
- expect.stringContaining("modified locally"),
156
- );
157
- });
158
-
159
145
  test("staleness check nags when stored hash is stale", async () => {
160
- await updateAiFiles(tmpDir, convexDir);
146
+ await installAiFiles({ projectDir: tmpDir, convexDir });
161
147
  const state = readJson(statePath());
162
148
  state.guidelinesHash = "deliberately-stale-hash";
163
149
  fs.writeFileSync(statePath(), JSON.stringify(state, null, 2) + "\n");
164
150
 
165
- await checkAiFilesStaleness("canonical-hash", null, tmpDir, convexDir);
151
+ await checkAiFilesStaleness({
152
+ canonicalGuidelinesHash: "canonical-hash",
153
+ canonicalAgentSkillsSha: null,
154
+ projectDir: tmpDir,
155
+ convexDir,
156
+ });
166
157
 
167
158
  expect(vi.mocked(logMessage)).toHaveBeenCalledWith(
168
159
  expect.stringContaining("out of date"),
@@ -170,14 +161,19 @@ describe("ai-files integration with default convex/ directory", () => {
170
161
  });
171
162
 
172
163
  test("staleness check is silent when disabled in convex.json", async () => {
173
- await updateAiFiles(tmpDir, convexDir);
174
- await disableAiFiles(tmpDir);
164
+ await installAiFiles({ projectDir: tmpDir, convexDir });
165
+ await safelyAttemptToDisableAiFiles(tmpDir);
175
166
  const state = readJson(statePath());
176
167
  state.guidelinesHash = "deliberately-stale-hash";
177
168
  fs.writeFileSync(statePath(), JSON.stringify(state, null, 2) + "\n");
178
169
  vi.mocked(logMessage).mockClear();
179
170
 
180
- await checkAiFilesStaleness("canonical-hash", null, tmpDir, convexDir);
171
+ await checkAiFilesStaleness({
172
+ canonicalGuidelinesHash: "canonical-hash",
173
+ canonicalAgentSkillsSha: null,
174
+ projectDir: tmpDir,
175
+ convexDir,
176
+ });
181
177
 
182
178
  const calls = vi.mocked(logMessage).mock.calls.map((c) => c[0]);
183
179
  expect(
@@ -186,40 +182,36 @@ describe("ai-files integration with default convex/ directory", () => {
186
182
  });
187
183
 
188
184
  test("disable keeps files but sets convex.json preference", async () => {
189
- await updateAiFiles(tmpDir, convexDir);
190
- await disableAiFiles(tmpDir);
185
+ await installAiFiles({ projectDir: tmpDir, convexDir });
186
+ await safelyAttemptToDisableAiFiles(tmpDir);
191
187
 
192
- expect(readJson(projectConfigPath()).aiFiles.disableStalenessMessage).toBe(
193
- true,
194
- );
188
+ expect(readJson(projectConfigPath()).aiFiles.enabled).toBe(false);
195
189
  expect(fs.existsSync(guidelinesPath())).toBe(true);
196
190
  expect(fs.existsSync(path.join(tmpDir, "AGENTS.md"))).toBe(true);
197
191
  expect(fs.existsSync(path.join(tmpDir, "CLAUDE.md"))).toBe(true);
198
192
  });
199
193
 
200
194
  test("disable before install writes only convex.json and no AI state file", async () => {
201
- await disableAiFiles(tmpDir);
195
+ await safelyAttemptToDisableAiFiles(tmpDir);
202
196
 
203
- expect(readJson(projectConfigPath()).aiFiles.disableStalenessMessage).toBe(
204
- true,
205
- );
197
+ expect(readJson(projectConfigPath()).aiFiles.enabled).toBe(false);
206
198
  expect(fs.existsSync(statePath())).toBe(false);
207
199
  expect(fs.existsSync(guidelinesPath())).toBe(false);
208
200
  });
209
201
 
210
202
  test("remove deletes ai directory and AGENTS.md managed section", async () => {
211
- await updateAiFiles(tmpDir, convexDir);
212
- await removeAiFiles(tmpDir, convexDir);
203
+ await installAiFiles({ projectDir: tmpDir, convexDir });
204
+ await removeAiFiles({ projectDir: tmpDir, convexDir });
213
205
 
214
206
  expect(fs.existsSync(aiDir())).toBe(false);
215
207
  });
216
208
 
217
209
  test("status reports not installed after remove", async () => {
218
- await updateAiFiles(tmpDir, convexDir);
219
- await removeAiFiles(tmpDir, convexDir);
210
+ await installAiFiles({ projectDir: tmpDir, convexDir });
211
+ await removeAiFiles({ projectDir: tmpDir, convexDir });
220
212
  vi.mocked(logMessage).mockClear();
221
213
 
222
- await statusAiFiles(tmpDir, convexDir);
214
+ await statusAiFiles({ projectDir: tmpDir, convexDir });
223
215
 
224
216
  expect(vi.mocked(logMessage)).toHaveBeenCalledWith(
225
217
  expect.stringContaining("not installed"),
@@ -227,10 +219,10 @@ describe("ai-files integration with default convex/ directory", () => {
227
219
  });
228
220
 
229
221
  test("status reports installed and enabled after install", async () => {
230
- await updateAiFiles(tmpDir, convexDir);
222
+ await installAiFiles({ projectDir: tmpDir, convexDir });
231
223
  vi.mocked(logMessage).mockClear();
232
224
 
233
- await statusAiFiles(tmpDir, convexDir);
225
+ await statusAiFiles({ projectDir: tmpDir, convexDir });
234
226
 
235
227
  expect(vi.mocked(logMessage)).toHaveBeenCalledWith(
236
228
  expect.stringContaining("enabled"),
@@ -238,52 +230,46 @@ describe("ai-files integration with default convex/ directory", () => {
238
230
  });
239
231
 
240
232
  test("disable after CLAUDE.md user edits preserves the file", async () => {
241
- await updateAiFiles(tmpDir, convexDir);
233
+ await installAiFiles({ projectDir: tmpDir, convexDir });
242
234
  fs.appendFileSync(path.join(tmpDir, "CLAUDE.md"), "My custom note\n");
243
- await disableAiFiles(tmpDir);
235
+ await safelyAttemptToDisableAiFiles(tmpDir);
244
236
  expect(fs.readFileSync(path.join(tmpDir, "CLAUDE.md"), "utf8")).toContain(
245
237
  "My custom note",
246
238
  );
247
239
  });
248
240
 
249
241
  test("update recreates missing CLAUDE.md", async () => {
250
- await updateAiFiles(tmpDir, convexDir);
242
+ await installAiFiles({ projectDir: tmpDir, convexDir });
251
243
  fs.rmSync(path.join(tmpDir, "CLAUDE.md"), { force: true });
252
244
 
253
- await updateAiFiles(tmpDir, convexDir);
245
+ await installAiFiles({ projectDir: tmpDir, convexDir });
254
246
 
255
247
  expect(fs.readFileSync(path.join(tmpDir, "CLAUDE.md"), "utf8")).toContain(
256
248
  "convex/_generated/ai/guidelines.md",
257
249
  );
258
250
  });
259
251
 
260
- test("enable clears disableStalenessMessage", async () => {
261
- await updateAiFiles(tmpDir, convexDir);
262
- await disableAiFiles(tmpDir);
263
- expect(readJson(projectConfigPath()).aiFiles.disableStalenessMessage).toBe(
264
- true,
265
- );
252
+ test("enable sets enabled flag to true", async () => {
253
+ await installAiFiles({ projectDir: tmpDir, convexDir });
254
+ await safelyAttemptToDisableAiFiles(tmpDir);
255
+ expect(readJson(projectConfigPath()).aiFiles.enabled).toBe(false);
266
256
 
267
- await enableAiFiles(tmpDir, convexDir);
257
+ await enableAiFiles({ projectDir: tmpDir, convexDir });
268
258
 
269
- expect(readJson(projectConfigPath()).aiFiles.disableStalenessMessage).toBe(
270
- false,
271
- );
259
+ expect(readJson(projectConfigPath()).aiFiles.enabled).toBe(true);
272
260
  });
273
261
 
274
262
  test("full cycle: disable -> remove -> enable reinstalls everything", async () => {
275
- await updateAiFiles(tmpDir, convexDir);
276
- await disableAiFiles(tmpDir);
277
- await removeAiFiles(tmpDir, convexDir);
263
+ await installAiFiles({ projectDir: tmpDir, convexDir });
264
+ await safelyAttemptToDisableAiFiles(tmpDir);
265
+ await removeAiFiles({ projectDir: tmpDir, convexDir });
278
266
  expect(fs.existsSync(aiDir())).toBe(false);
279
267
 
280
- await enableAiFiles(tmpDir, convexDir);
268
+ await enableAiFiles({ projectDir: tmpDir, convexDir });
281
269
 
282
270
  expect(fs.existsSync(guidelinesPath())).toBe(true);
283
271
  expect(fs.existsSync(path.join(tmpDir, "AGENTS.md"))).toBe(true);
284
- expect(readJson(projectConfigPath()).aiFiles.disableStalenessMessage).toBe(
285
- false,
286
- );
272
+ expect(readJson(projectConfigPath()).aiFiles.enabled).toBe(true);
287
273
  });
288
274
 
289
275
  test("remove strips managed section from AGENTS.md but preserves user content", async () => {
@@ -291,11 +277,11 @@ describe("ai-files integration with default convex/ directory", () => {
291
277
  path.join(tmpDir, "AGENTS.md"),
292
278
  "# My Project\n\nTeam guidelines here.\n",
293
279
  );
294
- await updateAiFiles(tmpDir, convexDir);
280
+ await installAiFiles({ projectDir: tmpDir, convexDir });
295
281
  const before = fs.readFileSync(path.join(tmpDir, "AGENTS.md"), "utf8");
296
282
  expect(before).toContain(AGENTS_MD_START_MARKER);
297
283
 
298
- await removeAiFiles(tmpDir, convexDir);
284
+ await removeAiFiles({ projectDir: tmpDir, convexDir });
299
285
 
300
286
  const after = fs.readFileSync(path.join(tmpDir, "AGENTS.md"), "utf8");
301
287
  expect(after).toContain("# My Project");
@@ -304,19 +290,19 @@ describe("ai-files integration with default convex/ directory", () => {
304
290
  });
305
291
 
306
292
  test("remove on AGENTS.md with only Convex content deletes the file", async () => {
307
- await updateAiFiles(tmpDir, convexDir);
293
+ await installAiFiles({ projectDir: tmpDir, convexDir });
308
294
  expect(fs.existsSync(path.join(tmpDir, "AGENTS.md"))).toBe(true);
309
295
 
310
- await removeAiFiles(tmpDir, convexDir);
296
+ await removeAiFiles({ projectDir: tmpDir, convexDir });
311
297
 
312
298
  expect(fs.existsSync(path.join(tmpDir, "AGENTS.md"))).toBe(false);
313
299
  });
314
300
 
315
301
  test("remove deletes CLAUDE.md when empty after stripping managed section", async () => {
316
- await updateAiFiles(tmpDir, convexDir);
302
+ await installAiFiles({ projectDir: tmpDir, convexDir });
317
303
  expect(fs.existsSync(path.join(tmpDir, "CLAUDE.md"))).toBe(true);
318
304
 
319
- await removeAiFiles(tmpDir, convexDir);
305
+ await removeAiFiles({ projectDir: tmpDir, convexDir });
320
306
 
321
307
  expect(fs.existsSync(path.join(tmpDir, "CLAUDE.md"))).toBe(false);
322
308
  });
@@ -326,11 +312,11 @@ describe("ai-files integration with default convex/ directory", () => {
326
312
  path.join(tmpDir, "CLAUDE.md"),
327
313
  "My project-specific Claude instructions\n",
328
314
  );
329
- await updateAiFiles(tmpDir, convexDir);
315
+ await installAiFiles({ projectDir: tmpDir, convexDir });
330
316
  const before = fs.readFileSync(path.join(tmpDir, "CLAUDE.md"), "utf8");
331
317
  expect(before).toContain(CLAUDE_MD_START_MARKER);
332
318
 
333
- await removeAiFiles(tmpDir, convexDir);
319
+ await removeAiFiles({ projectDir: tmpDir, convexDir });
334
320
 
335
321
  const after = fs.readFileSync(path.join(tmpDir, "CLAUDE.md"), "utf8");
336
322
  expect(after).toContain("My project-specific Claude instructions");
@@ -340,7 +326,12 @@ describe("ai-files integration with default convex/ directory", () => {
340
326
  test("checkAiFilesStaleness nags when no state file exists", async () => {
341
327
  vi.mocked(logMessage).mockClear();
342
328
 
343
- await checkAiFilesStaleness(null, null, tmpDir, convexDir);
329
+ await checkAiFilesStaleness({
330
+ canonicalGuidelinesHash: null,
331
+ canonicalAgentSkillsSha: null,
332
+ projectDir: tmpDir,
333
+ convexDir,
334
+ });
344
335
 
345
336
  expect(vi.mocked(logMessage)).toHaveBeenCalledWith(
346
337
  expect.stringContaining("not installed"),
@@ -348,16 +339,16 @@ describe("ai-files integration with default convex/ directory", () => {
348
339
  });
349
340
 
350
341
  test("checkAiFilesStaleness is silent when hashes match", async () => {
351
- await updateAiFiles(tmpDir, convexDir);
342
+ await installAiFiles({ projectDir: tmpDir, convexDir });
352
343
  const state = readJson(statePath());
353
344
  vi.mocked(logMessage).mockClear();
354
345
 
355
- await checkAiFilesStaleness(
356
- state.guidelinesHash,
357
- state.agentSkillsSha,
358
- tmpDir,
346
+ await checkAiFilesStaleness({
347
+ canonicalGuidelinesHash: state.guidelinesHash,
348
+ canonicalAgentSkillsSha: state.agentSkillsSha,
349
+ projectDir: tmpDir,
359
350
  convexDir,
360
- );
351
+ });
361
352
 
362
353
  const calls = vi.mocked(logMessage).mock.calls.map((c) => c[0]);
363
354
  expect(
@@ -369,9 +360,9 @@ describe("ai-files integration with default convex/ directory", () => {
369
360
  });
370
361
 
371
362
  test("AGENTS.md managed section is replaced not duplicated on repeated updates", async () => {
372
- await updateAiFiles(tmpDir, convexDir);
373
- await updateAiFiles(tmpDir, convexDir);
374
- await updateAiFiles(tmpDir, convexDir);
363
+ await installAiFiles({ projectDir: tmpDir, convexDir });
364
+ await installAiFiles({ projectDir: tmpDir, convexDir });
365
+ await installAiFiles({ projectDir: tmpDir, convexDir });
375
366
 
376
367
  const content = fs.readFileSync(path.join(tmpDir, "AGENTS.md"), "utf8");
377
368
  const markerCount = content.split(AGENTS_MD_START_MARKER).length - 1;
@@ -379,11 +370,11 @@ describe("ai-files integration with default convex/ directory", () => {
379
370
  });
380
371
 
381
372
  test("status reports disabled state after disable", async () => {
382
- await updateAiFiles(tmpDir, convexDir);
383
- await disableAiFiles(tmpDir);
373
+ await installAiFiles({ projectDir: tmpDir, convexDir });
374
+ await safelyAttemptToDisableAiFiles(tmpDir);
384
375
  vi.mocked(logMessage).mockClear();
385
376
 
386
- await statusAiFiles(tmpDir, convexDir);
377
+ await statusAiFiles({ projectDir: tmpDir, convexDir });
387
378
 
388
379
  expect(vi.mocked(logMessage)).toHaveBeenCalledWith(
389
380
  expect.stringContaining("disabled"),
@@ -421,7 +412,7 @@ describe("ai-files integration with functions directory override", () => {
421
412
  });
422
413
 
423
414
  test("installs into overridden functions directory, not default convex/", async () => {
424
- await updateAiFiles(tmpDir, convexDir);
415
+ await installAiFiles({ projectDir: tmpDir, convexDir });
425
416
 
426
417
  expect(fs.existsSync(guidelinesPath())).toBe(true);
427
418
  expect(fs.existsSync(statePath())).toBe(true);
@@ -440,7 +431,7 @@ describe("ai-files integration with functions directory override", () => {
440
431
  path.join(tmpDir, "AGENTS.md"),
441
432
  "# Existing\n\nUser content.\n",
442
433
  );
443
- await updateAiFiles(tmpDir, convexDir);
434
+ await installAiFiles({ projectDir: tmpDir, convexDir });
444
435
  const content = fs.readFileSync(path.join(tmpDir, "AGENTS.md"), "utf8");
445
436
  expect(content).toContain("# Existing");
446
437
  expect(content).toContain("User content.");
@@ -456,17 +447,17 @@ describe("ai-files integration with functions directory override", () => {
456
447
  "My custom CLAUDE.md content\n",
457
448
  "utf8",
458
449
  );
459
- await updateAiFiles(tmpDir, convexDir);
450
+ await installAiFiles({ projectDir: tmpDir, convexDir });
460
451
  const content = fs.readFileSync(path.join(tmpDir, "CLAUDE.md"), "utf8");
461
452
  expect(content).toContain("My custom CLAUDE.md content");
462
453
  });
463
454
 
464
455
  test("second update is idempotent", async () => {
465
- await updateAiFiles(tmpDir, convexDir);
456
+ await installAiFiles({ projectDir: tmpDir, convexDir });
466
457
  const firstGuidelines = fs.readFileSync(guidelinesPath(), "utf8");
467
458
  const firstState = fs.readFileSync(statePath(), "utf8");
468
459
 
469
- await updateAiFiles(tmpDir, convexDir);
460
+ await installAiFiles({ projectDir: tmpDir, convexDir });
470
461
 
471
462
  expect(fs.readFileSync(guidelinesPath(), "utf8")).toBe(firstGuidelines);
472
463
  expect(fs.readFileSync(statePath(), "utf8")).toBe(firstState);
@@ -479,36 +470,14 @@ describe("ai-files integration with functions directory override", () => {
479
470
  "legacy",
480
471
  "utf8",
481
472
  );
482
- await updateAiFiles(tmpDir, convexDir);
473
+ await installAiFiles({ projectDir: tmpDir, convexDir });
483
474
  expect(
484
475
  fs.existsSync(path.join(tmpDir, ".cursor", "rules", "convex_rules.mdc")),
485
476
  ).toBe(false);
486
477
  });
487
478
 
488
- test("skips locally modified guidelines when stored hash is stale", async () => {
489
- await updateAiFiles(tmpDir, convexDir);
490
- const localNote = "\n## My custom note\n";
491
- fs.appendFileSync(guidelinesPath(), localNote, "utf8");
492
- const state = readJson(statePath());
493
- state.guidelinesHash = "deliberately-stale-hash";
494
- fs.writeFileSync(
495
- statePath(),
496
- JSON.stringify(state, null, 2) + "\n",
497
- "utf8",
498
- );
499
-
500
- await updateAiFiles(tmpDir, convexDir);
501
-
502
- expect(fs.readFileSync(guidelinesPath(), "utf8")).toContain(
503
- localNote.trim(),
504
- );
505
- expect(vi.mocked(logMessage)).toHaveBeenCalledWith(
506
- expect.stringContaining("modified locally"),
507
- );
508
- });
509
-
510
479
  test("staleness check logs update nag for stale stored hash", async () => {
511
- await updateAiFiles(tmpDir, convexDir);
480
+ await installAiFiles({ projectDir: tmpDir, convexDir });
512
481
  const state = readJson(statePath());
513
482
  state.guidelinesHash = "deliberately-stale-hash";
514
483
  fs.writeFileSync(
@@ -517,7 +486,12 @@ describe("ai-files integration with functions directory override", () => {
517
486
  "utf8",
518
487
  );
519
488
 
520
- await checkAiFilesStaleness("canonical-hash", null, tmpDir, convexDir);
489
+ await checkAiFilesStaleness({
490
+ canonicalGuidelinesHash: "canonical-hash",
491
+ canonicalAgentSkillsSha: null,
492
+ projectDir: tmpDir,
493
+ convexDir,
494
+ });
521
495
 
522
496
  expect(vi.mocked(logMessage)).toHaveBeenCalledWith(
523
497
  expect.stringContaining("out of date"),
@@ -525,21 +499,19 @@ describe("ai-files integration with functions directory override", () => {
525
499
  });
526
500
 
527
501
  test("disable sets convex.json preference and keeps files", async () => {
528
- await updateAiFiles(tmpDir, convexDir);
529
- await disableAiFiles(tmpDir);
502
+ await installAiFiles({ projectDir: tmpDir, convexDir });
503
+ await safelyAttemptToDisableAiFiles(tmpDir);
530
504
 
531
- expect(readJson(projectConfigPath()).aiFiles.disableStalenessMessage).toBe(
532
- true,
533
- );
505
+ expect(readJson(projectConfigPath()).aiFiles.enabled).toBe(false);
534
506
  expect(fs.existsSync(guidelinesPath())).toBe(true);
535
507
  expect(fs.existsSync(path.join(tmpDir, "AGENTS.md"))).toBe(true);
536
508
  expect(fs.existsSync(path.join(tmpDir, "CLAUDE.md"))).toBe(true);
537
509
  });
538
510
 
539
511
  test("remove deletes files and status reports not installed", async () => {
540
- await updateAiFiles(tmpDir, convexDir);
541
- await removeAiFiles(tmpDir, convexDir);
542
- await statusAiFiles(tmpDir, convexDir);
512
+ await installAiFiles({ projectDir: tmpDir, convexDir });
513
+ await removeAiFiles({ projectDir: tmpDir, convexDir });
514
+ await statusAiFiles({ projectDir: tmpDir, convexDir });
543
515
 
544
516
  expect(fs.existsSync(aiDir())).toBe(false);
545
517
  expect(vi.mocked(logMessage)).toHaveBeenCalledWith(
@@ -548,23 +520,23 @@ describe("ai-files integration with functions directory override", () => {
548
520
  });
549
521
 
550
522
  test("disable after CLAUDE.md user edits preserves file", async () => {
551
- await updateAiFiles(tmpDir, convexDir);
523
+ await installAiFiles({ projectDir: tmpDir, convexDir });
552
524
  fs.appendFileSync(
553
525
  path.join(tmpDir, "CLAUDE.md"),
554
526
  "My custom note\n",
555
527
  "utf8",
556
528
  );
557
- await disableAiFiles(tmpDir);
529
+ await safelyAttemptToDisableAiFiles(tmpDir);
558
530
  expect(fs.readFileSync(path.join(tmpDir, "CLAUDE.md"), "utf8")).toContain(
559
531
  "My custom note",
560
532
  );
561
533
  });
562
534
 
563
535
  test("update recreates missing CLAUDE.md", async () => {
564
- await updateAiFiles(tmpDir, convexDir);
536
+ await installAiFiles({ projectDir: tmpDir, convexDir });
565
537
  fs.rmSync(path.join(tmpDir, "CLAUDE.md"), { force: true });
566
538
 
567
- await updateAiFiles(tmpDir, convexDir);
539
+ await installAiFiles({ projectDir: tmpDir, convexDir });
568
540
 
569
541
  const content = fs.readFileSync(path.join(tmpDir, "CLAUDE.md"), "utf8");
570
542
  expect(content).toMatch(
@@ -572,30 +544,28 @@ describe("ai-files integration with functions directory override", () => {
572
544
  );
573
545
  });
574
546
 
575
- test("enable clears disableStalenessMessage and re-enables status", async () => {
576
- await updateAiFiles(tmpDir, convexDir);
577
- await disableAiFiles(tmpDir);
578
- await enableAiFiles(tmpDir, convexDir);
579
- await statusAiFiles(tmpDir, convexDir);
547
+ test("enable sets enabled flag to true and re-enables status", async () => {
548
+ await installAiFiles({ projectDir: tmpDir, convexDir });
549
+ await safelyAttemptToDisableAiFiles(tmpDir);
550
+ await enableAiFiles({ projectDir: tmpDir, convexDir });
551
+ await statusAiFiles({ projectDir: tmpDir, convexDir });
580
552
 
581
- expect(readJson(projectConfigPath()).aiFiles.disableStalenessMessage).toBe(
582
- false,
583
- );
553
+ expect(readJson(projectConfigPath()).aiFiles.enabled).toBe(true);
584
554
  expect(vi.mocked(logMessage)).toHaveBeenCalledWith(
585
555
  expect.stringContaining("enabled"),
586
556
  );
587
557
  });
588
558
 
589
559
  test("disable + remove + enable works with overridden functions directory", async () => {
590
- await updateAiFiles(tmpDir, convexDir);
591
- await disableAiFiles(tmpDir);
592
- await removeAiFiles(tmpDir, convexDir);
560
+ await installAiFiles({ projectDir: tmpDir, convexDir });
561
+ await safelyAttemptToDisableAiFiles(tmpDir);
562
+ await removeAiFiles({ projectDir: tmpDir, convexDir });
593
563
 
594
564
  expect(
595
565
  fs.existsSync(path.join(tmpDir, "src", "convex", "_generated", "ai")),
596
566
  ).toBe(false);
597
567
 
598
- await enableAiFiles(tmpDir, convexDir);
568
+ await enableAiFiles({ projectDir: tmpDir, convexDir });
599
569
 
600
570
  expect(fs.existsSync(guidelinesPath())).toBe(true);
601
571
  });
@@ -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