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
|
@@ -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
|
-
|
|
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
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
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,18 +48,11 @@ vi.mock("child_process", () => ({
|
|
|
35
48
|
},
|
|
36
49
|
}));
|
|
37
50
|
|
|
38
|
-
vi.mock("
|
|
39
|
-
const actual = await importOriginal<typeof import("
|
|
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
|
-
|
|
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
|
|
|
@@ -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
|
-
|
|
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
|
-
|
|
112
|
+
mockPromptYesNo.mockResolvedValue(true);
|
|
107
113
|
|
|
108
|
-
|
|
109
|
-
testInput.emit("keypress", null, { name: "enter" });
|
|
110
|
-
await result;
|
|
114
|
+
await maybeSetupAiFiles({ 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
|
-
|
|
126
|
+
mockPromptYesNo.mockResolvedValue(false);
|
|
123
127
|
|
|
124
|
-
|
|
125
|
-
testInput.write("n");
|
|
126
|
-
testInput.emit("keypress", null, { name: "n" });
|
|
127
|
-
testInput.emit("keypress", null, { name: "enter" });
|
|
128
|
-
await result;
|
|
128
|
+
await maybeSetupAiFiles({ 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("
|
|
137
|
-
|
|
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 maybeSetupAiFiles({ 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 maybeSetupAiFiles({ 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 maybeSetupAiFiles({ 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,213 @@
|
|
|
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 AiFilesConfig } from "./config.js";
|
|
9
|
+
import { iife, readFileSafe } from "./utils.js";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Read the frontmatter `name:` values from skills installed by the skills CLI.
|
|
13
|
+
*/
|
|
14
|
+
async function readInstalledSkillNames(projectDir: string): Promise<string[]> {
|
|
15
|
+
const skillsDir = path.join(projectDir, ".agents", "skills");
|
|
16
|
+
const entries = await iife(async () => {
|
|
17
|
+
try {
|
|
18
|
+
const dirents = await fs.readdir(skillsDir, { withFileTypes: true });
|
|
19
|
+
return dirents
|
|
20
|
+
.filter((d) => d.isDirectory() || d.isSymbolicLink())
|
|
21
|
+
.map((d) => d.name);
|
|
22
|
+
} catch {
|
|
23
|
+
return [] as string[];
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
if (entries.length === 0) return [];
|
|
27
|
+
|
|
28
|
+
const names: string[] = [];
|
|
29
|
+
for (const entry of entries) {
|
|
30
|
+
const skillMdPath = path.join(skillsDir, entry, "SKILL.md");
|
|
31
|
+
const content = await readFileSafe(skillMdPath);
|
|
32
|
+
if (content === null) continue;
|
|
33
|
+
const match = content.match(/^---[\s\S]*?^name:\s*(.+?)\s*$/m);
|
|
34
|
+
if (match) {
|
|
35
|
+
names.push(match[1]);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return names;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Runs `npx skills add get-convex/agent-skills --yes` in the given directory.
|
|
43
|
+
* Returns true on success, false if the process fails or cannot be started.
|
|
44
|
+
*/
|
|
45
|
+
function runSkillsAdd(cwd: string): Promise<boolean> {
|
|
46
|
+
return runSkillsCommand(cwd, ["add", "get-convex/agent-skills", "--yes"]);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Runs `npx skills remove <name...> --yes` to surgically remove only the
|
|
51
|
+
* Convex-managed skills, leaving any skills from other sources intact.
|
|
52
|
+
*/
|
|
53
|
+
function runSkillsRemove({
|
|
54
|
+
cwd,
|
|
55
|
+
skillNames,
|
|
56
|
+
}: {
|
|
57
|
+
cwd: string;
|
|
58
|
+
skillNames: string[];
|
|
59
|
+
}): Promise<boolean> {
|
|
60
|
+
return runSkillsCommand(cwd, ["remove", ...skillNames, "--yes"]);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* This function exists so we have a way to disable skills installs without pushing a new
|
|
65
|
+
* version of the convex CLI
|
|
66
|
+
*/
|
|
67
|
+
async function shouldRunSkillsCli(): Promise<boolean> {
|
|
68
|
+
const versionData = await getVersion();
|
|
69
|
+
|
|
70
|
+
if (versionData.kind === "error") return true;
|
|
71
|
+
|
|
72
|
+
if (versionData.data.disableSkillsCli) {
|
|
73
|
+
logMessage(chalkStderr.yellow(`Agent skills are temporarily disabled.`));
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Remove the skills-lock.json file if it only contains skills that we
|
|
82
|
+
* are removing. The `npx skills remove` command leaves the lockfile behind
|
|
83
|
+
* even when it's logically empty.
|
|
84
|
+
*/
|
|
85
|
+
async function removeSkillsLockIfEmpty({
|
|
86
|
+
projectDir,
|
|
87
|
+
removedSkillNames,
|
|
88
|
+
}: {
|
|
89
|
+
projectDir: string;
|
|
90
|
+
removedSkillNames: string[];
|
|
91
|
+
}): Promise<boolean> {
|
|
92
|
+
const lockPath = path.join(projectDir, "skills-lock.json");
|
|
93
|
+
try {
|
|
94
|
+
const content = await fs.readFile(lockPath, "utf8");
|
|
95
|
+
const lock = JSON.parse(content);
|
|
96
|
+
|
|
97
|
+
if (
|
|
98
|
+
!lock ||
|
|
99
|
+
typeof lock !== "object" ||
|
|
100
|
+
!lock.skills ||
|
|
101
|
+
typeof lock.skills !== "object"
|
|
102
|
+
) {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const remainingSkills = Object.keys(lock.skills).filter(
|
|
107
|
+
(name) => !removedSkillNames.includes(name),
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
if (remainingSkills.length === 0) {
|
|
111
|
+
await fs.unlink(lockPath);
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
return false;
|
|
115
|
+
} catch {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Install Convex agent skills and record the SHA and names into the config.
|
|
122
|
+
* Handles the kill-switch check and all logging internally.
|
|
123
|
+
*/
|
|
124
|
+
export async function installSkills({
|
|
125
|
+
projectDir,
|
|
126
|
+
config,
|
|
127
|
+
}: {
|
|
128
|
+
projectDir: string;
|
|
129
|
+
config: AiFilesConfig;
|
|
130
|
+
}): Promise<void> {
|
|
131
|
+
if (!(await shouldRunSkillsCli())) return;
|
|
132
|
+
|
|
133
|
+
logMessage("Installing Convex agent skills...");
|
|
134
|
+
const skillsOk = await runSkillsAdd(projectDir);
|
|
135
|
+
if (!skillsOk) {
|
|
136
|
+
logMessage(
|
|
137
|
+
chalkStderr.yellow(
|
|
138
|
+
"Could not install agent skills. You can retry manually with: npx skills add get-convex/agent-skills",
|
|
139
|
+
),
|
|
140
|
+
);
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const sha = await fetchAgentSkillsSha();
|
|
145
|
+
if (sha) config.agentSkillsSha = sha;
|
|
146
|
+
|
|
147
|
+
const names = await readInstalledSkillNames(projectDir);
|
|
148
|
+
if (names.length > 0) config.installedSkillNames = names;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Remove Convex-managed agent skills and clean up the lock file if empty.
|
|
153
|
+
* Returns true if any removal occurred.
|
|
154
|
+
*/
|
|
155
|
+
export async function removeInstalledSkills({
|
|
156
|
+
projectDir,
|
|
157
|
+
skillNames,
|
|
158
|
+
}: {
|
|
159
|
+
projectDir: string;
|
|
160
|
+
skillNames: string[];
|
|
161
|
+
}): Promise<boolean> {
|
|
162
|
+
if (skillNames.length === 0 || !(await shouldRunSkillsCli())) return false;
|
|
163
|
+
|
|
164
|
+
logMessage(`Removing Convex agent skills: ${skillNames.join(", ")}`);
|
|
165
|
+
const skillsOk = await runSkillsRemove({ cwd: projectDir, skillNames });
|
|
166
|
+
if (!skillsOk) {
|
|
167
|
+
logMessage(
|
|
168
|
+
chalkStderr.yellow(
|
|
169
|
+
"Could not remove agent skills automatically. Remove them manually with: npx skills remove",
|
|
170
|
+
),
|
|
171
|
+
);
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const lockRemoved = await removeSkillsLockIfEmpty({
|
|
176
|
+
projectDir,
|
|
177
|
+
removedSkillNames: skillNames,
|
|
178
|
+
});
|
|
179
|
+
if (lockRemoved)
|
|
180
|
+
logMessage(`${chalkStderr.green("✔")} Deleted skills-lock.json.`);
|
|
181
|
+
return true;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function runSkillsCommand(cwd: string, args: string[]): Promise<boolean> {
|
|
185
|
+
return new Promise((resolve) => {
|
|
186
|
+
const proc = child_process.spawn(
|
|
187
|
+
"npx",
|
|
188
|
+
["--yes", "skills@latest", ...args],
|
|
189
|
+
{
|
|
190
|
+
cwd,
|
|
191
|
+
stdio: "pipe",
|
|
192
|
+
// .cmd files on Windows require shell execution.
|
|
193
|
+
shell: process.platform === "win32",
|
|
194
|
+
},
|
|
195
|
+
);
|
|
196
|
+
let capturedOutput = "";
|
|
197
|
+
proc.stdout?.on("data", (chunk) => {
|
|
198
|
+
capturedOutput += chunk.toString();
|
|
199
|
+
});
|
|
200
|
+
proc.stderr?.on("data", (chunk) => {
|
|
201
|
+
capturedOutput += chunk.toString();
|
|
202
|
+
});
|
|
203
|
+
proc.on("close", (code) => {
|
|
204
|
+
if (code !== 0 && capturedOutput.trim().length > 0) {
|
|
205
|
+
const lines = capturedOutput.trim().split(/\r?\n/);
|
|
206
|
+
const tail = lines.slice(-10).join("\n");
|
|
207
|
+
logMessage(chalkStderr.gray(`skills output (tail):\n${tail}`));
|
|
208
|
+
}
|
|
209
|
+
resolve(code === 0);
|
|
210
|
+
});
|
|
211
|
+
proc.on("error", () => resolve(false));
|
|
212
|
+
});
|
|
213
|
+
}
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import { chalkStderr } from "chalk";
|
|
3
|
+
import { logMessage } from "../../../bundler/log.js";
|
|
4
|
+
import {
|
|
5
|
+
AGENTS_MD_START_MARKER,
|
|
6
|
+
AGENTS_MD_END_MARKER,
|
|
7
|
+
agentsMdConvexSection,
|
|
8
|
+
} from "../../codegen_templates/agentsmd.js";
|
|
9
|
+
import {
|
|
10
|
+
CLAUDE_MD_START_MARKER,
|
|
11
|
+
CLAUDE_MD_END_MARKER,
|
|
12
|
+
claudeMdConvexSection,
|
|
13
|
+
} from "../../codegen_templates/claudemd.js";
|
|
14
|
+
import { getVersion } from "../versionApi.js";
|
|
15
|
+
import { hashSha256 } from "../utils/hash.js";
|
|
16
|
+
import {
|
|
17
|
+
type AiFilesPaths,
|
|
18
|
+
agentsMdPath,
|
|
19
|
+
claudeMdPath,
|
|
20
|
+
guidelinesPathForConvexDir,
|
|
21
|
+
} from "./paths.js";
|
|
22
|
+
import { type AiFilesConfig, readAiConfig } from "./config.js";
|
|
23
|
+
import { readFileSafe } from "./utils.js";
|
|
24
|
+
|
|
25
|
+
function logGuidelinesStatus({
|
|
26
|
+
guidelinesFile,
|
|
27
|
+
guidelinesRelPath,
|
|
28
|
+
config,
|
|
29
|
+
canonicalGuidelinesHash,
|
|
30
|
+
networkAvailable,
|
|
31
|
+
}: {
|
|
32
|
+
guidelinesFile: string | null;
|
|
33
|
+
guidelinesRelPath: string;
|
|
34
|
+
config: AiFilesConfig;
|
|
35
|
+
canonicalGuidelinesHash: string | null;
|
|
36
|
+
networkAvailable: boolean;
|
|
37
|
+
}): void {
|
|
38
|
+
if (guidelinesFile === null) {
|
|
39
|
+
logMessage(
|
|
40
|
+
` ${chalkStderr.yellow("⚠")} ${guidelinesRelPath}: not on disk — run ${chalkStderr.bold("npx convex ai-files install")} to reinstall`,
|
|
41
|
+
);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const isLocallyModified =
|
|
46
|
+
config.guidelinesHash !== null &&
|
|
47
|
+
hashSha256(guidelinesFile) !== config.guidelinesHash;
|
|
48
|
+
|
|
49
|
+
if (isLocallyModified) {
|
|
50
|
+
logMessage(
|
|
51
|
+
` ${chalkStderr.yellow("⚠")} ${guidelinesRelPath}: installed, modified locally (changes will be overwritten on next update)`,
|
|
52
|
+
);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const isOutOfDate =
|
|
57
|
+
networkAvailable &&
|
|
58
|
+
canonicalGuidelinesHash !== null &&
|
|
59
|
+
config.guidelinesHash !== null &&
|
|
60
|
+
config.guidelinesHash !== canonicalGuidelinesHash;
|
|
61
|
+
|
|
62
|
+
if (isOutOfDate) {
|
|
63
|
+
logMessage(
|
|
64
|
+
` ${chalkStderr.yellow("⚠")} ${guidelinesRelPath}: installed, out of date — run ${chalkStderr.bold("npx convex ai-files update")}`,
|
|
65
|
+
);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
logMessage(
|
|
70
|
+
` ${chalkStderr.green("✔")} ${guidelinesRelPath}: installed${networkAvailable ? ", up to date" : ""}`,
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function logAgentsMdStatus({
|
|
75
|
+
agentsContent,
|
|
76
|
+
config,
|
|
77
|
+
convexDirName,
|
|
78
|
+
}: {
|
|
79
|
+
agentsContent: string | null;
|
|
80
|
+
config: AiFilesConfig;
|
|
81
|
+
convexDirName: string;
|
|
82
|
+
}): void {
|
|
83
|
+
const hasSection =
|
|
84
|
+
agentsContent !== null &&
|
|
85
|
+
agentsContent.includes(AGENTS_MD_START_MARKER) &&
|
|
86
|
+
agentsContent.includes(AGENTS_MD_END_MARKER);
|
|
87
|
+
|
|
88
|
+
if (!hasSection) {
|
|
89
|
+
logMessage(
|
|
90
|
+
` ${chalkStderr.yellow("⚠")} AGENTS.md: Convex section missing — run ${chalkStderr.bold("npx convex ai-files install")} to reinstall`,
|
|
91
|
+
);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const currentHash = hashSha256(agentsMdConvexSection(convexDirName));
|
|
96
|
+
if (
|
|
97
|
+
config.agentsMdSectionHash !== null &&
|
|
98
|
+
config.agentsMdSectionHash !== currentHash
|
|
99
|
+
) {
|
|
100
|
+
logMessage(
|
|
101
|
+
` ${chalkStderr.yellow("⚠")} AGENTS.md: Convex section out of date — run ${chalkStderr.bold("npx convex ai-files update")}`,
|
|
102
|
+
);
|
|
103
|
+
} else {
|
|
104
|
+
logMessage(
|
|
105
|
+
` ${chalkStderr.green("✔")} AGENTS.md: Convex section present, up to date`,
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function logClaudeMdStatus({
|
|
111
|
+
claudeContent,
|
|
112
|
+
config,
|
|
113
|
+
convexDirName,
|
|
114
|
+
}: {
|
|
115
|
+
claudeContent: string | null;
|
|
116
|
+
config: AiFilesConfig;
|
|
117
|
+
convexDirName: string;
|
|
118
|
+
}): void {
|
|
119
|
+
const hasSection =
|
|
120
|
+
claudeContent !== null &&
|
|
121
|
+
claudeContent.includes(CLAUDE_MD_START_MARKER) &&
|
|
122
|
+
claudeContent.includes(CLAUDE_MD_END_MARKER);
|
|
123
|
+
|
|
124
|
+
if (!hasSection) {
|
|
125
|
+
if (claudeContent === null) {
|
|
126
|
+
logMessage(
|
|
127
|
+
` ${chalkStderr.yellow("⚠")} CLAUDE.md: missing - run ${chalkStderr.bold("npx convex ai-files install")} to create it`,
|
|
128
|
+
);
|
|
129
|
+
} else {
|
|
130
|
+
logMessage(
|
|
131
|
+
` ${chalkStderr.yellow("⚠")} CLAUDE.md: no Convex section present - run ${chalkStderr.bold("npx convex ai-files update")} to add it`,
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const currentHash = hashSha256(claudeMdConvexSection(convexDirName));
|
|
138
|
+
if (config.claudeMdHash !== null && config.claudeMdHash !== currentHash) {
|
|
139
|
+
logMessage(
|
|
140
|
+
` ${chalkStderr.yellow("⚠")} CLAUDE.md: Convex section out of date - run ${chalkStderr.bold("npx convex ai-files update")}`,
|
|
141
|
+
);
|
|
142
|
+
} else {
|
|
143
|
+
logMessage(
|
|
144
|
+
` ${chalkStderr.green("✔")} CLAUDE.md: Convex section present, up to date`,
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function logSkillsStatus({
|
|
150
|
+
config,
|
|
151
|
+
canonicalAgentSkillsSha,
|
|
152
|
+
networkAvailable,
|
|
153
|
+
}: {
|
|
154
|
+
config: AiFilesConfig;
|
|
155
|
+
canonicalAgentSkillsSha: string | null;
|
|
156
|
+
networkAvailable: boolean;
|
|
157
|
+
}): void {
|
|
158
|
+
if (config.installedSkillNames.length === 0) {
|
|
159
|
+
logMessage(
|
|
160
|
+
` ${chalkStderr.yellow("⚠")} Agent skills: not installed — run ${chalkStderr.bold("npx convex ai-files install")} to install`,
|
|
161
|
+
);
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const skillsList = config.installedSkillNames.join(", ");
|
|
166
|
+
const isStale =
|
|
167
|
+
networkAvailable &&
|
|
168
|
+
canonicalAgentSkillsSha !== null &&
|
|
169
|
+
config.agentSkillsSha !== null &&
|
|
170
|
+
config.agentSkillsSha !== canonicalAgentSkillsSha;
|
|
171
|
+
|
|
172
|
+
if (isStale) {
|
|
173
|
+
logMessage(
|
|
174
|
+
` ${chalkStderr.yellow("⚠")} Agent skills: ${skillsList} — out of date, run ${chalkStderr.bold("npx convex ai-files update")}`,
|
|
175
|
+
);
|
|
176
|
+
} else {
|
|
177
|
+
logMessage(
|
|
178
|
+
` ${chalkStderr.green("✔")} Agent skills: ${skillsList}${networkAvailable ? " (up to date)" : ""}`,
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export async function statusAiFiles({
|
|
184
|
+
projectDir,
|
|
185
|
+
convexDir,
|
|
186
|
+
}: AiFilesPaths): Promise<void> {
|
|
187
|
+
const convexDirName = path.relative(projectDir, convexDir);
|
|
188
|
+
const guidelinesRelPath = path.relative(
|
|
189
|
+
projectDir,
|
|
190
|
+
guidelinesPathForConvexDir(convexDir),
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
const config = await readAiConfig({ projectDir, convexDir });
|
|
194
|
+
|
|
195
|
+
if (config === null) {
|
|
196
|
+
logMessage(`Convex AI files: ${chalkStderr.yellow("not installed")}`);
|
|
197
|
+
logMessage(
|
|
198
|
+
` Run ${chalkStderr.bold("npx convex ai-files install")} to get started, ` +
|
|
199
|
+
`or ${chalkStderr.bold("npx convex ai-files disable")} to opt out.`,
|
|
200
|
+
);
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (!config.enabled) {
|
|
205
|
+
logMessage(`Convex AI files: ${chalkStderr.yellow("disabled")}`);
|
|
206
|
+
logMessage(
|
|
207
|
+
` Run ${chalkStderr.bold("npx convex ai-files enable")} to re-enable.`,
|
|
208
|
+
);
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
logMessage(`Convex AI files: ${chalkStderr.green("enabled")}`);
|
|
213
|
+
|
|
214
|
+
const [versionData, guidelinesFile, agentsContent, claudeContent] =
|
|
215
|
+
await Promise.all([
|
|
216
|
+
getVersion(),
|
|
217
|
+
readFileSafe(guidelinesPathForConvexDir(convexDir)),
|
|
218
|
+
readFileSafe(agentsMdPath(projectDir)),
|
|
219
|
+
readFileSafe(claudeMdPath(projectDir)),
|
|
220
|
+
]);
|
|
221
|
+
|
|
222
|
+
const networkAvailable = versionData.kind === "ok";
|
|
223
|
+
const canonicalGuidelinesHash = networkAvailable
|
|
224
|
+
? versionData.data.guidelinesHash
|
|
225
|
+
: null;
|
|
226
|
+
const canonicalAgentSkillsSha = networkAvailable
|
|
227
|
+
? versionData.data.agentSkillsSha
|
|
228
|
+
: null;
|
|
229
|
+
|
|
230
|
+
logGuidelinesStatus({
|
|
231
|
+
guidelinesFile,
|
|
232
|
+
guidelinesRelPath,
|
|
233
|
+
config,
|
|
234
|
+
canonicalGuidelinesHash,
|
|
235
|
+
networkAvailable,
|
|
236
|
+
});
|
|
237
|
+
logAgentsMdStatus({ agentsContent, config, convexDirName });
|
|
238
|
+
logClaudeMdStatus({ claudeContent, config, convexDirName });
|
|
239
|
+
logSkillsStatus({ config, canonicalAgentSkillsSha, networkAvailable });
|
|
240
|
+
}
|