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.
- package/CHANGELOG.md +12 -0
- package/dist/browser.bundle.js +6 -9
- package/dist/browser.bundle.js.map +2 -2
- package/dist/cjs/browser/sync/authentication_manager.js +4 -1
- package/dist/cjs/browser/sync/authentication_manager.js.map +2 -2
- package/dist/cjs/browser/sync/web_socket_manager.js +1 -7
- package/dist/cjs/browser/sync/web_socket_manager.js.map +2 -2
- package/dist/cjs/cli/aiFiles.js +15 -14
- package/dist/cjs/cli/aiFiles.js.map +2 -2
- package/dist/cjs/cli/configure.js +15 -10
- package/dist/cjs/cli/configure.js.map +2 -2
- package/dist/cjs/cli/lib/aiFiles/agentsmd.js +69 -0
- package/dist/cjs/cli/lib/aiFiles/agentsmd.js.map +7 -0
- package/dist/cjs/cli/lib/aiFiles/claudemd.js +69 -0
- package/dist/cjs/cli/lib/aiFiles/claudemd.js.map +7 -0
- package/dist/cjs/cli/lib/{ai → aiFiles}/config.js +73 -46
- package/dist/cjs/cli/lib/aiFiles/config.js.map +7 -0
- package/dist/cjs/cli/lib/aiFiles/cursorrules.js +48 -0
- package/dist/cjs/cli/lib/aiFiles/cursorrules.js.map +7 -0
- package/dist/cjs/cli/lib/aiFiles/guidelinesmd.js +51 -0
- package/dist/cjs/cli/lib/aiFiles/guidelinesmd.js.map +7 -0
- package/dist/cjs/cli/lib/aiFiles/index.js +231 -0
- package/dist/cjs/cli/lib/aiFiles/index.js.map +7 -0
- package/dist/cjs/cli/lib/aiFiles/paths.js.map +7 -0
- package/dist/cjs/cli/lib/aiFiles/skills.js +180 -0
- package/dist/cjs/cli/lib/aiFiles/skills.js.map +7 -0
- package/dist/cjs/cli/lib/aiFiles/status.js +195 -0
- package/dist/cjs/cli/lib/aiFiles/status.js.map +7 -0
- package/dist/cjs/cli/lib/aiFiles/utils.js +111 -0
- package/dist/cjs/cli/lib/aiFiles/utils.js.map +7 -0
- package/dist/cjs/cli/lib/command.js +6 -1
- package/dist/cjs/cli/lib/command.js.map +2 -2
- package/dist/cjs/cli/lib/config.js +3 -4
- package/dist/cjs/cli/lib/config.js.map +2 -2
- package/dist/cjs/cli/lib/localDeployment/anonymous.js +2 -2
- package/dist/cjs/cli/lib/localDeployment/anonymous.js.map +2 -2
- package/dist/cjs/cli/lib/updates.js +8 -8
- package/dist/cjs/cli/lib/updates.js.map +2 -2
- package/dist/cjs/cli/lib/versionApi.js +7 -4
- package/dist/cjs/cli/lib/versionApi.js.map +2 -2
- package/dist/cjs/cli/lib/workos/workos.js +4 -6
- package/dist/cjs/cli/lib/workos/workos.js.map +2 -2
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs-types/browser/sync/authentication_manager.d.ts.map +1 -1
- package/dist/cjs-types/browser/sync/web_socket_manager.d.ts.map +1 -1
- package/dist/cjs-types/cli/aiFiles.d.ts.map +1 -1
- package/dist/cjs-types/cli/configure.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/aiFiles/agentsmd.d.ts +19 -0
- package/dist/cjs-types/cli/lib/aiFiles/agentsmd.d.ts.map +1 -0
- package/dist/cjs-types/cli/lib/aiFiles/agentsmd.test.d.ts +2 -0
- package/dist/cjs-types/cli/lib/aiFiles/agentsmd.test.d.ts.map +1 -0
- package/dist/cjs-types/cli/lib/aiFiles/claudemd.d.ts +19 -0
- package/dist/cjs-types/cli/lib/aiFiles/claudemd.d.ts.map +1 -0
- package/dist/cjs-types/cli/lib/aiFiles/claudemd.test.d.ts +2 -0
- package/dist/cjs-types/cli/lib/aiFiles/claudemd.test.d.ts.map +1 -0
- package/dist/cjs-types/cli/lib/aiFiles/config.d.ts +46 -0
- package/dist/cjs-types/cli/lib/aiFiles/config.d.ts.map +1 -0
- package/dist/cjs-types/cli/lib/aiFiles/config.test.d.ts.map +1 -0
- package/dist/cjs-types/cli/lib/aiFiles/cursorrules.d.ts +10 -0
- package/dist/cjs-types/cli/lib/aiFiles/cursorrules.d.ts.map +1 -0
- package/dist/cjs-types/cli/lib/aiFiles/guidelinesmd.d.ts +12 -0
- package/dist/cjs-types/cli/lib/aiFiles/guidelinesmd.d.ts.map +1 -0
- package/dist/cjs-types/cli/lib/aiFiles/guidelinesmd.test.d.ts +2 -0
- package/dist/cjs-types/cli/lib/aiFiles/guidelinesmd.test.d.ts.map +1 -0
- package/dist/cjs-types/cli/lib/aiFiles/index.d.ts +40 -0
- package/dist/cjs-types/cli/lib/aiFiles/index.d.ts.map +1 -0
- package/dist/cjs-types/cli/lib/aiFiles/index.test.d.ts.map +1 -0
- package/dist/cjs-types/cli/lib/aiFiles/integration.test.d.ts.map +1 -0
- package/dist/cjs-types/cli/lib/{ai → aiFiles}/paths.d.ts +4 -0
- package/dist/cjs-types/cli/lib/aiFiles/paths.d.ts.map +1 -0
- package/dist/cjs-types/cli/lib/aiFiles/prompt.test.d.ts.map +1 -0
- package/dist/cjs-types/cli/lib/aiFiles/skills.d.ts +18 -0
- package/dist/cjs-types/cli/lib/aiFiles/skills.d.ts.map +1 -0
- package/dist/cjs-types/cli/lib/aiFiles/status.d.ts +3 -0
- package/dist/cjs-types/cli/lib/aiFiles/status.d.ts.map +1 -0
- package/dist/cjs-types/cli/lib/aiFiles/utils.d.ts +46 -0
- package/dist/cjs-types/cli/lib/aiFiles/utils.d.ts.map +1 -0
- package/dist/cjs-types/cli/lib/config.d.ts +1 -0
- package/dist/cjs-types/cli/lib/config.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/versionApi.d.ts +7 -1
- package/dist/cjs-types/cli/lib/versionApi.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/workos/workos.d.ts.map +1 -1
- package/dist/cjs-types/index.d.ts +1 -1
- package/dist/cli.bundle.cjs +1605 -1548
- package/dist/cli.bundle.cjs.map +4 -4
- package/dist/esm/browser/sync/authentication_manager.js +4 -1
- package/dist/esm/browser/sync/authentication_manager.js.map +2 -2
- package/dist/esm/browser/sync/web_socket_manager.js +1 -7
- package/dist/esm/browser/sync/web_socket_manager.js.map +2 -2
- package/dist/esm/cli/aiFiles.js +17 -17
- package/dist/esm/cli/aiFiles.js.map +2 -2
- package/dist/esm/cli/configure.js +15 -10
- package/dist/esm/cli/configure.js.map +2 -2
- package/dist/esm/cli/lib/aiFiles/agentsmd.js +52 -0
- package/dist/esm/cli/lib/aiFiles/agentsmd.js.map +7 -0
- package/dist/esm/cli/lib/aiFiles/claudemd.js +52 -0
- package/dist/esm/cli/lib/aiFiles/claudemd.js.map +7 -0
- package/dist/esm/cli/lib/{ai → aiFiles}/config.js +71 -45
- package/dist/esm/cli/lib/aiFiles/config.js.map +7 -0
- package/dist/esm/cli/lib/aiFiles/cursorrules.js +16 -0
- package/dist/esm/cli/lib/aiFiles/cursorrules.js.map +7 -0
- package/dist/esm/cli/lib/aiFiles/guidelinesmd.js +28 -0
- package/dist/esm/cli/lib/aiFiles/guidelinesmd.js.map +7 -0
- package/dist/esm/cli/lib/aiFiles/index.js +210 -0
- package/dist/esm/cli/lib/aiFiles/index.js.map +7 -0
- package/dist/esm/cli/lib/aiFiles/paths.js.map +7 -0
- package/dist/esm/cli/lib/aiFiles/skills.js +147 -0
- package/dist/esm/cli/lib/aiFiles/skills.js.map +7 -0
- package/dist/esm/cli/lib/aiFiles/status.js +175 -0
- package/dist/esm/cli/lib/aiFiles/status.js.map +7 -0
- package/dist/esm/cli/lib/aiFiles/utils.js +82 -0
- package/dist/esm/cli/lib/aiFiles/utils.js.map +7 -0
- package/dist/esm/cli/lib/command.js +6 -1
- package/dist/esm/cli/lib/command.js.map +2 -2
- package/dist/esm/cli/lib/config.js +3 -4
- package/dist/esm/cli/lib/config.js.map +2 -2
- package/dist/esm/cli/lib/localDeployment/anonymous.js +2 -2
- package/dist/esm/cli/lib/localDeployment/anonymous.js.map +2 -2
- package/dist/esm/cli/lib/updates.js +8 -8
- package/dist/esm/cli/lib/updates.js.map +2 -2
- package/dist/esm/cli/lib/versionApi.js +7 -4
- package/dist/esm/cli/lib/versionApi.js.map +2 -2
- package/dist/esm/cli/lib/workos/workos.js +4 -6
- package/dist/esm/cli/lib/workos/workos.js.map +2 -2
- package/dist/esm/index.js +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm-types/browser/sync/authentication_manager.d.ts.map +1 -1
- package/dist/esm-types/browser/sync/web_socket_manager.d.ts.map +1 -1
- package/dist/esm-types/cli/aiFiles.d.ts.map +1 -1
- package/dist/esm-types/cli/configure.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/aiFiles/agentsmd.d.ts +19 -0
- package/dist/esm-types/cli/lib/aiFiles/agentsmd.d.ts.map +1 -0
- package/dist/esm-types/cli/lib/aiFiles/agentsmd.test.d.ts +2 -0
- package/dist/esm-types/cli/lib/aiFiles/agentsmd.test.d.ts.map +1 -0
- package/dist/esm-types/cli/lib/aiFiles/claudemd.d.ts +19 -0
- package/dist/esm-types/cli/lib/aiFiles/claudemd.d.ts.map +1 -0
- package/dist/esm-types/cli/lib/aiFiles/claudemd.test.d.ts +2 -0
- package/dist/esm-types/cli/lib/aiFiles/claudemd.test.d.ts.map +1 -0
- package/dist/esm-types/cli/lib/aiFiles/config.d.ts +46 -0
- package/dist/esm-types/cli/lib/aiFiles/config.d.ts.map +1 -0
- package/dist/esm-types/cli/lib/aiFiles/config.test.d.ts.map +1 -0
- package/dist/esm-types/cli/lib/aiFiles/cursorrules.d.ts +10 -0
- package/dist/esm-types/cli/lib/aiFiles/cursorrules.d.ts.map +1 -0
- package/dist/esm-types/cli/lib/aiFiles/guidelinesmd.d.ts +12 -0
- package/dist/esm-types/cli/lib/aiFiles/guidelinesmd.d.ts.map +1 -0
- package/dist/esm-types/cli/lib/aiFiles/guidelinesmd.test.d.ts +2 -0
- package/dist/esm-types/cli/lib/aiFiles/guidelinesmd.test.d.ts.map +1 -0
- package/dist/esm-types/cli/lib/aiFiles/index.d.ts +40 -0
- package/dist/esm-types/cli/lib/aiFiles/index.d.ts.map +1 -0
- package/dist/esm-types/cli/lib/aiFiles/index.test.d.ts.map +1 -0
- package/dist/esm-types/cli/lib/aiFiles/integration.test.d.ts.map +1 -0
- package/dist/esm-types/cli/lib/{ai → aiFiles}/paths.d.ts +4 -0
- package/dist/esm-types/cli/lib/aiFiles/paths.d.ts.map +1 -0
- package/dist/esm-types/cli/lib/aiFiles/prompt.test.d.ts.map +1 -0
- package/dist/esm-types/cli/lib/aiFiles/skills.d.ts +18 -0
- package/dist/esm-types/cli/lib/aiFiles/skills.d.ts.map +1 -0
- package/dist/esm-types/cli/lib/aiFiles/status.d.ts +3 -0
- package/dist/esm-types/cli/lib/aiFiles/status.d.ts.map +1 -0
- package/dist/esm-types/cli/lib/aiFiles/utils.d.ts +46 -0
- package/dist/esm-types/cli/lib/aiFiles/utils.d.ts.map +1 -0
- package/dist/esm-types/cli/lib/config.d.ts +1 -0
- package/dist/esm-types/cli/lib/config.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/versionApi.d.ts +7 -1
- package/dist/esm-types/cli/lib/versionApi.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/workos/workos.d.ts.map +1 -1
- package/dist/esm-types/index.d.ts +1 -1
- package/dist/react.bundle.js +6 -9
- package/dist/react.bundle.js.map +2 -2
- package/package.json +1 -1
- package/schemas/convex.schema.json +7 -1
- package/src/browser/sync/authentication_manager.ts +9 -4
- package/src/browser/sync/client_node.test.ts +125 -0
- package/src/browser/sync/web_socket_manager.ts +1 -7
- package/src/cli/aiFiles.ts +20 -27
- package/src/cli/configure.ts +17 -11
- package/src/cli/deploymentSelection.test.ts +56 -2
- package/src/cli/lib/{ai → aiFiles}/MANUAL_TESTING.md +6 -2
- package/src/cli/lib/aiFiles/agentsmd.test.ts +133 -0
- package/src/cli/lib/aiFiles/agentsmd.ts +77 -0
- package/src/cli/lib/aiFiles/claudemd.test.ts +92 -0
- package/src/cli/lib/aiFiles/claudemd.ts +77 -0
- package/src/cli/lib/{ai → aiFiles}/config.test.ts +181 -59
- package/src/cli/lib/{ai → aiFiles}/config.ts +92 -63
- package/src/cli/lib/aiFiles/cursorrules.ts +25 -0
- package/src/cli/lib/aiFiles/guidelinesmd.test.ts +40 -0
- package/src/cli/lib/aiFiles/guidelinesmd.ts +41 -0
- package/src/cli/lib/{ai → aiFiles}/index.test.ts +200 -339
- package/src/cli/lib/aiFiles/index.ts +303 -0
- package/src/cli/lib/{ai → aiFiles}/integration.test.ts +117 -147
- package/src/cli/lib/{ai → aiFiles}/paths.ts +5 -0
- package/src/cli/lib/{ai → aiFiles}/prompt.test.ts +78 -30
- package/src/cli/lib/aiFiles/skills.ts +213 -0
- package/src/cli/lib/aiFiles/status.ts +240 -0
- package/src/cli/lib/aiFiles/utils.ts +163 -0
- package/src/cli/lib/command.ts +6 -1
- package/src/cli/lib/config.test.ts +1 -1
- package/src/cli/lib/config.ts +6 -5
- package/src/cli/lib/localDeployment/anonymous.ts +2 -2
- package/src/cli/lib/updates.test.ts +40 -30
- package/src/cli/lib/updates.ts +8 -8
- package/src/cli/lib/versionApi.test.ts +13 -10
- package/src/cli/lib/versionApi.ts +13 -5
- package/src/cli/lib/workos/workos.ts +4 -5
- package/src/index.ts +1 -1
- package/src/values/.claude/settings.local.json +10 -0
- package/dist/cjs/cli/lib/ai/config.js.map +0 -7
- package/dist/cjs/cli/lib/ai/index.js +0 -704
- package/dist/cjs/cli/lib/ai/index.js.map +0 -7
- package/dist/cjs/cli/lib/ai/paths.js.map +0 -7
- package/dist/cjs-types/cli/lib/ai/config.d.ts +0 -50
- package/dist/cjs-types/cli/lib/ai/config.d.ts.map +0 -1
- package/dist/cjs-types/cli/lib/ai/config.test.d.ts.map +0 -1
- package/dist/cjs-types/cli/lib/ai/index.d.ts +0 -56
- package/dist/cjs-types/cli/lib/ai/index.d.ts.map +0 -1
- package/dist/cjs-types/cli/lib/ai/index.test.d.ts.map +0 -1
- package/dist/cjs-types/cli/lib/ai/integration.test.d.ts.map +0 -1
- package/dist/cjs-types/cli/lib/ai/paths.d.ts.map +0 -1
- package/dist/cjs-types/cli/lib/ai/prompt.test.d.ts.map +0 -1
- package/dist/esm/cli/lib/ai/config.js.map +0 -7
- package/dist/esm/cli/lib/ai/index.js +0 -684
- package/dist/esm/cli/lib/ai/index.js.map +0 -7
- package/dist/esm/cli/lib/ai/paths.js.map +0 -7
- package/dist/esm-types/cli/lib/ai/config.d.ts +0 -50
- package/dist/esm-types/cli/lib/ai/config.d.ts.map +0 -1
- package/dist/esm-types/cli/lib/ai/config.test.d.ts.map +0 -1
- package/dist/esm-types/cli/lib/ai/index.d.ts +0 -56
- package/dist/esm-types/cli/lib/ai/index.d.ts.map +0 -1
- package/dist/esm-types/cli/lib/ai/index.test.d.ts.map +0 -1
- package/dist/esm-types/cli/lib/ai/integration.test.d.ts.map +0 -1
- package/dist/esm-types/cli/lib/ai/paths.d.ts.map +0 -1
- package/dist/esm-types/cli/lib/ai/prompt.test.d.ts.map +0 -1
- package/src/cli/lib/ai/index.ts +0 -1006
- /package/dist/cjs/cli/lib/{ai → aiFiles}/paths.js +0 -0
- /package/dist/cjs-types/cli/lib/{ai → aiFiles}/config.test.d.ts +0 -0
- /package/dist/cjs-types/cli/lib/{ai → aiFiles}/index.test.d.ts +0 -0
- /package/dist/cjs-types/cli/lib/{ai → aiFiles}/integration.test.d.ts +0 -0
- /package/dist/cjs-types/cli/lib/{ai → aiFiles}/prompt.test.d.ts +0 -0
- /package/dist/esm/cli/lib/{ai → aiFiles}/paths.js +0 -0
- /package/dist/esm-types/cli/lib/{ai → aiFiles}/config.test.d.ts +0 -0
- /package/dist/esm-types/cli/lib/{ai → aiFiles}/index.test.d.ts +0 -0
- /package/dist/esm-types/cli/lib/{ai → aiFiles}/integration.test.d.ts +0 -0
- /package/dist/esm-types/cli/lib/{ai → aiFiles}/prompt.test.d.ts +0 -0
|
@@ -6,8 +6,9 @@ import { promises as fs } from "fs";
|
|
|
6
6
|
import path from "path";
|
|
7
7
|
import { z } from "zod";
|
|
8
8
|
import { aiFilesStatePathForConvexDir } from "./paths.js";
|
|
9
|
+
import { iife, readFileSafe } from "./utils.js";
|
|
9
10
|
|
|
10
|
-
const aiFilesStateSchema = z.object({
|
|
11
|
+
export const aiFilesStateSchema = z.object({
|
|
11
12
|
guidelinesHash: z.string().nullable(),
|
|
12
13
|
agentsMdSectionHash: z.string().nullable(),
|
|
13
14
|
claudeMdHash: z.string().nullable(),
|
|
@@ -23,17 +24,21 @@ const aiFilesProjectConfigSchema = z
|
|
|
23
24
|
.object({
|
|
24
25
|
aiFiles: z
|
|
25
26
|
.object({
|
|
26
|
-
|
|
27
|
+
// `enabled` is the canonical field. When present it takes full
|
|
28
|
+
// precedence - `enabled: true` will re-enable even if the legacy
|
|
29
|
+
// disableStalenessMessage field is still `true` in the file.
|
|
30
|
+
enabled: z.boolean().optional(),
|
|
31
|
+
// @deprecated - use `enabled` instead. Read for backward compat;
|
|
32
|
+
// new writes always emit `enabled` and drop this key.
|
|
33
|
+
disableStalenessMessage: z.boolean().optional(),
|
|
27
34
|
})
|
|
28
|
-
.default({
|
|
35
|
+
.default({}),
|
|
29
36
|
})
|
|
30
37
|
.passthrough();
|
|
31
38
|
|
|
32
|
-
export const aiFilesSchema = aiFilesStateSchema;
|
|
33
|
-
|
|
34
39
|
type AiFilesState = z.infer<typeof aiFilesStateSchema>;
|
|
35
40
|
export type AiFilesConfig = AiFilesState & {
|
|
36
|
-
|
|
41
|
+
enabled: boolean;
|
|
37
42
|
};
|
|
38
43
|
|
|
39
44
|
const EMPTY_AI_STATE: AiFilesState = {
|
|
@@ -44,35 +49,38 @@ const EMPTY_AI_STATE: AiFilesState = {
|
|
|
44
49
|
installedSkillNames: [],
|
|
45
50
|
};
|
|
46
51
|
|
|
47
|
-
async function
|
|
52
|
+
async function readAiEnabledFromProjectConfig(
|
|
48
53
|
projectDir: string,
|
|
49
54
|
): Promise<boolean> {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
raw = await fs.readFile(path.join(projectDir, "convex.json"), "utf8");
|
|
53
|
-
} catch {
|
|
54
|
-
return false;
|
|
55
|
-
}
|
|
55
|
+
const raw = await readFileSafe(path.join(projectDir, "convex.json"));
|
|
56
|
+
if (raw === null) return true;
|
|
56
57
|
try {
|
|
57
58
|
const parsed = aiFilesProjectConfigSchema.parse(JSON.parse(raw));
|
|
58
|
-
|
|
59
|
+
// `enabled` takes full precedence when explicitly set.
|
|
60
|
+
if (parsed.aiFiles.enabled !== undefined) return parsed.aiFiles.enabled;
|
|
61
|
+
// Legacy `disableStalenessMessage` - invert it.
|
|
62
|
+
return !(parsed.aiFiles.disableStalenessMessage ?? false);
|
|
59
63
|
} catch (err) {
|
|
60
64
|
Sentry.captureException(err);
|
|
61
|
-
return
|
|
65
|
+
return true;
|
|
62
66
|
}
|
|
63
67
|
}
|
|
64
68
|
|
|
65
|
-
export async function
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
+
export async function writeAiEnabledToProjectConfig({
|
|
70
|
+
projectDir,
|
|
71
|
+
enabled,
|
|
72
|
+
}: {
|
|
73
|
+
projectDir: string;
|
|
74
|
+
enabled: boolean;
|
|
75
|
+
}): Promise<void> {
|
|
69
76
|
const filePath = path.join(projectDir, "convex.json");
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
77
|
+
const existing = await iife(async () => {
|
|
78
|
+
try {
|
|
79
|
+
return JSON.parse(await fs.readFile(filePath, "utf8")) as unknown;
|
|
80
|
+
} catch {
|
|
81
|
+
return {} as unknown;
|
|
82
|
+
}
|
|
83
|
+
});
|
|
76
84
|
const base =
|
|
77
85
|
existing !== null &&
|
|
78
86
|
typeof existing === "object" &&
|
|
@@ -86,54 +94,75 @@ export async function writeAiDisabledToProjectConfig(
|
|
|
86
94
|
? (base.aiFiles as Record<string, unknown>)
|
|
87
95
|
: {};
|
|
88
96
|
const { $schema, ...rest } = base;
|
|
97
|
+
// Remove legacy keys on every write.
|
|
98
|
+
const { disableStalenessMessage: _legacy, ...restAiFiles } = aiFilesValue;
|
|
89
99
|
const next: Record<string, unknown> = {
|
|
90
100
|
$schema: $schema ?? "node_modules/convex/schemas/convex.schema.json",
|
|
91
101
|
...rest,
|
|
92
|
-
aiFiles: {
|
|
93
|
-
...aiFilesValue,
|
|
94
|
-
disableStalenessMessage,
|
|
95
|
-
},
|
|
102
|
+
aiFiles: { ...restAiFiles, enabled },
|
|
96
103
|
};
|
|
97
104
|
await fs.writeFile(filePath, JSON.stringify(next, null, 2) + "\n", "utf8");
|
|
98
105
|
}
|
|
99
106
|
|
|
100
|
-
export async function readAiConfig(
|
|
101
|
-
projectDir
|
|
102
|
-
convexDir
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
"utf8",
|
|
111
|
-
);
|
|
112
|
-
} catch {
|
|
107
|
+
export async function readAiConfig({
|
|
108
|
+
projectDir,
|
|
109
|
+
convexDir,
|
|
110
|
+
}: {
|
|
111
|
+
projectDir: string;
|
|
112
|
+
convexDir: string;
|
|
113
|
+
}): Promise<AiFilesConfig | null> {
|
|
114
|
+
const enabled = await readAiEnabledFromProjectConfig(projectDir);
|
|
115
|
+
const rawState = await readFileSafe(aiFilesStatePathForConvexDir(convexDir));
|
|
116
|
+
if (rawState === null) {
|
|
113
117
|
// No state file means AI files are not installed, unless the user has
|
|
114
|
-
// explicitly disabled
|
|
115
|
-
return
|
|
116
|
-
? { ...EMPTY_AI_STATE, disableStalenessMessage }
|
|
117
|
-
: null;
|
|
118
|
+
// explicitly disabled in convex.json.
|
|
119
|
+
return !enabled ? { ...EMPTY_AI_STATE, enabled } : null;
|
|
118
120
|
}
|
|
119
121
|
try {
|
|
120
122
|
const state = aiFilesStateSchema.parse(JSON.parse(rawState));
|
|
121
|
-
return {
|
|
122
|
-
...state,
|
|
123
|
-
disableStalenessMessage,
|
|
124
|
-
};
|
|
123
|
+
return { ...state, enabled };
|
|
125
124
|
} catch (err) {
|
|
126
125
|
Sentry.captureException(err);
|
|
127
126
|
return null;
|
|
128
127
|
}
|
|
129
128
|
}
|
|
130
129
|
|
|
131
|
-
export async function
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
130
|
+
export async function hasAiFilesConfig({
|
|
131
|
+
projectDir,
|
|
132
|
+
convexDir,
|
|
133
|
+
}: {
|
|
134
|
+
projectDir: string;
|
|
135
|
+
convexDir: string;
|
|
136
|
+
}): Promise<boolean> {
|
|
137
|
+
if (!(await readAiEnabledFromProjectConfig(projectDir))) {
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
try {
|
|
141
|
+
const rawState = await fs.readFile(
|
|
142
|
+
aiFilesStatePathForConvexDir(convexDir),
|
|
143
|
+
"utf8",
|
|
144
|
+
);
|
|
145
|
+
aiFilesStateSchema.parse(JSON.parse(rawState));
|
|
146
|
+
return true;
|
|
147
|
+
} catch (err) {
|
|
148
|
+
if ((err as NodeJS.ErrnoException).code !== "ENOENT") {
|
|
149
|
+
Sentry.captureException(err);
|
|
150
|
+
}
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export async function writeAiConfig({
|
|
156
|
+
config,
|
|
157
|
+
projectDir,
|
|
158
|
+
convexDir,
|
|
159
|
+
options,
|
|
160
|
+
}: {
|
|
161
|
+
config: AiFilesConfig;
|
|
162
|
+
projectDir: string;
|
|
163
|
+
convexDir: string;
|
|
164
|
+
options?: { persistEnabledPreference?: "ifFalse" | "always" | "never" };
|
|
165
|
+
}): Promise<void> {
|
|
137
166
|
const state = aiFilesStateSchema.parse({
|
|
138
167
|
guidelinesHash: config.guidelinesHash,
|
|
139
168
|
agentsMdSectionHash: config.agentsMdSectionHash,
|
|
@@ -146,14 +175,14 @@ export async function writeAiConfig(
|
|
|
146
175
|
JSON.stringify(state, null, 2) + "\n",
|
|
147
176
|
"utf8",
|
|
148
177
|
);
|
|
149
|
-
|
|
178
|
+
|
|
179
|
+
const persistMode = options?.persistEnabledPreference ?? "ifFalse";
|
|
150
180
|
if (
|
|
151
181
|
persistMode === "always" ||
|
|
152
|
-
(persistMode === "
|
|
153
|
-
)
|
|
154
|
-
await
|
|
155
|
-
config.disableStalenessMessage,
|
|
182
|
+
(persistMode === "ifFalse" && !config.enabled)
|
|
183
|
+
)
|
|
184
|
+
await writeAiEnabledToProjectConfig({
|
|
156
185
|
projectDir,
|
|
157
|
-
|
|
158
|
-
|
|
186
|
+
enabled: config.enabled,
|
|
187
|
+
});
|
|
159
188
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import { chalkStderr } from "chalk";
|
|
3
|
+
import { logMessage } from "../../../bundler/log.js";
|
|
4
|
+
import { safelyDeleteFile } from "./utils.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Remove the legacy `.cursor/rules/convex_rules.mdc` file if it exists.
|
|
8
|
+
* This file was written by the old cursor rules auto-update feature (removed
|
|
9
|
+
* in favour of the AI files system). We clean it up unconditionally
|
|
10
|
+
* during `writeAiFiles`, `convex ai-files update`, and `convex ai-files remove`
|
|
11
|
+
* since it was always auto-managed and is now superseded by
|
|
12
|
+
* `convex/_generated/ai/guidelines.md`.
|
|
13
|
+
*/
|
|
14
|
+
export async function removeLegacyCursorRulesFile(
|
|
15
|
+
projectDir: string,
|
|
16
|
+
): Promise<boolean> {
|
|
17
|
+
const removed = await safelyDeleteFile(
|
|
18
|
+
path.join(projectDir, ".cursor", "rules", "convex_rules.mdc"),
|
|
19
|
+
);
|
|
20
|
+
if (removed)
|
|
21
|
+
logMessage(
|
|
22
|
+
`${chalkStderr.green("✔")} Removed legacy .cursor/rules/convex_rules.mdc (superseded by convex/_generated/ai/guidelines.md).`,
|
|
23
|
+
);
|
|
24
|
+
return removed;
|
|
25
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { describe, test, expect, beforeEach, afterEach } from "vitest";
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import os from "os";
|
|
4
|
+
import path from "path";
|
|
5
|
+
import { hasGuidelinesInstalled } from "./guidelinesmd.js";
|
|
6
|
+
|
|
7
|
+
describe("hasGuidelinesInstalled", () => {
|
|
8
|
+
let tmpDir: string;
|
|
9
|
+
let convexDir: string;
|
|
10
|
+
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
tmpDir = fs.mkdtempSync(`${os.tmpdir()}${path.sep}`);
|
|
13
|
+
convexDir = path.join(tmpDir, "convex");
|
|
14
|
+
fs.mkdirSync(path.join(convexDir, "_generated", "ai"), { recursive: true });
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
afterEach(() => {
|
|
18
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
test("returns false when guidelines.md does not exist", async () => {
|
|
22
|
+
expect(await hasGuidelinesInstalled(convexDir)).toBe(false);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test("returns true when guidelines.md exists", async () => {
|
|
26
|
+
fs.writeFileSync(
|
|
27
|
+
path.join(convexDir, "_generated", "ai", "guidelines.md"),
|
|
28
|
+
"some content",
|
|
29
|
+
);
|
|
30
|
+
expect(await hasGuidelinesInstalled(convexDir)).toBe(true);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test("returns true even when guidelines.md is empty", async () => {
|
|
34
|
+
fs.writeFileSync(
|
|
35
|
+
path.join(convexDir, "_generated", "ai", "guidelines.md"),
|
|
36
|
+
"",
|
|
37
|
+
);
|
|
38
|
+
expect(await hasGuidelinesInstalled(convexDir)).toBe(true);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// eslint-disable-next-line no-restricted-imports
|
|
2
|
+
import { promises as fs } from "fs";
|
|
3
|
+
import { chalkStderr } from "chalk";
|
|
4
|
+
import { logMessage } from "../../../bundler/log.js";
|
|
5
|
+
import { downloadGuidelines } from "../versionApi.js";
|
|
6
|
+
import { hashSha256 } from "../utils/hash.js";
|
|
7
|
+
import { guidelinesPathForConvexDir } from "./paths.js";
|
|
8
|
+
import { readFileSafe } from "./utils.js";
|
|
9
|
+
import { type AiFilesConfig } from "./config.js";
|
|
10
|
+
|
|
11
|
+
export async function hasGuidelinesInstalled(
|
|
12
|
+
convexDir: string,
|
|
13
|
+
): Promise<boolean> {
|
|
14
|
+
return (await readFileSafe(guidelinesPathForConvexDir(convexDir))) !== null;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Download and write the guidelines file.
|
|
19
|
+
* Guidelines live in `_generated/` so local edits are not expected and are
|
|
20
|
+
* not preserved.
|
|
21
|
+
*/
|
|
22
|
+
export async function installGuidelinesFile({
|
|
23
|
+
convexDir,
|
|
24
|
+
config,
|
|
25
|
+
}: {
|
|
26
|
+
convexDir: string;
|
|
27
|
+
config: AiFilesConfig;
|
|
28
|
+
}): Promise<void> {
|
|
29
|
+
const guidelines = await downloadGuidelines();
|
|
30
|
+
if (guidelines === null) {
|
|
31
|
+
logMessage(
|
|
32
|
+
chalkStderr.yellow(
|
|
33
|
+
"Could not download Convex AI guidelines right now. You can retry with: npx convex ai-files install",
|
|
34
|
+
),
|
|
35
|
+
);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
await fs.writeFile(guidelinesPathForConvexDir(convexDir), guidelines, "utf8");
|
|
40
|
+
config.guidelinesHash = hashSha256(guidelines);
|
|
41
|
+
}
|