convex 1.34.1 → 1.35.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 +86 -43
- package/dist/browser.bundle.js +1 -1
- package/dist/browser.bundle.js.map +1 -1
- package/dist/cjs/cli/aiFiles.js +31 -13
- package/dist/cjs/cli/aiFiles.js.map +3 -3
- package/dist/cjs/cli/configure.js +21 -24
- package/dist/cjs/cli/configure.js.map +2 -2
- package/dist/cjs/cli/deploy.js +8 -9
- package/dist/cjs/cli/deploy.js.map +2 -2
- package/dist/cjs/cli/deploymentCreate.js +225 -40
- package/dist/cjs/cli/deploymentCreate.js.map +3 -3
- package/dist/cjs/cli/deploymentSelect.js +14 -13
- package/dist/cjs/cli/deploymentSelect.js.map +2 -2
- package/dist/cjs/cli/dev.js +30 -11
- package/dist/cjs/cli/dev.js.map +2 -2
- package/dist/cjs/cli/docs.js +1 -1
- package/dist/cjs/cli/docs.js.map +2 -2
- package/dist/cjs/cli/init.js +1 -1
- package/dist/cjs/cli/init.js.map +2 -2
- package/dist/cjs/cli/lib/aiFiles/agentsmd.js +14 -10
- package/dist/cjs/cli/lib/aiFiles/agentsmd.js.map +2 -2
- package/dist/cjs/cli/lib/aiFiles/claudemd.js +14 -10
- package/dist/cjs/cli/lib/aiFiles/claudemd.js.map +2 -2
- package/dist/cjs/cli/lib/aiFiles/guidelinesmd.js +10 -3
- package/dist/cjs/cli/lib/aiFiles/guidelinesmd.js.map +2 -2
- package/dist/cjs/cli/lib/aiFiles/index.js +70 -86
- package/dist/cjs/cli/lib/aiFiles/index.js.map +3 -3
- package/dist/cjs/cli/lib/aiFiles/skills.js +28 -12
- package/dist/cjs/cli/lib/aiFiles/skills.js.map +2 -2
- package/dist/cjs/cli/lib/aiFiles/state.js +96 -0
- package/dist/cjs/cli/lib/aiFiles/state.js.map +7 -0
- package/dist/cjs/cli/lib/aiFiles/status.js +31 -28
- package/dist/cjs/cli/lib/aiFiles/status.js.map +2 -2
- package/dist/cjs/cli/lib/aiFiles/utils.js +31 -14
- package/dist/cjs/cli/lib/aiFiles/utils.js.map +2 -2
- package/dist/cjs/cli/lib/api.js +70 -7
- package/dist/cjs/cli/lib/api.js.map +2 -2
- package/dist/cjs/cli/lib/command.js +4 -5
- package/dist/cjs/cli/lib/command.js.map +2 -2
- package/dist/cjs/cli/lib/config.js +41 -4
- package/dist/cjs/cli/lib/config.js.map +3 -3
- package/dist/cjs/cli/lib/deploy2.js +9 -26
- package/dist/cjs/cli/lib/deploy2.js.map +2 -2
- package/dist/cjs/cli/lib/deployApi/componentDefinition.js +4 -1
- package/dist/cjs/cli/lib/deployApi/componentDefinition.js.map +2 -2
- package/dist/cjs/cli/lib/deploymentSelection.js +45 -2
- package/dist/cjs/cli/lib/deploymentSelection.js.map +2 -2
- package/dist/cjs/cli/lib/deploymentSelector.js +1 -0
- package/dist/cjs/cli/lib/deploymentSelector.js.map +2 -2
- package/dist/cjs/cli/lib/dev.js +162 -117
- package/dist/cjs/cli/lib/dev.js.map +2 -2
- package/dist/cjs/cli/lib/env.js +1 -13
- package/dist/cjs/cli/lib/env.js.map +2 -2
- package/dist/cjs/cli/lib/envvars.js +8 -1
- package/dist/cjs/cli/lib/envvars.js.map +2 -2
- package/dist/cjs/cli/lib/expiration.js +104 -0
- package/dist/cjs/cli/lib/expiration.js.map +7 -0
- package/dist/cjs/cli/lib/generatedFunctionLogsApi.js.map +1 -1
- package/dist/cjs/cli/lib/init.js +4 -3
- package/dist/cjs/cli/lib/init.js.map +2 -2
- package/dist/cjs/cli/lib/insights.js +1 -1
- package/dist/cjs/cli/lib/insights.js.map +2 -2
- package/dist/cjs/cli/lib/localDeployment/anonymous.js +14 -7
- package/dist/cjs/cli/lib/localDeployment/anonymous.js.map +2 -2
- package/dist/cjs/cli/lib/localDeployment/localDeployment.js +8 -10
- package/dist/cjs/cli/lib/localDeployment/localDeployment.js.map +2 -2
- package/dist/cjs/cli/lib/localDeployment/run.js +1 -0
- package/dist/cjs/cli/lib/localDeployment/run.js.map +2 -2
- package/dist/cjs/cli/lib/localDeployment/upgrade.js +2 -2
- package/dist/cjs/cli/lib/localDeployment/upgrade.js.map +2 -2
- package/dist/cjs/cli/lib/localDeployment/utils.js +9 -0
- package/dist/cjs/cli/lib/localDeployment/utils.js.map +2 -2
- package/dist/cjs/cli/lib/mcp/tools/status.js +1 -1
- package/dist/cjs/cli/lib/mcp/tools/status.js.map +2 -2
- package/dist/cjs/cli/lib/updates.js +8 -9
- package/dist/cjs/cli/lib/updates.js.map +2 -2
- package/dist/cjs/cli/lib/usage.js +2 -1
- package/dist/cjs/cli/lib/usage.js.map +2 -2
- package/dist/cjs/cli/lib/utils/prompts.js +2 -1
- package/dist/cjs/cli/lib/utils/prompts.js.map +2 -2
- package/dist/cjs/cli/lib/utils/utils.js +46 -20
- package/dist/cjs/cli/lib/utils/utils.js.map +3 -3
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/react-clerk/ConvexProviderWithClerk.js.map +1 -1
- package/dist/cjs/server/components/definition.js.map +1 -1
- package/dist/cjs/server/components/index.js +40 -4
- package/dist/cjs/server/components/index.js.map +2 -2
- package/dist/cjs/server/data_model.js.map +1 -1
- package/dist/cjs/server/impl/meta_impl.js +78 -0
- package/dist/cjs/server/impl/meta_impl.js.map +7 -0
- package/dist/cjs/server/impl/registration_impl.js +16 -11
- package/dist/cjs/server/impl/registration_impl.js.map +2 -2
- package/dist/cjs/server/index.js.map +2 -2
- package/dist/cjs/server/meta.js +17 -0
- package/dist/cjs/server/meta.js.map +7 -0
- package/dist/cjs/server/registration.js.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/configure.test.d.ts +2 -0
- package/dist/cjs-types/cli/configure.test.d.ts.map +1 -0
- package/dist/cjs-types/cli/deploy.d.ts.map +1 -1
- package/dist/cjs-types/cli/deploymentCreate.d.ts +1 -0
- package/dist/cjs-types/cli/deploymentCreate.d.ts.map +1 -1
- package/dist/cjs-types/cli/deploymentSelect.d.ts +2 -1
- package/dist/cjs-types/cli/deploymentSelect.d.ts.map +1 -1
- package/dist/cjs-types/cli/dev.d.ts +3 -1
- package/dist/cjs-types/cli/dev.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/aiFiles/agentsmd.d.ts +5 -5
- package/dist/cjs-types/cli/lib/aiFiles/agentsmd.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/aiFiles/claudemd.d.ts +5 -5
- package/dist/cjs-types/cli/lib/aiFiles/claudemd.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/aiFiles/guidelinesmd.d.ts +3 -3
- package/dist/cjs-types/cli/lib/aiFiles/guidelinesmd.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/aiFiles/index.d.ts +20 -18
- package/dist/cjs-types/cli/lib/aiFiles/index.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/aiFiles/skills.d.ts +6 -4
- package/dist/cjs-types/cli/lib/aiFiles/skills.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/aiFiles/state.d.ts +38 -0
- package/dist/cjs-types/cli/lib/aiFiles/state.d.ts.map +1 -0
- package/dist/cjs-types/cli/lib/aiFiles/state.test.d.ts +2 -0
- package/dist/cjs-types/cli/lib/aiFiles/state.test.d.ts.map +1 -0
- package/dist/cjs-types/cli/lib/aiFiles/status.d.ts +4 -1
- package/dist/cjs-types/cli/lib/aiFiles/status.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/aiFiles/utils.d.ts +13 -3
- package/dist/cjs-types/cli/lib/aiFiles/utils.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/aiFiles/utils.test.d.ts +2 -0
- package/dist/cjs-types/cli/lib/aiFiles/utils.test.d.ts.map +1 -0
- package/dist/cjs-types/cli/lib/api.d.ts +3 -3
- package/dist/cjs-types/cli/lib/api.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/command.d.ts +2 -1
- package/dist/cjs-types/cli/lib/command.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/config.d.ts +17 -6
- package/dist/cjs-types/cli/lib/config.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/deploy2.d.ts +5 -2
- package/dist/cjs-types/cli/lib/deploy2.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/deployApi/componentDefinition.d.ts +27 -12
- package/dist/cjs-types/cli/lib/deployApi/componentDefinition.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/deployApi/modules.d.ts +12 -12
- package/dist/cjs-types/cli/lib/deployApi/startPush.d.ts +25 -16
- package/dist/cjs-types/cli/lib/deployApi/startPush.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/deploymentSelection.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/deploymentSelector.d.ts +2 -0
- package/dist/cjs-types/cli/lib/deploymentSelector.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/dev.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/env.d.ts +0 -4
- package/dist/cjs-types/cli/lib/env.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/envvars.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/expiration.d.ts +35 -0
- package/dist/cjs-types/cli/lib/expiration.d.ts.map +1 -0
- package/dist/cjs-types/cli/lib/expiration.test.d.ts +2 -0
- package/dist/cjs-types/cli/lib/expiration.test.d.ts.map +1 -0
- package/dist/cjs-types/cli/lib/generatedFunctionLogsApi.d.ts +16 -1
- package/dist/cjs-types/cli/lib/generatedFunctionLogsApi.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/init.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/localDeployment/anonymous.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/localDeployment/localDeployment.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/localDeployment/run.d.ts +15 -0
- package/dist/cjs-types/cli/lib/localDeployment/run.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/localDeployment/upgrade.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/localDeployment/utils.d.ts +7 -0
- package/dist/cjs-types/cli/lib/localDeployment/utils.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/mcp/requestContext.d.ts +3 -3
- package/dist/cjs-types/cli/lib/updates.d.ts +4 -3
- package/dist/cjs-types/cli/lib/updates.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/usage.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/utils/prompts.d.ts +1 -0
- package/dist/cjs-types/cli/lib/utils/prompts.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/utils/utils.d.ts +16 -2
- package/dist/cjs-types/cli/lib/utils/utils.d.ts.map +1 -1
- package/dist/cjs-types/index.d.ts +1 -1
- package/dist/cjs-types/react-clerk/ConvexProviderWithClerk.d.ts +1 -1
- package/dist/cjs-types/server/components/definition.d.ts +1 -0
- package/dist/cjs-types/server/components/definition.d.ts.map +1 -1
- package/dist/cjs-types/server/components/index.d.ts +5 -1
- package/dist/cjs-types/server/components/index.d.ts.map +1 -1
- package/dist/cjs-types/server/data_model.d.ts +2 -1
- package/dist/cjs-types/server/data_model.d.ts.map +1 -1
- package/dist/cjs-types/server/impl/meta_impl.d.ts +5 -0
- package/dist/cjs-types/server/impl/meta_impl.d.ts.map +1 -0
- package/dist/cjs-types/server/impl/registration_impl.d.ts.map +1 -1
- package/dist/cjs-types/server/index.d.ts +1 -0
- package/dist/cjs-types/server/index.d.ts.map +1 -1
- package/dist/cjs-types/server/meta.d.ts +72 -0
- package/dist/cjs-types/server/meta.d.ts.map +1 -0
- package/dist/cjs-types/server/registration.d.ts.map +1 -1
- package/dist/cli.bundle.cjs +1665 -1215
- package/dist/cli.bundle.cjs.map +4 -4
- package/dist/esm/cli/aiFiles.js +33 -15
- package/dist/esm/cli/aiFiles.js.map +2 -2
- package/dist/esm/cli/configure.js +23 -26
- package/dist/esm/cli/configure.js.map +2 -2
- package/dist/esm/cli/deploy.js +12 -11
- package/dist/esm/cli/deploy.js.map +2 -2
- package/dist/esm/cli/deploymentCreate.js +238 -42
- package/dist/esm/cli/deploymentCreate.js.map +2 -2
- package/dist/esm/cli/deploymentSelect.js +13 -12
- package/dist/esm/cli/deploymentSelect.js.map +2 -2
- package/dist/esm/cli/dev.js +34 -13
- package/dist/esm/cli/dev.js.map +2 -2
- package/dist/esm/cli/docs.js +1 -1
- package/dist/esm/cli/docs.js.map +2 -2
- package/dist/esm/cli/init.js +2 -2
- package/dist/esm/cli/init.js.map +2 -2
- package/dist/esm/cli/lib/aiFiles/agentsmd.js +13 -9
- package/dist/esm/cli/lib/aiFiles/agentsmd.js.map +2 -2
- package/dist/esm/cli/lib/aiFiles/claudemd.js +13 -9
- package/dist/esm/cli/lib/aiFiles/claudemd.js.map +2 -2
- package/dist/esm/cli/lib/aiFiles/guidelinesmd.js +12 -5
- package/dist/esm/cli/lib/aiFiles/guidelinesmd.js.map +2 -2
- package/dist/esm/cli/lib/aiFiles/index.js +72 -89
- package/dist/esm/cli/lib/aiFiles/index.js.map +2 -2
- package/dist/esm/cli/lib/aiFiles/skills.js +29 -13
- package/dist/esm/cli/lib/aiFiles/skills.js.map +2 -2
- package/dist/esm/cli/lib/aiFiles/state.js +60 -0
- package/dist/esm/cli/lib/aiFiles/state.js.map +7 -0
- package/dist/esm/cli/lib/aiFiles/status.js +32 -29
- package/dist/esm/cli/lib/aiFiles/status.js.map +2 -2
- package/dist/esm/cli/lib/aiFiles/utils.js +25 -10
- package/dist/esm/cli/lib/aiFiles/utils.js.map +2 -2
- package/dist/esm/cli/lib/api.js +70 -7
- package/dist/esm/cli/lib/api.js.map +2 -2
- package/dist/esm/cli/lib/command.js +4 -5
- package/dist/esm/cli/lib/command.js.map +2 -2
- package/dist/esm/cli/lib/config.js +39 -3
- package/dist/esm/cli/lib/config.js.map +2 -2
- package/dist/esm/cli/lib/deploy2.js +13 -26
- package/dist/esm/cli/lib/deploy2.js.map +2 -2
- package/dist/esm/cli/lib/deployApi/componentDefinition.js +4 -1
- package/dist/esm/cli/lib/deployApi/componentDefinition.js.map +2 -2
- package/dist/esm/cli/lib/deploymentSelection.js +46 -2
- package/dist/esm/cli/lib/deploymentSelection.js.map +2 -2
- package/dist/esm/cli/lib/deploymentSelector.js +1 -0
- package/dist/esm/cli/lib/deploymentSelector.js.map +2 -2
- package/dist/esm/cli/lib/dev.js +162 -118
- package/dist/esm/cli/lib/dev.js.map +2 -2
- package/dist/esm/cli/lib/env.js +0 -11
- package/dist/esm/cli/lib/env.js.map +2 -2
- package/dist/esm/cli/lib/envvars.js +8 -1
- package/dist/esm/cli/lib/envvars.js.map +2 -2
- package/dist/esm/cli/lib/expiration.js +80 -0
- package/dist/esm/cli/lib/expiration.js.map +7 -0
- package/dist/esm/cli/lib/init.js +4 -3
- package/dist/esm/cli/lib/init.js.map +2 -2
- package/dist/esm/cli/lib/insights.js +1 -1
- package/dist/esm/cli/lib/insights.js.map +2 -2
- package/dist/esm/cli/lib/localDeployment/anonymous.js +16 -9
- package/dist/esm/cli/lib/localDeployment/anonymous.js.map +2 -2
- package/dist/esm/cli/lib/localDeployment/localDeployment.js +9 -11
- package/dist/esm/cli/lib/localDeployment/localDeployment.js.map +2 -2
- package/dist/esm/cli/lib/localDeployment/run.js +1 -1
- package/dist/esm/cli/lib/localDeployment/run.js.map +2 -2
- package/dist/esm/cli/lib/localDeployment/upgrade.js +2 -2
- package/dist/esm/cli/lib/localDeployment/upgrade.js.map +2 -2
- package/dist/esm/cli/lib/localDeployment/utils.js +8 -0
- package/dist/esm/cli/lib/localDeployment/utils.js.map +2 -2
- package/dist/esm/cli/lib/mcp/tools/status.js +1 -1
- package/dist/esm/cli/lib/mcp/tools/status.js.map +2 -2
- package/dist/esm/cli/lib/updates.js +11 -9
- package/dist/esm/cli/lib/updates.js.map +2 -2
- package/dist/esm/cli/lib/usage.js +2 -1
- package/dist/esm/cli/lib/usage.js.map +2 -2
- package/dist/esm/cli/lib/utils/prompts.js +2 -1
- package/dist/esm/cli/lib/utils/prompts.js.map +2 -2
- package/dist/esm/cli/lib/utils/utils.js +45 -20
- package/dist/esm/cli/lib/utils/utils.js.map +3 -3
- package/dist/esm/index.js +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/react-clerk/ConvexProviderWithClerk.js.map +1 -1
- package/dist/esm/server/components/index.js +40 -4
- package/dist/esm/server/components/index.js.map +2 -2
- package/dist/esm/server/impl/meta_impl.js +54 -0
- package/dist/esm/server/impl/meta_impl.js.map +7 -0
- package/dist/esm/server/impl/registration_impl.js +20 -11
- package/dist/esm/server/impl/registration_impl.js.map +2 -2
- package/dist/esm/server/index.js.map +2 -2
- package/dist/esm/server/meta.js +2 -0
- package/dist/esm/server/meta.js.map +7 -0
- 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/configure.test.d.ts +2 -0
- package/dist/esm-types/cli/configure.test.d.ts.map +1 -0
- package/dist/esm-types/cli/deploy.d.ts.map +1 -1
- package/dist/esm-types/cli/deploymentCreate.d.ts +1 -0
- package/dist/esm-types/cli/deploymentCreate.d.ts.map +1 -1
- package/dist/esm-types/cli/deploymentSelect.d.ts +2 -1
- package/dist/esm-types/cli/deploymentSelect.d.ts.map +1 -1
- package/dist/esm-types/cli/dev.d.ts +3 -1
- package/dist/esm-types/cli/dev.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/aiFiles/agentsmd.d.ts +5 -5
- package/dist/esm-types/cli/lib/aiFiles/agentsmd.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/aiFiles/claudemd.d.ts +5 -5
- package/dist/esm-types/cli/lib/aiFiles/claudemd.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/aiFiles/guidelinesmd.d.ts +3 -3
- package/dist/esm-types/cli/lib/aiFiles/guidelinesmd.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/aiFiles/index.d.ts +20 -18
- package/dist/esm-types/cli/lib/aiFiles/index.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/aiFiles/skills.d.ts +6 -4
- package/dist/esm-types/cli/lib/aiFiles/skills.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/aiFiles/state.d.ts +38 -0
- package/dist/esm-types/cli/lib/aiFiles/state.d.ts.map +1 -0
- package/dist/esm-types/cli/lib/aiFiles/state.test.d.ts +2 -0
- package/dist/esm-types/cli/lib/aiFiles/state.test.d.ts.map +1 -0
- package/dist/esm-types/cli/lib/aiFiles/status.d.ts +4 -1
- package/dist/esm-types/cli/lib/aiFiles/status.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/aiFiles/utils.d.ts +13 -3
- package/dist/esm-types/cli/lib/aiFiles/utils.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/aiFiles/utils.test.d.ts +2 -0
- package/dist/esm-types/cli/lib/aiFiles/utils.test.d.ts.map +1 -0
- package/dist/esm-types/cli/lib/api.d.ts +3 -3
- package/dist/esm-types/cli/lib/api.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/command.d.ts +2 -1
- package/dist/esm-types/cli/lib/command.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/config.d.ts +17 -6
- package/dist/esm-types/cli/lib/config.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/deploy2.d.ts +5 -2
- package/dist/esm-types/cli/lib/deploy2.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/deployApi/componentDefinition.d.ts +27 -12
- package/dist/esm-types/cli/lib/deployApi/componentDefinition.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/deployApi/modules.d.ts +12 -12
- package/dist/esm-types/cli/lib/deployApi/startPush.d.ts +25 -16
- package/dist/esm-types/cli/lib/deployApi/startPush.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/deploymentSelection.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/deploymentSelector.d.ts +2 -0
- package/dist/esm-types/cli/lib/deploymentSelector.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/dev.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/env.d.ts +0 -4
- package/dist/esm-types/cli/lib/env.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/envvars.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/expiration.d.ts +35 -0
- package/dist/esm-types/cli/lib/expiration.d.ts.map +1 -0
- package/dist/esm-types/cli/lib/expiration.test.d.ts +2 -0
- package/dist/esm-types/cli/lib/expiration.test.d.ts.map +1 -0
- package/dist/esm-types/cli/lib/generatedFunctionLogsApi.d.ts +16 -1
- package/dist/esm-types/cli/lib/generatedFunctionLogsApi.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/init.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/localDeployment/anonymous.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/localDeployment/localDeployment.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/localDeployment/run.d.ts +15 -0
- package/dist/esm-types/cli/lib/localDeployment/run.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/localDeployment/upgrade.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/localDeployment/utils.d.ts +7 -0
- package/dist/esm-types/cli/lib/localDeployment/utils.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/mcp/requestContext.d.ts +3 -3
- package/dist/esm-types/cli/lib/updates.d.ts +4 -3
- package/dist/esm-types/cli/lib/updates.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/usage.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/utils/prompts.d.ts +1 -0
- package/dist/esm-types/cli/lib/utils/prompts.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/utils/utils.d.ts +16 -2
- package/dist/esm-types/cli/lib/utils/utils.d.ts.map +1 -1
- package/dist/esm-types/index.d.ts +1 -1
- package/dist/esm-types/react-clerk/ConvexProviderWithClerk.d.ts +1 -1
- package/dist/esm-types/server/components/definition.d.ts +1 -0
- package/dist/esm-types/server/components/definition.d.ts.map +1 -1
- package/dist/esm-types/server/components/index.d.ts +5 -1
- package/dist/esm-types/server/components/index.d.ts.map +1 -1
- package/dist/esm-types/server/data_model.d.ts +2 -1
- package/dist/esm-types/server/data_model.d.ts.map +1 -1
- package/dist/esm-types/server/impl/meta_impl.d.ts +5 -0
- package/dist/esm-types/server/impl/meta_impl.d.ts.map +1 -0
- package/dist/esm-types/server/impl/registration_impl.d.ts.map +1 -1
- package/dist/esm-types/server/index.d.ts +1 -0
- package/dist/esm-types/server/index.d.ts.map +1 -1
- package/dist/esm-types/server/meta.d.ts +72 -0
- package/dist/esm-types/server/meta.d.ts.map +1 -0
- package/dist/esm-types/server/registration.d.ts.map +1 -1
- package/dist/react.bundle.js +1 -1
- package/dist/react.bundle.js.map +1 -1
- package/package.json +11 -7
- package/schemas/convex.schema.json +15 -2
- package/src/cli/aiFiles.ts +44 -14
- package/src/cli/configure.test.ts +138 -0
- package/src/cli/configure.ts +48 -47
- package/src/cli/deploy.ts +13 -10
- package/src/cli/deploymentCreate.test.ts +349 -14
- package/src/cli/deploymentCreate.ts +268 -41
- package/src/cli/deploymentSelect.test.ts +136 -27
- package/src/cli/deploymentSelect.ts +50 -41
- package/src/cli/deploymentSelection.test.ts +343 -35
- package/src/cli/dev.ts +49 -14
- package/src/cli/docs.ts +1 -1
- package/src/cli/init.ts +2 -2
- package/src/cli/lib/aiFiles/agentsmd.ts +15 -11
- package/src/cli/lib/aiFiles/claudemd.ts +15 -11
- package/src/cli/lib/aiFiles/guidelinesmd.test.ts +12 -2
- package/src/cli/lib/aiFiles/guidelinesmd.ts +15 -7
- package/src/cli/lib/aiFiles/index.test.ts +188 -222
- package/src/cli/lib/aiFiles/index.ts +119 -125
- package/src/cli/lib/aiFiles/integration.test.ts +112 -45
- package/src/cli/lib/aiFiles/prompt.test.ts +6 -6
- package/src/cli/lib/aiFiles/skills.ts +46 -16
- package/src/cli/lib/aiFiles/state.test.ts +280 -0
- package/src/cli/lib/aiFiles/state.ts +82 -0
- package/src/cli/lib/aiFiles/status.ts +45 -39
- package/src/cli/lib/aiFiles/utils.test.ts +50 -0
- package/src/cli/lib/aiFiles/utils.ts +38 -10
- package/src/cli/lib/api.ts +88 -7
- package/src/cli/lib/command.ts +12 -7
- package/src/cli/lib/config.test.ts +184 -7
- package/src/cli/lib/config.ts +67 -7
- package/src/cli/lib/deploy2.ts +14 -27
- package/src/cli/lib/deployApi/componentDefinition.ts +4 -1
- package/src/cli/lib/deploymentSelection.ts +59 -6
- package/src/cli/lib/deploymentSelector.test.ts +6 -0
- package/src/cli/lib/deploymentSelector.ts +2 -0
- package/src/cli/lib/dev.ts +202 -153
- package/src/cli/lib/env.ts +0 -15
- package/src/cli/lib/envvars.ts +16 -1
- package/src/cli/lib/expiration.test.ts +159 -0
- package/src/cli/lib/expiration.ts +124 -0
- package/src/cli/lib/generatedFunctionLogsApi.ts +16 -1
- package/src/cli/lib/init.ts +6 -2
- package/src/cli/lib/insights.ts +1 -1
- package/src/cli/lib/localDeployment/anonymous.ts +19 -9
- package/src/cli/lib/localDeployment/localDeployment.ts +9 -11
- package/src/cli/lib/localDeployment/run.ts +1 -1
- package/src/cli/lib/localDeployment/upgrade.ts +12 -10
- package/src/cli/lib/localDeployment/utils.ts +12 -0
- package/src/cli/lib/mcp/tools/status.ts +1 -1
- package/src/cli/lib/updates.test.ts +102 -75
- package/src/cli/lib/updates.ts +14 -12
- package/src/cli/lib/usage.ts +3 -1
- package/src/cli/lib/utils/prompts.ts +2 -0
- package/src/cli/lib/utils/utils.test.ts +6 -6
- package/src/cli/lib/utils/utils.ts +66 -27
- package/src/index.ts +1 -1
- package/src/react-clerk/ConvexProviderWithClerk.test.tsx +1 -1
- package/src/react-clerk/ConvexProviderWithClerk.tsx +1 -1
- package/src/server/components/definition.ts +3 -0
- package/src/server/components/index.ts +62 -5
- package/src/server/data_model.ts +2 -1
- package/src/server/impl/meta_impl.ts +74 -0
- package/src/server/impl/registration_impl.ts +21 -9
- package/src/server/index.ts +8 -0
- package/src/server/meta.ts +76 -0
- package/src/server/registration.ts +10 -0
- package/src/server/schema.test.ts +78 -1
- package/dist/cjs/cli/lib/aiFiles/config.js +0 -171
- package/dist/cjs/cli/lib/aiFiles/config.js.map +0 -7
- package/dist/cjs-types/cli/lib/aiFiles/config.d.ts +0 -46
- package/dist/cjs-types/cli/lib/aiFiles/config.d.ts.map +0 -1
- package/dist/cjs-types/cli/lib/aiFiles/config.test.d.ts +0 -2
- package/dist/cjs-types/cli/lib/aiFiles/config.test.d.ts.map +0 -1
- package/dist/esm/cli/lib/aiFiles/config.js +0 -135
- package/dist/esm/cli/lib/aiFiles/config.js.map +0 -7
- package/dist/esm-types/cli/lib/aiFiles/config.d.ts +0 -46
- package/dist/esm-types/cli/lib/aiFiles/config.d.ts.map +0 -1
- package/dist/esm-types/cli/lib/aiFiles/config.test.d.ts +0 -2
- package/dist/esm-types/cli/lib/aiFiles/config.test.d.ts.map +0 -1
- package/src/cli/lib/aiFiles/config.test.ts +0 -460
- package/src/cli/lib/aiFiles/config.ts +0 -188
- package/src/values/.claude/settings.local.json +0 -10
|
@@ -56,7 +56,7 @@ vi.mock("../utils/prompts.js", async (importOriginal) => {
|
|
|
56
56
|
};
|
|
57
57
|
});
|
|
58
58
|
|
|
59
|
-
import {
|
|
59
|
+
import { attemptSetupAiFiles } from "./index.js";
|
|
60
60
|
|
|
61
61
|
function makeTmpDir(): string {
|
|
62
62
|
return fs.mkdtempSync(`${os.tmpdir()}${path.sep}`);
|
|
@@ -111,7 +111,7 @@ describe("maybeSetupAiFiles interactive prompt", () => {
|
|
|
111
111
|
test("user accepts prompt: AI files are installed", async () => {
|
|
112
112
|
mockPromptYesNo.mockResolvedValue(true);
|
|
113
113
|
|
|
114
|
-
await
|
|
114
|
+
await attemptSetupAiFiles({ ctx: fakeCtx, convexDir, projectDir: tmpDir });
|
|
115
115
|
|
|
116
116
|
expect(fs.existsSync(guidelinesPath())).toBe(true);
|
|
117
117
|
expect(fs.existsSync(statePath())).toBe(true);
|
|
@@ -125,7 +125,7 @@ describe("maybeSetupAiFiles interactive prompt", () => {
|
|
|
125
125
|
test("user declines prompt: no config and no AI files are written", async () => {
|
|
126
126
|
mockPromptYesNo.mockResolvedValue(false);
|
|
127
127
|
|
|
128
|
-
await
|
|
128
|
+
await attemptSetupAiFiles({ ctx: fakeCtx, convexDir, projectDir: tmpDir });
|
|
129
129
|
|
|
130
130
|
expect(fs.existsSync(guidelinesPath())).toBe(false);
|
|
131
131
|
expect(fs.existsSync(path.join(tmpDir, "AGENTS.md"))).toBe(false);
|
|
@@ -136,7 +136,7 @@ describe("maybeSetupAiFiles interactive prompt", () => {
|
|
|
136
136
|
test("non-interactive terminal skips the prompt and does not install AI files", async () => {
|
|
137
137
|
process.stdin.isTTY = false;
|
|
138
138
|
|
|
139
|
-
await
|
|
139
|
+
await attemptSetupAiFiles({ ctx: fakeCtx, convexDir, projectDir: tmpDir });
|
|
140
140
|
|
|
141
141
|
expect(fs.existsSync(guidelinesPath())).toBe(false);
|
|
142
142
|
expect(fs.existsSync(statePath())).toBe(false);
|
|
@@ -163,7 +163,7 @@ describe("maybeSetupAiFiles interactive prompt", () => {
|
|
|
163
163
|
),
|
|
164
164
|
);
|
|
165
165
|
|
|
166
|
-
await
|
|
166
|
+
await attemptSetupAiFiles({ ctx: fakeCtx, convexDir, projectDir: tmpDir });
|
|
167
167
|
|
|
168
168
|
expect(fs.existsSync(path.join(stateDir, "ai-files.state.json"))).toBe(
|
|
169
169
|
true,
|
|
@@ -187,7 +187,7 @@ describe("maybeSetupAiFiles interactive prompt", () => {
|
|
|
187
187
|
].join("\n"),
|
|
188
188
|
);
|
|
189
189
|
|
|
190
|
-
await
|
|
190
|
+
await attemptSetupAiFiles({ ctx: fakeCtx, convexDir, projectDir: tmpDir });
|
|
191
191
|
|
|
192
192
|
expect(fs.existsSync(statePath())).toBe(true);
|
|
193
193
|
expect(fs.existsSync(guidelinesPath())).toBe(true);
|
|
@@ -5,8 +5,10 @@ import { promises as fs } from "fs";
|
|
|
5
5
|
import { chalkStderr } from "chalk";
|
|
6
6
|
import { logMessage } from "../../../bundler/log.js";
|
|
7
7
|
import { getVersion, fetchAgentSkillsSha } from "../versionApi.js";
|
|
8
|
-
import { type
|
|
9
|
-
import { iife,
|
|
8
|
+
import { type AiFilesState } from "./state.js";
|
|
9
|
+
import { exhaustiveCheck, iife, readFileOrNull } from "./utils.js";
|
|
10
|
+
|
|
11
|
+
import { type AiFilesProjectConfig } from "../config.js";
|
|
10
12
|
|
|
11
13
|
/**
|
|
12
14
|
* Read the frontmatter `name:` values from skills installed by the skills CLI.
|
|
@@ -28,7 +30,7 @@ async function readInstalledSkillNames(projectDir: string): Promise<string[]> {
|
|
|
28
30
|
const names: string[] = [];
|
|
29
31
|
for (const entry of entries) {
|
|
30
32
|
const skillMdPath = path.join(skillsDir, entry, "SKILL.md");
|
|
31
|
-
const content = await
|
|
33
|
+
const content = await readFileOrNull(skillMdPath);
|
|
32
34
|
if (content === null) continue;
|
|
33
35
|
const match = content.match(/^---[\s\S]*?^name:\s*(.+?)\s*$/m);
|
|
34
36
|
if (match) {
|
|
@@ -38,12 +40,28 @@ async function readInstalledSkillNames(projectDir: string): Promise<string[]> {
|
|
|
38
40
|
return names;
|
|
39
41
|
}
|
|
40
42
|
|
|
43
|
+
/**
|
|
44
|
+
* Resolve the configured agent list, falling back to defaults.
|
|
45
|
+
*/
|
|
46
|
+
function configuredSkillAgents(
|
|
47
|
+
aiFilesConfig?: AiFilesProjectConfig | undefined,
|
|
48
|
+
): string[] {
|
|
49
|
+
// We default to the two most popular agents for now, "codex" installs to `.agents` which also
|
|
50
|
+
// covers cursor and many other tools. See: https://github.com/vercel-labs/skills?tab=readme-ov-file#supported-agents
|
|
51
|
+
const defaultAgents = ["claude-code", "codex"];
|
|
52
|
+
return aiFilesConfig?.skills?.agents ?? defaultAgents;
|
|
53
|
+
}
|
|
54
|
+
|
|
41
55
|
/**
|
|
42
56
|
* Runs `npx skills add get-convex/agent-skills --yes` in the given directory.
|
|
43
57
|
* Returns true on success, false if the process fails or cannot be started.
|
|
44
58
|
*/
|
|
45
|
-
function runSkillsAdd(cwd: string): Promise<boolean> {
|
|
46
|
-
|
|
59
|
+
function runSkillsAdd(cwd: string, agents: string[]): Promise<boolean> {
|
|
60
|
+
const args = ["add", "get-convex/agent-skills", "--yes"];
|
|
61
|
+
for (const agent of agents) {
|
|
62
|
+
args.push("--agent", agent);
|
|
63
|
+
}
|
|
64
|
+
return runSkillsCommand(cwd, args);
|
|
47
65
|
}
|
|
48
66
|
|
|
49
67
|
/**
|
|
@@ -69,12 +87,15 @@ async function shouldRunSkillsCli(): Promise<boolean> {
|
|
|
69
87
|
|
|
70
88
|
if (versionData.kind === "error") return true;
|
|
71
89
|
|
|
72
|
-
if (versionData.
|
|
73
|
-
|
|
74
|
-
|
|
90
|
+
if (versionData.kind === "ok") {
|
|
91
|
+
if (versionData.data.disableSkillsCli) {
|
|
92
|
+
logMessage(chalkStderr.yellow(`Agent skills are temporarily disabled.`));
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
return true;
|
|
75
96
|
}
|
|
76
97
|
|
|
77
|
-
return
|
|
98
|
+
return exhaustiveCheck(versionData);
|
|
78
99
|
}
|
|
79
100
|
|
|
80
101
|
/**
|
|
@@ -118,20 +139,24 @@ async function removeSkillsLockIfEmpty({
|
|
|
118
139
|
}
|
|
119
140
|
|
|
120
141
|
/**
|
|
121
|
-
* Install Convex agent skills and record the SHA and names into the
|
|
142
|
+
* Install Convex agent skills and record the SHA and names into the state.
|
|
122
143
|
* Handles the kill-switch check and all logging internally.
|
|
123
144
|
*/
|
|
124
145
|
export async function installSkills({
|
|
125
146
|
projectDir,
|
|
126
|
-
|
|
147
|
+
state,
|
|
148
|
+
aiFilesConfig,
|
|
127
149
|
}: {
|
|
128
150
|
projectDir: string;
|
|
129
|
-
|
|
151
|
+
state: AiFilesState;
|
|
152
|
+
aiFilesConfig?: AiFilesProjectConfig | undefined;
|
|
130
153
|
}): Promise<void> {
|
|
131
154
|
if (!(await shouldRunSkillsCli())) return;
|
|
155
|
+
const agents = configuredSkillAgents(aiFilesConfig);
|
|
156
|
+
if (agents.length === 0) return;
|
|
132
157
|
|
|
133
158
|
logMessage("Installing Convex agent skills...");
|
|
134
|
-
const skillsOk = await runSkillsAdd(projectDir);
|
|
159
|
+
const skillsOk = await runSkillsAdd(projectDir, agents);
|
|
135
160
|
if (!skillsOk) {
|
|
136
161
|
logMessage(
|
|
137
162
|
chalkStderr.yellow(
|
|
@@ -142,10 +167,12 @@ export async function installSkills({
|
|
|
142
167
|
}
|
|
143
168
|
|
|
144
169
|
const sha = await fetchAgentSkillsSha();
|
|
145
|
-
if (sha)
|
|
170
|
+
if (sha) state.agentSkillsSha = sha;
|
|
146
171
|
|
|
147
172
|
const names = await readInstalledSkillNames(projectDir);
|
|
148
|
-
if (names.length > 0)
|
|
173
|
+
if (names.length > 0) state.installedSkillNames = names;
|
|
174
|
+
|
|
175
|
+
logMessage(`${chalkStderr.green("✔")} Skills installed`);
|
|
149
176
|
}
|
|
150
177
|
|
|
151
178
|
/**
|
|
@@ -159,7 +186,8 @@ export async function removeInstalledSkills({
|
|
|
159
186
|
projectDir: string;
|
|
160
187
|
skillNames: string[];
|
|
161
188
|
}): Promise<boolean> {
|
|
162
|
-
if (skillNames.length === 0
|
|
189
|
+
if (skillNames.length === 0) return false;
|
|
190
|
+
if (!(await shouldRunSkillsCli())) return false;
|
|
163
191
|
|
|
164
192
|
logMessage(`Removing Convex agent skills: ${skillNames.join(", ")}`);
|
|
165
193
|
const skillsOk = await runSkillsRemove({ cwd: projectDir, skillNames });
|
|
@@ -176,8 +204,10 @@ export async function removeInstalledSkills({
|
|
|
176
204
|
projectDir,
|
|
177
205
|
removedSkillNames: skillNames,
|
|
178
206
|
});
|
|
207
|
+
|
|
179
208
|
if (lockRemoved)
|
|
180
209
|
logMessage(`${chalkStderr.green("✔")} Deleted skills-lock.json.`);
|
|
210
|
+
|
|
181
211
|
return true;
|
|
182
212
|
}
|
|
183
213
|
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import { describe, test, expect, vi, beforeEach, afterEach } from "vitest";
|
|
2
|
+
import * as Sentry from "@sentry/node";
|
|
3
|
+
import { promises as fs } from "fs";
|
|
4
|
+
import {
|
|
5
|
+
aiFilesStateSchema,
|
|
6
|
+
attemptReadAiState,
|
|
7
|
+
hasAiState,
|
|
8
|
+
readAiStateOrDefault,
|
|
9
|
+
writeAiState,
|
|
10
|
+
} from "./state.js";
|
|
11
|
+
|
|
12
|
+
vi.mock("@sentry/node", () => ({
|
|
13
|
+
captureException: vi.fn(),
|
|
14
|
+
captureMessage: vi.fn(),
|
|
15
|
+
}));
|
|
16
|
+
|
|
17
|
+
vi.mock("fs", () => ({
|
|
18
|
+
promises: {
|
|
19
|
+
readFile: vi.fn(),
|
|
20
|
+
writeFile: vi.fn(),
|
|
21
|
+
mkdir: vi.fn().mockResolvedValue(undefined),
|
|
22
|
+
},
|
|
23
|
+
}));
|
|
24
|
+
|
|
25
|
+
const mockFs = vi.mocked(fs);
|
|
26
|
+
const mockCaptureException = vi.mocked(Sentry.captureException);
|
|
27
|
+
|
|
28
|
+
const dummyConvexDir = "/tmp/test-project/convex";
|
|
29
|
+
|
|
30
|
+
describe("aiFilesStateSchema", () => {
|
|
31
|
+
test("accepts a fully populated valid state object", () => {
|
|
32
|
+
const result = aiFilesStateSchema.safeParse({
|
|
33
|
+
guidelinesHash: "abc123",
|
|
34
|
+
agentsMdSectionHash: "def456",
|
|
35
|
+
claudeMdHash: "ghi789",
|
|
36
|
+
agentSkillsSha: "deadbeef",
|
|
37
|
+
installedSkillNames: ["convex-migrations", "convex-perf-review"],
|
|
38
|
+
});
|
|
39
|
+
expect(result.success).toBe(true);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test("accepts null hashes", () => {
|
|
43
|
+
const result = aiFilesStateSchema.safeParse({
|
|
44
|
+
guidelinesHash: null,
|
|
45
|
+
agentsMdSectionHash: null,
|
|
46
|
+
claudeMdHash: null,
|
|
47
|
+
agentSkillsSha: null,
|
|
48
|
+
});
|
|
49
|
+
expect(result.success).toBe(true);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test("applies default for installedSkillNames when absent", () => {
|
|
53
|
+
const result = aiFilesStateSchema.safeParse({
|
|
54
|
+
guidelinesHash: "abc",
|
|
55
|
+
agentsMdSectionHash: null,
|
|
56
|
+
claudeMdHash: null,
|
|
57
|
+
agentSkillsSha: null,
|
|
58
|
+
});
|
|
59
|
+
expect(result.success).toBe(true);
|
|
60
|
+
if (result.success) {
|
|
61
|
+
expect(result.data.installedSkillNames).toEqual([]);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test("rejects a number where a string hash is expected", () => {
|
|
66
|
+
const result = aiFilesStateSchema.safeParse({
|
|
67
|
+
guidelinesHash: 123,
|
|
68
|
+
agentsMdSectionHash: null,
|
|
69
|
+
claudeMdHash: null,
|
|
70
|
+
agentSkillsSha: null,
|
|
71
|
+
});
|
|
72
|
+
expect(result.success).toBe(false);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test("rejects missing required fields", () => {
|
|
76
|
+
const result = aiFilesStateSchema.safeParse({
|
|
77
|
+
guidelinesHash: "abc",
|
|
78
|
+
});
|
|
79
|
+
expect(result.success).toBe(false);
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
describe("attemptReadAiState", () => {
|
|
84
|
+
beforeEach(() => vi.clearAllMocks());
|
|
85
|
+
afterEach(() => vi.resetAllMocks());
|
|
86
|
+
|
|
87
|
+
test("returns no-file when the state file does not exist", async () => {
|
|
88
|
+
mockFs.readFile.mockRejectedValue(
|
|
89
|
+
Object.assign(new Error("ENOENT"), { code: "ENOENT" }),
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
const result = await attemptReadAiState(dummyConvexDir);
|
|
93
|
+
|
|
94
|
+
expect(result).toEqual({ kind: "no-file" });
|
|
95
|
+
expect(mockCaptureException).not.toHaveBeenCalled();
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
test("returns no-file when the state file is empty", async () => {
|
|
99
|
+
mockFs.readFile.mockResolvedValueOnce("");
|
|
100
|
+
|
|
101
|
+
const result = await attemptReadAiState(dummyConvexDir);
|
|
102
|
+
|
|
103
|
+
expect(result).toEqual({ kind: "no-file" });
|
|
104
|
+
expect(mockCaptureException).not.toHaveBeenCalled();
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
test("throws when reading the state file fails for reasons other than not found", async () => {
|
|
108
|
+
const error = Object.assign(new Error("EACCES"), { code: "EACCES" });
|
|
109
|
+
mockFs.readFile.mockRejectedValueOnce(error);
|
|
110
|
+
|
|
111
|
+
await expect(attemptReadAiState(dummyConvexDir)).rejects.toBe(error);
|
|
112
|
+
expect(mockCaptureException).not.toHaveBeenCalled();
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
test("returns ok with parsed state", async () => {
|
|
116
|
+
mockFs.readFile.mockResolvedValueOnce(
|
|
117
|
+
JSON.stringify({
|
|
118
|
+
guidelinesHash: "abc",
|
|
119
|
+
agentsMdSectionHash: "def",
|
|
120
|
+
claudeMdHash: null,
|
|
121
|
+
agentSkillsSha: null,
|
|
122
|
+
}),
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
const result = await attemptReadAiState(dummyConvexDir);
|
|
126
|
+
|
|
127
|
+
expect(result).toEqual({
|
|
128
|
+
kind: "ok",
|
|
129
|
+
state: {
|
|
130
|
+
guidelinesHash: "abc",
|
|
131
|
+
agentsMdSectionHash: "def",
|
|
132
|
+
claudeMdHash: null,
|
|
133
|
+
agentSkillsSha: null,
|
|
134
|
+
installedSkillNames: [],
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
test("returns parse-error and captures exception when JSON is invalid", async () => {
|
|
140
|
+
mockFs.readFile.mockResolvedValueOnce("not valid json {{{}");
|
|
141
|
+
|
|
142
|
+
const result = await attemptReadAiState(dummyConvexDir);
|
|
143
|
+
|
|
144
|
+
expect(result.kind).toBe("parse-error");
|
|
145
|
+
expect(mockCaptureException).toHaveBeenCalledWith(expect.any(Error));
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
test("returns parse-error and captures exception when schema validation fails", async () => {
|
|
149
|
+
mockFs.readFile.mockResolvedValueOnce(
|
|
150
|
+
JSON.stringify({
|
|
151
|
+
guidelinesHash: 99,
|
|
152
|
+
agentsMdSectionHash: null,
|
|
153
|
+
}),
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
const result = await attemptReadAiState(dummyConvexDir);
|
|
157
|
+
|
|
158
|
+
expect(result.kind).toBe("parse-error");
|
|
159
|
+
expect(mockCaptureException).toHaveBeenCalledWith(expect.any(Error));
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
describe("readAiStateOrDefault", () => {
|
|
164
|
+
beforeEach(() => vi.clearAllMocks());
|
|
165
|
+
afterEach(() => vi.resetAllMocks());
|
|
166
|
+
|
|
167
|
+
test("returns default state when no state file exists", async () => {
|
|
168
|
+
mockFs.readFile.mockRejectedValue(
|
|
169
|
+
Object.assign(new Error("ENOENT"), { code: "ENOENT" }),
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
const result = await readAiStateOrDefault(dummyConvexDir);
|
|
173
|
+
|
|
174
|
+
expect(result).toEqual({
|
|
175
|
+
guidelinesHash: null,
|
|
176
|
+
agentsMdSectionHash: null,
|
|
177
|
+
claudeMdHash: null,
|
|
178
|
+
agentSkillsSha: null,
|
|
179
|
+
installedSkillNames: [],
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
test("returns default state on parse error", async () => {
|
|
184
|
+
mockFs.readFile.mockResolvedValueOnce("not valid json {{{}");
|
|
185
|
+
|
|
186
|
+
const result = await readAiStateOrDefault(dummyConvexDir);
|
|
187
|
+
|
|
188
|
+
expect(result).toEqual({
|
|
189
|
+
guidelinesHash: null,
|
|
190
|
+
agentsMdSectionHash: null,
|
|
191
|
+
claudeMdHash: null,
|
|
192
|
+
agentSkillsSha: null,
|
|
193
|
+
installedSkillNames: [],
|
|
194
|
+
});
|
|
195
|
+
expect(mockCaptureException).toHaveBeenCalled();
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
test("returns parsed state when state file exists", async () => {
|
|
199
|
+
const stored = {
|
|
200
|
+
guidelinesHash: "abc",
|
|
201
|
+
agentsMdSectionHash: "def",
|
|
202
|
+
claudeMdHash: null,
|
|
203
|
+
agentSkillsSha: "deadbeef",
|
|
204
|
+
};
|
|
205
|
+
mockFs.readFile.mockResolvedValueOnce(JSON.stringify(stored));
|
|
206
|
+
|
|
207
|
+
const result = await readAiStateOrDefault(dummyConvexDir);
|
|
208
|
+
|
|
209
|
+
expect(result).toEqual({
|
|
210
|
+
...stored,
|
|
211
|
+
installedSkillNames: [],
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
describe("hasAiState", () => {
|
|
217
|
+
beforeEach(() => vi.clearAllMocks());
|
|
218
|
+
afterEach(() => vi.resetAllMocks());
|
|
219
|
+
|
|
220
|
+
test("returns false when state file does not exist", async () => {
|
|
221
|
+
mockFs.readFile.mockRejectedValue(
|
|
222
|
+
Object.assign(new Error("ENOENT"), { code: "ENOENT" }),
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
const result = await hasAiState(dummyConvexDir);
|
|
226
|
+
|
|
227
|
+
expect(result).toBe(false);
|
|
228
|
+
expect(mockCaptureException).not.toHaveBeenCalled();
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
test("returns true when a valid state file exists", async () => {
|
|
232
|
+
mockFs.readFile.mockResolvedValueOnce(
|
|
233
|
+
JSON.stringify({
|
|
234
|
+
guidelinesHash: "abc",
|
|
235
|
+
agentsMdSectionHash: "def",
|
|
236
|
+
claudeMdHash: null,
|
|
237
|
+
agentSkillsSha: null,
|
|
238
|
+
}),
|
|
239
|
+
);
|
|
240
|
+
|
|
241
|
+
const result = await hasAiState(dummyConvexDir);
|
|
242
|
+
|
|
243
|
+
expect(result).toBe(true);
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
test("returns false and captures exception when the state file is invalid", async () => {
|
|
247
|
+
mockFs.readFile.mockResolvedValueOnce("not valid json {{{}");
|
|
248
|
+
|
|
249
|
+
const result = await hasAiState(dummyConvexDir);
|
|
250
|
+
|
|
251
|
+
expect(result).toBe(false);
|
|
252
|
+
expect(mockCaptureException).toHaveBeenCalledWith(expect.any(Error));
|
|
253
|
+
});
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
describe("writeAiState", () => {
|
|
257
|
+
beforeEach(() => vi.clearAllMocks());
|
|
258
|
+
afterEach(() => vi.resetAllMocks());
|
|
259
|
+
|
|
260
|
+
test("writes state file", async () => {
|
|
261
|
+
mockFs.writeFile.mockResolvedValue(undefined);
|
|
262
|
+
|
|
263
|
+
const state = {
|
|
264
|
+
guidelinesHash: "abc",
|
|
265
|
+
agentsMdSectionHash: "def",
|
|
266
|
+
claudeMdHash: null,
|
|
267
|
+
agentSkillsSha: null,
|
|
268
|
+
installedSkillNames: ["convex-migrations"],
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
await writeAiState({ state, convexDir: dummyConvexDir });
|
|
272
|
+
|
|
273
|
+
expect(mockFs.writeFile).toHaveBeenCalledTimes(1);
|
|
274
|
+
expect(mockFs.writeFile).toHaveBeenCalledWith(
|
|
275
|
+
expect.stringContaining("ai-files.state.json"),
|
|
276
|
+
JSON.stringify(state, null, 2) + "\n",
|
|
277
|
+
"utf8",
|
|
278
|
+
);
|
|
279
|
+
});
|
|
280
|
+
});
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import * as Sentry from "@sentry/node";
|
|
2
|
+
// Use raw fs (not ctx.fs) so these operations run asynchronously and don't
|
|
3
|
+
// interfere with the file-watcher used by `convex dev`.
|
|
4
|
+
// eslint-disable-next-line no-restricted-imports
|
|
5
|
+
import { promises as fs } from "fs";
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
import { aiDirForConvexDir, aiFilesStatePathForConvexDir } from "./paths.js";
|
|
8
|
+
import { attemptReadFile, exhaustiveCheck } from "./utils.js";
|
|
9
|
+
|
|
10
|
+
export const aiFilesStateSchema = z.object({
|
|
11
|
+
guidelinesHash: z.string().nullable(),
|
|
12
|
+
agentsMdSectionHash: z.string().nullable(),
|
|
13
|
+
claudeMdHash: z.string().nullable(),
|
|
14
|
+
// Commit SHA from get-convex/agent-skills that was current when skills were
|
|
15
|
+
// last installed. Used to detect when newer skills are available.
|
|
16
|
+
agentSkillsSha: z.string().nullable(),
|
|
17
|
+
// Names of skills installed by `npx skills add`, used by `remove` to
|
|
18
|
+
// only remove Convex-managed skills.
|
|
19
|
+
installedSkillNames: z.array(z.string()).default([]),
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
export type AiFilesState = z.infer<typeof aiFilesStateSchema>;
|
|
23
|
+
|
|
24
|
+
const DEFAULT_AI_STATE: AiFilesState = {
|
|
25
|
+
guidelinesHash: null,
|
|
26
|
+
agentsMdSectionHash: null,
|
|
27
|
+
claudeMdHash: null,
|
|
28
|
+
agentSkillsSha: null,
|
|
29
|
+
installedSkillNames: [],
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export type AttemptReadAiStateResult =
|
|
33
|
+
| { kind: "no-file" }
|
|
34
|
+
| { kind: "ok"; state: AiFilesState }
|
|
35
|
+
| { kind: "parse-error"; error: unknown };
|
|
36
|
+
|
|
37
|
+
export async function attemptReadAiState(
|
|
38
|
+
convexDir: string,
|
|
39
|
+
): Promise<AttemptReadAiStateResult> {
|
|
40
|
+
const result = await attemptReadFile(aiFilesStatePathForConvexDir(convexDir));
|
|
41
|
+
if (result.kind === "not-found" || result.kind === "empty")
|
|
42
|
+
return { kind: "no-file" };
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
const state = aiFilesStateSchema.parse(JSON.parse(result.content));
|
|
46
|
+
return { kind: "ok", state };
|
|
47
|
+
} catch (error) {
|
|
48
|
+
Sentry.captureException(error);
|
|
49
|
+
return { kind: "parse-error", error };
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export async function readAiStateOrDefault(
|
|
54
|
+
convexDir: string,
|
|
55
|
+
): Promise<AiFilesState> {
|
|
56
|
+
const result = await attemptReadAiState(convexDir);
|
|
57
|
+
if (result.kind === "ok") return result.state;
|
|
58
|
+
if (result.kind === "no-file") return { ...DEFAULT_AI_STATE };
|
|
59
|
+
if (result.kind === "parse-error") return { ...DEFAULT_AI_STATE };
|
|
60
|
+
return exhaustiveCheck(result);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export async function hasAiState(convexDir: string): Promise<boolean> {
|
|
64
|
+
const result = await attemptReadAiState(convexDir);
|
|
65
|
+
return result.kind === "ok";
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export async function writeAiState({
|
|
69
|
+
state,
|
|
70
|
+
convexDir,
|
|
71
|
+
}: {
|
|
72
|
+
state: AiFilesState;
|
|
73
|
+
convexDir: string;
|
|
74
|
+
}): Promise<void> {
|
|
75
|
+
const validated = aiFilesStateSchema.parse(state);
|
|
76
|
+
await fs.mkdir(aiDirForConvexDir(convexDir), { recursive: true });
|
|
77
|
+
await fs.writeFile(
|
|
78
|
+
aiFilesStatePathForConvexDir(convexDir),
|
|
79
|
+
JSON.stringify(validated, null, 2) + "\n",
|
|
80
|
+
"utf8",
|
|
81
|
+
);
|
|
82
|
+
}
|