convex 1.34.0 → 1.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +98 -43
- package/dist/browser.bundle.js +13 -10
- package/dist/browser.bundle.js.map +3 -3
- package/dist/cjs/browser/index-node.js +3 -1
- package/dist/cjs/browser/index.js +3 -1
- package/dist/cjs/browser/index.js.map +2 -2
- package/dist/cjs/browser/query_options.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 +39 -20
- package/dist/cjs/cli/aiFiles.js.map +3 -3
- package/dist/cjs/cli/codegen_templates/readme.js +14 -1
- package/dist/cjs/cli/codegen_templates/readme.js.map +2 -2
- package/dist/cjs/cli/configure.js +34 -32
- package/dist/cjs/cli/configure.js.map +2 -2
- package/dist/cjs/cli/deploy.js +7 -8
- 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 +73 -0
- package/dist/cjs/cli/lib/aiFiles/agentsmd.js.map +7 -0
- package/dist/cjs/cli/lib/aiFiles/claudemd.js +73 -0
- package/dist/cjs/cli/lib/aiFiles/claudemd.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 +58 -0
- package/dist/cjs/cli/lib/aiFiles/guidelinesmd.js.map +7 -0
- package/dist/cjs/cli/lib/aiFiles/index.js +215 -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 +196 -0
- package/dist/cjs/cli/lib/aiFiles/skills.js.map +7 -0
- 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 +198 -0
- package/dist/cjs/cli/lib/aiFiles/status.js.map +7 -0
- package/dist/cjs/cli/lib/aiFiles/utils.js +128 -0
- package/dist/cjs/cli/lib/aiFiles/utils.js.map +7 -0
- 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 +10 -6
- package/dist/cjs/cli/lib/command.js.map +2 -2
- package/dist/cjs/cli/lib/config.js +43 -7
- 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/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 +15 -8
- 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 +12 -13
- 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/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/react/client.js +43 -6
- package/dist/cjs/react/client.js.map +2 -2
- package/dist/cjs/react/index.js +2 -0
- package/dist/cjs/react/index.js.map +2 -2
- package/dist/cjs/react-clerk/ConvexProviderWithClerk.js.map +1 -1
- package/dist/cjs/server/api.js.map +2 -2
- 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/browser/index.d.ts +1 -0
- package/dist/cjs-types/browser/index.d.ts.map +1 -1
- package/dist/cjs-types/browser/query_options.d.ts +12 -9
- package/dist/cjs-types/browser/query_options.d.ts.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/codegen_templates/readme.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 +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/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 +42 -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 +20 -0
- package/dist/cjs-types/cli/lib/aiFiles/skills.d.ts.map +1 -0
- 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 +6 -0
- package/dist/cjs-types/cli/lib/aiFiles/status.d.ts.map +1 -0
- package/dist/cjs-types/cli/lib/aiFiles/utils.d.ts +56 -0
- package/dist/cjs-types/cli/lib/aiFiles/utils.d.ts.map +1 -0
- 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 +18 -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/definitionConfig.d.ts +24 -24
- package/dist/cjs-types/cli/lib/deployApi/modules.d.ts +14 -14
- package/dist/cjs-types/cli/lib/deployApi/startPush.d.ts +61 -52
- 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/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/mcp/tools/insights.d.ts +2 -2
- 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/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/cjs-types/react/client.d.ts +54 -2
- package/dist/cjs-types/react/client.d.ts.map +1 -1
- package/dist/cjs-types/react/index.d.ts +7 -2
- package/dist/cjs-types/react/index.d.ts.map +1 -1
- package/dist/cjs-types/react/use_query_object_options.test.d.ts +5 -0
- package/dist/cjs-types/react/use_query_object_options.test.d.ts.map +1 -0
- package/dist/cjs-types/react/use_query_result.test.d.ts +5 -0
- package/dist/cjs-types/react/use_query_result.test.d.ts.map +1 -0
- package/dist/cjs-types/react-clerk/ConvexProviderWithClerk.d.ts +1 -1
- package/dist/cjs-types/server/api.d.ts +5 -1
- package/dist/cjs-types/server/api.d.ts.map +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 +2446 -1933
- package/dist/cli.bundle.cjs.map +4 -4
- package/dist/esm/browser/index-node.js +1 -0
- package/dist/esm/browser/index.js +1 -0
- package/dist/esm/browser/index.js.map +2 -2
- package/dist/esm/browser/query_options.js.map +2 -2
- 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 +41 -23
- package/dist/esm/cli/aiFiles.js.map +2 -2
- package/dist/esm/cli/codegen_templates/readme.js +14 -1
- package/dist/esm/cli/codegen_templates/readme.js.map +2 -2
- package/dist/esm/cli/configure.js +35 -33
- package/dist/esm/cli/configure.js.map +2 -2
- package/dist/esm/cli/deploy.js +11 -10
- 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 +56 -0
- package/dist/esm/cli/lib/aiFiles/agentsmd.js.map +7 -0
- package/dist/esm/cli/lib/aiFiles/claudemd.js +56 -0
- package/dist/esm/cli/lib/aiFiles/claudemd.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 +35 -0
- package/dist/esm/cli/lib/aiFiles/guidelinesmd.js.map +7 -0
- package/dist/esm/cli/lib/aiFiles/index.js +193 -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 +163 -0
- package/dist/esm/cli/lib/aiFiles/skills.js.map +7 -0
- 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 +178 -0
- package/dist/esm/cli/lib/aiFiles/status.js.map +7 -0
- package/dist/esm/cli/lib/aiFiles/utils.js +97 -0
- package/dist/esm/cli/lib/aiFiles/utils.js.map +7 -0
- 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 +10 -6
- package/dist/esm/cli/lib/command.js.map +2 -2
- package/dist/esm/cli/lib/config.js +41 -6
- 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/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 +14 -12
- 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/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/react/client.js +43 -6
- package/dist/esm/react/client.js.map +2 -2
- package/dist/esm/react/index.js +1 -0
- package/dist/esm/react/index.js.map +2 -2
- package/dist/esm/react-clerk/ConvexProviderWithClerk.js.map +1 -1
- package/dist/esm/server/api.js.map +2 -2
- 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/browser/index.d.ts +1 -0
- package/dist/esm-types/browser/index.d.ts.map +1 -1
- package/dist/esm-types/browser/query_options.d.ts +12 -9
- package/dist/esm-types/browser/query_options.d.ts.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/codegen_templates/readme.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 +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/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 +42 -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 +20 -0
- package/dist/esm-types/cli/lib/aiFiles/skills.d.ts.map +1 -0
- 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 +6 -0
- package/dist/esm-types/cli/lib/aiFiles/status.d.ts.map +1 -0
- package/dist/esm-types/cli/lib/aiFiles/utils.d.ts +56 -0
- package/dist/esm-types/cli/lib/aiFiles/utils.d.ts.map +1 -0
- 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 +18 -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/definitionConfig.d.ts +24 -24
- package/dist/esm-types/cli/lib/deployApi/modules.d.ts +14 -14
- package/dist/esm-types/cli/lib/deployApi/startPush.d.ts +61 -52
- 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/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/mcp/tools/insights.d.ts +2 -2
- 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/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/esm-types/react/client.d.ts +54 -2
- package/dist/esm-types/react/client.d.ts.map +1 -1
- package/dist/esm-types/react/index.d.ts +7 -2
- package/dist/esm-types/react/index.d.ts.map +1 -1
- package/dist/esm-types/react/use_query_object_options.test.d.ts +5 -0
- package/dist/esm-types/react/use_query_object_options.test.d.ts.map +1 -0
- package/dist/esm-types/react/use_query_result.test.d.ts +5 -0
- package/dist/esm-types/react/use_query_result.test.d.ts.map +1 -0
- package/dist/esm-types/react-clerk/ConvexProviderWithClerk.d.ts +1 -1
- package/dist/esm-types/server/api.d.ts +5 -1
- package/dist/esm-types/server/api.d.ts.map +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 +55 -15
- package/dist/react.bundle.js.map +3 -3
- package/package.json +11 -7
- package/schemas/convex.schema.json +22 -3
- package/src/browser/index.ts +3 -0
- package/src/browser/query_options.test.ts +0 -9
- package/src/browser/query_options.ts +36 -15
- 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 +56 -33
- package/src/cli/codegen_templates/readme.ts +14 -1
- package/src/cli/configure.test.ts +138 -0
- package/src/cli/configure.ts +62 -55
- package/src/cli/deploy.ts +12 -9
- 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 +399 -37
- 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/{ai → aiFiles}/MANUAL_TESTING.md +6 -2
- package/src/cli/lib/aiFiles/agentsmd.test.ts +133 -0
- package/src/cli/lib/aiFiles/agentsmd.ts +81 -0
- package/src/cli/lib/aiFiles/claudemd.test.ts +92 -0
- package/src/cli/lib/aiFiles/claudemd.ts +81 -0
- package/src/cli/lib/aiFiles/cursorrules.ts +25 -0
- package/src/cli/lib/aiFiles/guidelinesmd.test.ts +50 -0
- package/src/cli/lib/aiFiles/guidelinesmd.ts +49 -0
- package/src/cli/lib/{ai → aiFiles}/index.test.ts +343 -516
- package/src/cli/lib/aiFiles/index.ts +297 -0
- package/src/cli/lib/{ai → aiFiles}/integration.test.ts +195 -158
- package/src/cli/lib/{ai → aiFiles}/paths.ts +5 -0
- package/src/cli/lib/{ai → aiFiles}/prompt.test.ts +79 -31
- package/src/cli/lib/aiFiles/skills.ts +243 -0
- 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 +246 -0
- package/src/cli/lib/aiFiles/utils.test.ts +50 -0
- package/src/cli/lib/aiFiles/utils.ts +191 -0
- package/src/cli/lib/api.ts +88 -7
- package/src/cli/lib/command.ts +18 -8
- package/src/cli/lib/config.test.ts +185 -8
- package/src/cli/lib/config.ts +73 -12
- 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/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 +97 -60
- package/src/cli/lib/updates.ts +17 -15
- 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/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/react/client.test.tsx +65 -0
- package/src/react/client.ts +129 -13
- package/src/react/index.ts +9 -1
- package/src/react/use_query_object_options.test.ts +50 -0
- package/src/react/use_query_result.test.ts +41 -0
- package/src/react-clerk/ConvexProviderWithClerk.test.tsx +1 -1
- package/src/react-clerk/ConvexProviderWithClerk.tsx +1 -1
- package/src/server/api.ts +5 -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/ai/config.js +0 -144
- 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 +0 -2
- 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 +0 -109
- 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 +0 -2
- 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/config.test.ts +0 -338
- package/src/cli/lib/ai/config.ts +0 -159
- 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}/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}/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,10 @@
|
|
|
1
1
|
import { describe, test, expect, vi, beforeEach, afterEach } from "vitest";
|
|
2
|
-
import * as Sentry from "@sentry/node";
|
|
3
2
|
import { logMessage } from "../../../bundler/log.js";
|
|
4
3
|
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
} from "./
|
|
4
|
+
attemptReadAiState,
|
|
5
|
+
readAiStateOrDefault,
|
|
6
|
+
writeAiState,
|
|
7
|
+
} from "./state.js";
|
|
9
8
|
import {
|
|
10
9
|
downloadGuidelines,
|
|
11
10
|
fetchAgentSkillsSha,
|
|
@@ -15,14 +14,11 @@ import fs from "fs";
|
|
|
15
14
|
import os from "os";
|
|
16
15
|
import path from "path";
|
|
17
16
|
import {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
checkAiFilesStaleness,
|
|
21
|
-
updateAiFiles,
|
|
17
|
+
checkAiFilesStalenessAndLog,
|
|
18
|
+
installAiFiles,
|
|
22
19
|
removeAiFiles,
|
|
23
|
-
disableAiFiles,
|
|
24
|
-
statusAiFiles,
|
|
25
20
|
} from "./index.js";
|
|
21
|
+
import { statusAiFiles } from "./status.js";
|
|
26
22
|
import {
|
|
27
23
|
AGENTS_MD_START_MARKER,
|
|
28
24
|
AGENTS_MD_END_MARKER,
|
|
@@ -33,147 +29,7 @@ import {
|
|
|
33
29
|
} from "../../codegen_templates/claudemd.js";
|
|
34
30
|
|
|
35
31
|
// ---------------------------------------------------------------------------
|
|
36
|
-
//
|
|
37
|
-
// actual file I/O and string-surgery logic without complex mock wiring.
|
|
38
|
-
// ---------------------------------------------------------------------------
|
|
39
|
-
|
|
40
|
-
describe("injectAgentsMdSection", () => {
|
|
41
|
-
let tmpDir: string;
|
|
42
|
-
|
|
43
|
-
beforeEach(() => {
|
|
44
|
-
tmpDir = fs.mkdtempSync(`${os.tmpdir()}${path.sep}`);
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
afterEach(() => {
|
|
48
|
-
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
const section = `${AGENTS_MD_START_MARKER}\n## Convex\nRead guidelines.\n${AGENTS_MD_END_MARKER}`;
|
|
52
|
-
|
|
53
|
-
test("creates AGENTS.md when it does not exist", async () => {
|
|
54
|
-
await injectAgentsMdSection(section, tmpDir);
|
|
55
|
-
|
|
56
|
-
const content = fs.readFileSync(path.join(tmpDir, "AGENTS.md"), "utf8");
|
|
57
|
-
expect(content).toContain(AGENTS_MD_START_MARKER);
|
|
58
|
-
expect(content).toContain(AGENTS_MD_END_MARKER);
|
|
59
|
-
expect(content).toContain("## Convex");
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
test("appends to an existing AGENTS.md that has no Convex section", async () => {
|
|
63
|
-
const existing = "# My project\n\nSome existing content.\n";
|
|
64
|
-
fs.writeFileSync(path.join(tmpDir, "AGENTS.md"), existing);
|
|
65
|
-
|
|
66
|
-
await injectAgentsMdSection(section, tmpDir);
|
|
67
|
-
|
|
68
|
-
const content = fs.readFileSync(path.join(tmpDir, "AGENTS.md"), "utf8");
|
|
69
|
-
expect(content).toContain("# My project");
|
|
70
|
-
expect(content).toContain("Some existing content.");
|
|
71
|
-
expect(content).toContain(AGENTS_MD_START_MARKER);
|
|
72
|
-
expect(content).toContain("## Convex");
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
test("replaces an existing Convex section when markers are present", async () => {
|
|
76
|
-
const oldSection = `${AGENTS_MD_START_MARKER}\n## Convex\nOld content.\n${AGENTS_MD_END_MARKER}`;
|
|
77
|
-
const existing = `# My project\n\n${oldSection}\n`;
|
|
78
|
-
fs.writeFileSync(path.join(tmpDir, "AGENTS.md"), existing);
|
|
79
|
-
|
|
80
|
-
const newSection = `${AGENTS_MD_START_MARKER}\n## Convex\nNew content.\n${AGENTS_MD_END_MARKER}`;
|
|
81
|
-
await injectAgentsMdSection(newSection, tmpDir);
|
|
82
|
-
|
|
83
|
-
const content = fs.readFileSync(path.join(tmpDir, "AGENTS.md"), "utf8");
|
|
84
|
-
expect(content).toContain("New content.");
|
|
85
|
-
expect(content).not.toContain("Old content.");
|
|
86
|
-
// Only one occurrence of the start marker
|
|
87
|
-
expect(content.split(AGENTS_MD_START_MARKER).length - 1).toBe(1);
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
test("preserves content before and after an existing Convex section", async () => {
|
|
91
|
-
const oldSection = `${AGENTS_MD_START_MARKER}\n## Convex\nOld.\n${AGENTS_MD_END_MARKER}`;
|
|
92
|
-
const existing = `# Before\n\n${oldSection}\n\n# After\n`;
|
|
93
|
-
fs.writeFileSync(path.join(tmpDir, "AGENTS.md"), existing);
|
|
94
|
-
|
|
95
|
-
await injectAgentsMdSection(section, tmpDir);
|
|
96
|
-
|
|
97
|
-
const content = fs.readFileSync(path.join(tmpDir, "AGENTS.md"), "utf8");
|
|
98
|
-
expect(content).toContain("# Before");
|
|
99
|
-
expect(content).toContain("# After");
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
test("returns a non-null hash of the written content", async () => {
|
|
103
|
-
const hash = await injectAgentsMdSection(section, tmpDir);
|
|
104
|
-
expect(typeof hash).toBe("string");
|
|
105
|
-
expect(hash!.length).toBeGreaterThan(0);
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
test("returns hash of the section content, not the entire file", async () => {
|
|
109
|
-
fs.writeFileSync(
|
|
110
|
-
path.join(tmpDir, "AGENTS.md"),
|
|
111
|
-
"# My project\n\nExisting content.\n",
|
|
112
|
-
);
|
|
113
|
-
|
|
114
|
-
const hash = await injectAgentsMdSection(section, tmpDir);
|
|
115
|
-
|
|
116
|
-
const { hashSha256 } = await import("../utils/hash.js");
|
|
117
|
-
expect(hash).toBe(hashSha256(section));
|
|
118
|
-
});
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
describe("injectClaudeMdSection", () => {
|
|
122
|
-
let tmpDir: string;
|
|
123
|
-
|
|
124
|
-
beforeEach(() => {
|
|
125
|
-
tmpDir = fs.mkdtempSync(`${os.tmpdir()}${path.sep}`);
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
afterEach(() => {
|
|
129
|
-
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
const section = `${CLAUDE_MD_START_MARKER}\n## Convex\nRead guidelines.\n${CLAUDE_MD_END_MARKER}`;
|
|
133
|
-
|
|
134
|
-
test("creates CLAUDE.md when it does not exist", async () => {
|
|
135
|
-
const result = await injectClaudeMdSection(section, tmpDir);
|
|
136
|
-
|
|
137
|
-
const content = fs.readFileSync(path.join(tmpDir, "CLAUDE.md"), "utf8");
|
|
138
|
-
expect(content).toContain(CLAUDE_MD_START_MARKER);
|
|
139
|
-
expect(content).toContain(CLAUDE_MD_END_MARKER);
|
|
140
|
-
expect(result.didWrite).toBe(true);
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
test("appends managed section to existing CLAUDE.md content", async () => {
|
|
144
|
-
fs.writeFileSync(
|
|
145
|
-
path.join(tmpDir, "CLAUDE.md"),
|
|
146
|
-
"My custom instructions\n",
|
|
147
|
-
);
|
|
148
|
-
|
|
149
|
-
const result = await injectClaudeMdSection(section, tmpDir);
|
|
150
|
-
|
|
151
|
-
const content = fs.readFileSync(path.join(tmpDir, "CLAUDE.md"), "utf8");
|
|
152
|
-
expect(content).toContain("My custom instructions");
|
|
153
|
-
expect(content).toContain(CLAUDE_MD_START_MARKER);
|
|
154
|
-
expect(result.didWrite).toBe(true);
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
test("replaces managed section without touching user content", async () => {
|
|
158
|
-
const oldSection = `${CLAUDE_MD_START_MARKER}\nOld\n${CLAUDE_MD_END_MARKER}`;
|
|
159
|
-
fs.writeFileSync(
|
|
160
|
-
path.join(tmpDir, "CLAUDE.md"),
|
|
161
|
-
`# Header\n\n${oldSection}\n\n# Footer\n`,
|
|
162
|
-
"utf8",
|
|
163
|
-
);
|
|
164
|
-
|
|
165
|
-
await injectClaudeMdSection(section, tmpDir);
|
|
166
|
-
|
|
167
|
-
const content = fs.readFileSync(path.join(tmpDir, "CLAUDE.md"), "utf8");
|
|
168
|
-
expect(content).toContain("# Header");
|
|
169
|
-
expect(content).toContain("# Footer");
|
|
170
|
-
expect(content).toContain("## Convex");
|
|
171
|
-
expect(content).not.toContain("Old");
|
|
172
|
-
});
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
// ---------------------------------------------------------------------------
|
|
176
|
-
// checkAiFilesStaleness — mock-based: logic only, no real I/O needed.
|
|
32
|
+
// Mocks
|
|
177
33
|
// ---------------------------------------------------------------------------
|
|
178
34
|
|
|
179
35
|
vi.mock("@sentry/node", () => ({
|
|
@@ -185,10 +41,11 @@ vi.mock("../../../bundler/log.js", () => ({
|
|
|
185
41
|
logMessage: vi.fn(),
|
|
186
42
|
}));
|
|
187
43
|
|
|
188
|
-
vi.mock("./
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
44
|
+
vi.mock("./state.js", () => ({
|
|
45
|
+
attemptReadAiState: vi.fn(),
|
|
46
|
+
readAiStateOrDefault: vi.fn(),
|
|
47
|
+
writeAiState: vi.fn(),
|
|
48
|
+
hasAiState: vi.fn().mockResolvedValue(false),
|
|
192
49
|
}));
|
|
193
50
|
|
|
194
51
|
vi.mock("../versionApi.js", () => ({
|
|
@@ -201,7 +58,6 @@ vi.mock("child_process", () => ({
|
|
|
201
58
|
default: {
|
|
202
59
|
spawn: vi.fn(() => {
|
|
203
60
|
const emitter = { on: vi.fn() };
|
|
204
|
-
// Immediately simulate a successful exit.
|
|
205
61
|
emitter.on.mockImplementation(
|
|
206
62
|
(event: string, cb: (arg: number) => void) => {
|
|
207
63
|
if (event === "close") cb(0);
|
|
@@ -213,28 +69,30 @@ vi.mock("child_process", () => ({
|
|
|
213
69
|
}));
|
|
214
70
|
|
|
215
71
|
const mockLogMessage = vi.mocked(logMessage);
|
|
216
|
-
const
|
|
217
|
-
const
|
|
218
|
-
const
|
|
219
|
-
writeAiDisabledToProjectConfig,
|
|
220
|
-
);
|
|
72
|
+
const mockAttemptReadAiState = vi.mocked(attemptReadAiState);
|
|
73
|
+
const mockReadAiStateOrDefault = vi.mocked(readAiStateOrDefault);
|
|
74
|
+
const mockWriteAiState = vi.mocked(writeAiState);
|
|
221
75
|
const mockDownloadGuidelines = vi.mocked(downloadGuidelines);
|
|
222
76
|
const mockFetchAgentSkillsSha = vi.mocked(fetchAgentSkillsSha);
|
|
223
77
|
const mockGetVersion = vi.mocked(getVersion);
|
|
224
|
-
const mockCaptureException = vi.mocked(Sentry.captureException);
|
|
225
78
|
|
|
226
|
-
/** Minimal valid
|
|
227
|
-
const
|
|
79
|
+
/** Minimal valid state used across tests; includes all required fields. */
|
|
80
|
+
const baseState = {
|
|
228
81
|
guidelinesHash: null,
|
|
229
82
|
agentsMdSectionHash: null,
|
|
230
83
|
claudeMdHash: null,
|
|
231
84
|
agentSkillsSha: null,
|
|
232
85
|
installedSkillNames: [] as string[],
|
|
233
|
-
disableStalenessMessage: false,
|
|
234
86
|
};
|
|
235
87
|
|
|
88
|
+
// ---------------------------------------------------------------------------
|
|
89
|
+
// checkAiFilesStaleness
|
|
90
|
+
// ---------------------------------------------------------------------------
|
|
91
|
+
|
|
236
92
|
describe("checkAiFilesStaleness", () => {
|
|
237
|
-
beforeEach(() =>
|
|
93
|
+
beforeEach(() => {
|
|
94
|
+
vi.clearAllMocks();
|
|
95
|
+
});
|
|
238
96
|
afterEach(() => {
|
|
239
97
|
vi.unstubAllEnvs();
|
|
240
98
|
vi.resetAllMocks();
|
|
@@ -244,11 +102,16 @@ describe("checkAiFilesStaleness", () => {
|
|
|
244
102
|
const dummyConvexDir = "/tmp/test-project/convex";
|
|
245
103
|
|
|
246
104
|
test("logs install nudge when no state file exists, even with null canonical values", async () => {
|
|
247
|
-
|
|
105
|
+
mockAttemptReadAiState.mockResolvedValue({ kind: "no-file" });
|
|
248
106
|
|
|
249
|
-
await
|
|
107
|
+
await checkAiFilesStalenessAndLog({
|
|
108
|
+
canonicalGuidelinesHash: null,
|
|
109
|
+
canonicalAgentSkillsSha: null,
|
|
110
|
+
projectDir: dummyProjectDir,
|
|
111
|
+
convexDir: dummyConvexDir,
|
|
112
|
+
});
|
|
250
113
|
|
|
251
|
-
expect(
|
|
114
|
+
expect(mockAttemptReadAiState).toHaveBeenCalled();
|
|
252
115
|
expect(mockLogMessage).toHaveBeenCalledWith(
|
|
253
116
|
expect.stringContaining("npx convex ai-files install"),
|
|
254
117
|
);
|
|
@@ -257,26 +120,31 @@ describe("checkAiFilesStaleness", () => {
|
|
|
257
120
|
);
|
|
258
121
|
});
|
|
259
122
|
|
|
260
|
-
test("does nothing when both canonical values are null but
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
guidelinesHash: "some-hash",
|
|
123
|
+
test("does nothing when both canonical values are null but state exists (version server unavailable)", async () => {
|
|
124
|
+
mockAttemptReadAiState.mockResolvedValue({
|
|
125
|
+
kind: "ok",
|
|
126
|
+
state: { ...baseState, guidelinesHash: "some-hash" },
|
|
264
127
|
});
|
|
265
128
|
|
|
266
|
-
await
|
|
129
|
+
await checkAiFilesStalenessAndLog({
|
|
130
|
+
canonicalGuidelinesHash: null,
|
|
131
|
+
canonicalAgentSkillsSha: null,
|
|
132
|
+
projectDir: dummyProjectDir,
|
|
133
|
+
convexDir: dummyConvexDir,
|
|
134
|
+
});
|
|
267
135
|
|
|
268
136
|
expect(mockLogMessage).not.toHaveBeenCalled();
|
|
269
137
|
});
|
|
270
138
|
|
|
271
139
|
test("logs install nudge when no state file exists, even if canonical hashes are available", async () => {
|
|
272
|
-
|
|
140
|
+
mockAttemptReadAiState.mockResolvedValue({ kind: "no-file" });
|
|
273
141
|
|
|
274
|
-
await
|
|
275
|
-
"canonical-hash",
|
|
276
|
-
null,
|
|
277
|
-
dummyProjectDir,
|
|
278
|
-
dummyConvexDir,
|
|
279
|
-
);
|
|
142
|
+
await checkAiFilesStalenessAndLog({
|
|
143
|
+
canonicalGuidelinesHash: "canonical-hash",
|
|
144
|
+
canonicalAgentSkillsSha: null,
|
|
145
|
+
projectDir: dummyProjectDir,
|
|
146
|
+
convexDir: dummyConvexDir,
|
|
147
|
+
});
|
|
280
148
|
|
|
281
149
|
expect(mockLogMessage).toHaveBeenCalledWith(
|
|
282
150
|
expect.stringContaining("npx convex ai-files install"),
|
|
@@ -289,72 +157,48 @@ describe("checkAiFilesStaleness", () => {
|
|
|
289
157
|
);
|
|
290
158
|
});
|
|
291
159
|
|
|
292
|
-
test("
|
|
293
|
-
|
|
294
|
-
mockReadAiConfig.mockResolvedValue(null);
|
|
295
|
-
|
|
296
|
-
await checkAiFilesStaleness(
|
|
297
|
-
"canonical-hash",
|
|
298
|
-
null,
|
|
299
|
-
dummyProjectDir,
|
|
300
|
-
dummyConvexDir,
|
|
301
|
-
);
|
|
302
|
-
|
|
303
|
-
expect(mockLogMessage).toHaveBeenCalledWith(
|
|
304
|
-
expect.stringContaining("If you are an agent tell the human to run"),
|
|
305
|
-
);
|
|
306
|
-
expect(mockLogMessage).toHaveBeenCalledWith(
|
|
307
|
-
expect.stringContaining("npx convex ai-files install"),
|
|
308
|
-
);
|
|
309
|
-
expect(mockLogMessage).toHaveBeenCalledWith(
|
|
310
|
-
expect.stringContaining("npx convex ai-files disable"),
|
|
311
|
-
);
|
|
312
|
-
});
|
|
160
|
+
test("does nothing when config has enabled=false (user opted out)", async () => {
|
|
161
|
+
mockAttemptReadAiState.mockResolvedValue({ kind: "no-file" });
|
|
313
162
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
163
|
+
await checkAiFilesStalenessAndLog({
|
|
164
|
+
canonicalGuidelinesHash: "canonical-hash",
|
|
165
|
+
canonicalAgentSkillsSha: null,
|
|
166
|
+
aiFilesConfig: { enabled: false },
|
|
167
|
+
projectDir: dummyProjectDir,
|
|
168
|
+
convexDir: dummyConvexDir,
|
|
318
169
|
});
|
|
319
170
|
|
|
320
|
-
await checkAiFilesStaleness(
|
|
321
|
-
"canonical-hash",
|
|
322
|
-
null,
|
|
323
|
-
dummyProjectDir,
|
|
324
|
-
dummyConvexDir,
|
|
325
|
-
);
|
|
326
|
-
|
|
327
171
|
expect(mockLogMessage).not.toHaveBeenCalled();
|
|
328
172
|
});
|
|
329
173
|
|
|
330
174
|
test("does nothing when stored guidelines hash matches canonical", async () => {
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
guidelinesHash: "same-hash",
|
|
175
|
+
mockAttemptReadAiState.mockResolvedValue({
|
|
176
|
+
kind: "ok",
|
|
177
|
+
state: { ...baseState, guidelinesHash: "same-hash" },
|
|
334
178
|
});
|
|
335
179
|
|
|
336
|
-
await
|
|
337
|
-
"same-hash",
|
|
338
|
-
null,
|
|
339
|
-
dummyProjectDir,
|
|
340
|
-
dummyConvexDir,
|
|
341
|
-
);
|
|
180
|
+
await checkAiFilesStalenessAndLog({
|
|
181
|
+
canonicalGuidelinesHash: "same-hash",
|
|
182
|
+
canonicalAgentSkillsSha: null,
|
|
183
|
+
projectDir: dummyProjectDir,
|
|
184
|
+
convexDir: dummyConvexDir,
|
|
185
|
+
});
|
|
342
186
|
|
|
343
187
|
expect(mockLogMessage).not.toHaveBeenCalled();
|
|
344
188
|
});
|
|
345
189
|
|
|
346
190
|
test("logs nag message when guidelines hash is stale", async () => {
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
guidelinesHash: "old-hash",
|
|
191
|
+
mockAttemptReadAiState.mockResolvedValue({
|
|
192
|
+
kind: "ok",
|
|
193
|
+
state: { ...baseState, guidelinesHash: "old-hash" },
|
|
350
194
|
});
|
|
351
195
|
|
|
352
|
-
await
|
|
353
|
-
"new-canonical-hash",
|
|
354
|
-
null,
|
|
355
|
-
dummyProjectDir,
|
|
356
|
-
dummyConvexDir,
|
|
357
|
-
);
|
|
196
|
+
await checkAiFilesStalenessAndLog({
|
|
197
|
+
canonicalGuidelinesHash: "new-canonical-hash",
|
|
198
|
+
canonicalAgentSkillsSha: null,
|
|
199
|
+
projectDir: dummyProjectDir,
|
|
200
|
+
convexDir: dummyConvexDir,
|
|
201
|
+
});
|
|
358
202
|
|
|
359
203
|
expect(mockLogMessage).toHaveBeenCalledWith(
|
|
360
204
|
expect.stringContaining("npx convex ai-files update"),
|
|
@@ -362,18 +206,21 @@ describe("checkAiFilesStaleness", () => {
|
|
|
362
206
|
});
|
|
363
207
|
|
|
364
208
|
test("logs nag message when agent skills SHA is stale", async () => {
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
209
|
+
mockAttemptReadAiState.mockResolvedValue({
|
|
210
|
+
kind: "ok",
|
|
211
|
+
state: {
|
|
212
|
+
...baseState,
|
|
213
|
+
guidelinesHash: "current-hash",
|
|
214
|
+
agentSkillsSha: "old-sha",
|
|
215
|
+
},
|
|
369
216
|
});
|
|
370
217
|
|
|
371
|
-
await
|
|
372
|
-
"current-hash",
|
|
373
|
-
"new-sha",
|
|
374
|
-
dummyProjectDir,
|
|
375
|
-
dummyConvexDir,
|
|
376
|
-
);
|
|
218
|
+
await checkAiFilesStalenessAndLog({
|
|
219
|
+
canonicalGuidelinesHash: "current-hash",
|
|
220
|
+
canonicalAgentSkillsSha: "new-sha",
|
|
221
|
+
projectDir: dummyProjectDir,
|
|
222
|
+
convexDir: dummyConvexDir,
|
|
223
|
+
});
|
|
377
224
|
|
|
378
225
|
expect(mockLogMessage).toHaveBeenCalledWith(
|
|
379
226
|
expect.stringContaining("npx convex ai-files update"),
|
|
@@ -381,38 +228,44 @@ describe("checkAiFilesStaleness", () => {
|
|
|
381
228
|
});
|
|
382
229
|
|
|
383
230
|
test("does nothing when stored guidelinesHash is null (never written)", async () => {
|
|
384
|
-
|
|
231
|
+
mockAttemptReadAiState.mockResolvedValue({
|
|
232
|
+
kind: "ok",
|
|
233
|
+
state: baseState,
|
|
234
|
+
});
|
|
385
235
|
|
|
386
|
-
await
|
|
387
|
-
"some-hash",
|
|
388
|
-
"some-sha",
|
|
389
|
-
dummyProjectDir,
|
|
390
|
-
dummyConvexDir,
|
|
391
|
-
);
|
|
236
|
+
await checkAiFilesStalenessAndLog({
|
|
237
|
+
canonicalGuidelinesHash: "some-hash",
|
|
238
|
+
canonicalAgentSkillsSha: "some-sha",
|
|
239
|
+
projectDir: dummyProjectDir,
|
|
240
|
+
convexDir: dummyConvexDir,
|
|
241
|
+
});
|
|
392
242
|
|
|
393
243
|
expect(mockLogMessage).not.toHaveBeenCalled();
|
|
394
244
|
});
|
|
395
245
|
});
|
|
396
246
|
|
|
397
247
|
// ---------------------------------------------------------------------------
|
|
398
|
-
//
|
|
248
|
+
// installAiFiles
|
|
399
249
|
// ---------------------------------------------------------------------------
|
|
400
250
|
|
|
401
|
-
describe("
|
|
251
|
+
describe("installAiFiles", () => {
|
|
402
252
|
beforeEach(() => {
|
|
403
253
|
vi.clearAllMocks();
|
|
404
254
|
mockFetchAgentSkillsSha.mockResolvedValue("canonical-sha-abc123");
|
|
405
255
|
mockGetVersion.mockResolvedValue({
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
256
|
+
kind: "ok",
|
|
257
|
+
data: {
|
|
258
|
+
message: null,
|
|
259
|
+
guidelinesHash: null,
|
|
260
|
+
agentSkillsSha: "canonical-sha-abc123",
|
|
261
|
+
disableSkillsCli: false,
|
|
262
|
+
},
|
|
410
263
|
});
|
|
411
264
|
});
|
|
412
265
|
afterEach(() => vi.resetAllMocks());
|
|
413
266
|
|
|
414
|
-
test("runs full init and installs skills when no
|
|
415
|
-
|
|
267
|
+
test("runs full init and installs skills when no state exists", async () => {
|
|
268
|
+
mockReadAiStateOrDefault.mockResolvedValue(baseState);
|
|
416
269
|
|
|
417
270
|
const tmpDir = fs.mkdtempSync(`${os.tmpdir()}${path.sep}`);
|
|
418
271
|
const convexDir = path.join(tmpDir, "convex");
|
|
@@ -422,7 +275,7 @@ describe("updateAiFiles", () => {
|
|
|
422
275
|
|
|
423
276
|
mockDownloadGuidelines.mockResolvedValue("guidelines content");
|
|
424
277
|
|
|
425
|
-
await
|
|
278
|
+
await installAiFiles({ projectDir: tmpDir, convexDir });
|
|
426
279
|
|
|
427
280
|
expect(
|
|
428
281
|
fs.existsSync(
|
|
@@ -441,32 +294,6 @@ describe("updateAiFiles", () => {
|
|
|
441
294
|
}
|
|
442
295
|
});
|
|
443
296
|
|
|
444
|
-
test("reports up to date when guidelines hash already matches", async () => {
|
|
445
|
-
mockDownloadGuidelines.mockResolvedValue("guidelines content");
|
|
446
|
-
const tmpDir = fs.mkdtempSync(`${os.tmpdir()}${path.sep}`);
|
|
447
|
-
const convexDir = path.join(tmpDir, "convex");
|
|
448
|
-
|
|
449
|
-
const { hashSha256 } = await import("../utils/hash.js");
|
|
450
|
-
const realHash = hashSha256("guidelines content");
|
|
451
|
-
|
|
452
|
-
mockReadAiConfig.mockResolvedValue({
|
|
453
|
-
...baseConfig,
|
|
454
|
-
guidelinesHash: realHash,
|
|
455
|
-
agentSkillsSha: "canonical-sha-abc123",
|
|
456
|
-
});
|
|
457
|
-
|
|
458
|
-
try {
|
|
459
|
-
await updateAiFiles(tmpDir, convexDir);
|
|
460
|
-
|
|
461
|
-
expect(mockLogMessage).toHaveBeenCalledWith(
|
|
462
|
-
expect.stringContaining("already up to date"),
|
|
463
|
-
);
|
|
464
|
-
expect(mockCaptureException).not.toHaveBeenCalled();
|
|
465
|
-
} finally {
|
|
466
|
-
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
467
|
-
}
|
|
468
|
-
});
|
|
469
|
-
|
|
470
297
|
test("stores canonical agentSkillsSha and skill names after successful install", async () => {
|
|
471
298
|
const tmpDir = fs.mkdtempSync(`${os.tmpdir()}${path.sep}`);
|
|
472
299
|
const convexDir = path.join(tmpDir, "convex");
|
|
@@ -485,79 +312,20 @@ describe("updateAiFiles", () => {
|
|
|
485
312
|
}
|
|
486
313
|
|
|
487
314
|
mockDownloadGuidelines.mockResolvedValue(null);
|
|
488
|
-
|
|
489
|
-
...
|
|
315
|
+
mockReadAiStateOrDefault.mockResolvedValue({
|
|
316
|
+
...baseState,
|
|
490
317
|
agentSkillsSha: "old-sha",
|
|
491
318
|
});
|
|
492
319
|
|
|
493
|
-
await
|
|
494
|
-
|
|
495
|
-
expect(mockWriteAiConfig).toHaveBeenCalledWith(
|
|
496
|
-
expect.objectContaining({
|
|
497
|
-
agentSkillsSha: "canonical-sha-abc123",
|
|
498
|
-
installedSkillNames: ["migration-helper", "schema-builder"],
|
|
499
|
-
}),
|
|
500
|
-
expect.anything(),
|
|
501
|
-
expect.anything(),
|
|
502
|
-
);
|
|
503
|
-
} finally {
|
|
504
|
-
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
505
|
-
}
|
|
506
|
-
});
|
|
507
|
-
|
|
508
|
-
test("update does not clear disableStalenessMessage when set true", async () => {
|
|
509
|
-
const tmpDir = fs.mkdtempSync(`${os.tmpdir()}${path.sep}`);
|
|
510
|
-
const convexDir = path.join(tmpDir, "convex");
|
|
511
|
-
try {
|
|
512
|
-
mockReadAiConfig.mockResolvedValue({
|
|
513
|
-
...baseConfig,
|
|
514
|
-
disableStalenessMessage: true,
|
|
515
|
-
});
|
|
516
|
-
mockDownloadGuidelines.mockResolvedValue(null);
|
|
517
|
-
|
|
518
|
-
await updateAiFiles(tmpDir, convexDir);
|
|
519
|
-
|
|
520
|
-
expect(mockWriteAiConfig).toHaveBeenCalledWith(
|
|
521
|
-
expect.objectContaining({ disableStalenessMessage: true }),
|
|
522
|
-
expect.anything(),
|
|
523
|
-
expect.anything(),
|
|
524
|
-
);
|
|
525
|
-
} finally {
|
|
526
|
-
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
527
|
-
}
|
|
528
|
-
});
|
|
529
|
-
|
|
530
|
-
test("update recreates convex/_generated/ai when only disable config exists", async () => {
|
|
531
|
-
const tmpDir = fs.mkdtempSync(`${os.tmpdir()}${path.sep}`);
|
|
532
|
-
const convexDir = path.join(tmpDir, "convex");
|
|
533
|
-
try {
|
|
534
|
-
fs.mkdirSync(convexDir, { recursive: true });
|
|
535
|
-
fs.writeFileSync(path.join(convexDir, "schema.ts"), "");
|
|
536
|
-
fs.writeFileSync(path.join(tmpDir, "convex.json"), "{}");
|
|
537
|
-
mockReadAiConfig.mockResolvedValue({
|
|
538
|
-
...baseConfig,
|
|
539
|
-
disableStalenessMessage: true,
|
|
540
|
-
guidelinesHash: null,
|
|
541
|
-
});
|
|
542
|
-
mockDownloadGuidelines.mockResolvedValue("fresh guidelines");
|
|
543
|
-
|
|
544
|
-
await updateAiFiles(tmpDir, convexDir);
|
|
320
|
+
await installAiFiles({ projectDir: tmpDir, convexDir });
|
|
545
321
|
|
|
546
|
-
expect(
|
|
547
|
-
true,
|
|
548
|
-
);
|
|
549
|
-
expect(
|
|
550
|
-
fs.existsSync(
|
|
551
|
-
path.join(convexDir, "_generated", "ai", "guidelines.md"),
|
|
552
|
-
),
|
|
553
|
-
).toBe(true);
|
|
554
|
-
expect(mockWriteAiConfig).toHaveBeenCalledWith(
|
|
322
|
+
expect(mockWriteAiState).toHaveBeenCalledWith(
|
|
555
323
|
expect.objectContaining({
|
|
556
|
-
|
|
557
|
-
|
|
324
|
+
state: expect.objectContaining({
|
|
325
|
+
agentSkillsSha: "canonical-sha-abc123",
|
|
326
|
+
installedSkillNames: ["migration-helper", "schema-builder"],
|
|
327
|
+
}),
|
|
558
328
|
}),
|
|
559
|
-
tmpDir,
|
|
560
|
-
expect.anything(),
|
|
561
329
|
);
|
|
562
330
|
} finally {
|
|
563
331
|
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
@@ -568,10 +336,10 @@ describe("updateAiFiles", () => {
|
|
|
568
336
|
const tmpDir = fs.mkdtempSync(`${os.tmpdir()}${path.sep}`);
|
|
569
337
|
const convexDir = path.join(tmpDir, "convex");
|
|
570
338
|
try {
|
|
571
|
-
|
|
339
|
+
mockReadAiStateOrDefault.mockResolvedValue(baseState);
|
|
572
340
|
mockDownloadGuidelines.mockResolvedValue(null);
|
|
573
341
|
|
|
574
|
-
await
|
|
342
|
+
await installAiFiles({ projectDir: tmpDir, convexDir });
|
|
575
343
|
|
|
576
344
|
expect(mockLogMessage).toHaveBeenCalledWith(
|
|
577
345
|
expect.stringContaining("Could not download Convex AI guidelines"),
|
|
@@ -585,16 +353,19 @@ describe("updateAiFiles", () => {
|
|
|
585
353
|
const tmpDir = fs.mkdtempSync(`${os.tmpdir()}${path.sep}`);
|
|
586
354
|
const convexDir = path.join(tmpDir, "convex");
|
|
587
355
|
try {
|
|
588
|
-
|
|
356
|
+
mockReadAiStateOrDefault.mockResolvedValue(baseState);
|
|
589
357
|
mockDownloadGuidelines.mockResolvedValue("guidelines content");
|
|
590
358
|
mockGetVersion.mockResolvedValue({
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
359
|
+
kind: "ok",
|
|
360
|
+
data: {
|
|
361
|
+
message: null,
|
|
362
|
+
guidelinesHash: null,
|
|
363
|
+
agentSkillsSha: null,
|
|
364
|
+
disableSkillsCli: true,
|
|
365
|
+
},
|
|
595
366
|
});
|
|
596
367
|
|
|
597
|
-
await
|
|
368
|
+
await installAiFiles({ projectDir: tmpDir, convexDir });
|
|
598
369
|
|
|
599
370
|
const { default: cp } = await import("child_process");
|
|
600
371
|
const spawnCalls = vi.mocked(cp.spawn).mock.calls;
|
|
@@ -612,7 +383,7 @@ describe("updateAiFiles", () => {
|
|
|
612
383
|
});
|
|
613
384
|
|
|
614
385
|
// ---------------------------------------------------------------------------
|
|
615
|
-
// removeAiFiles
|
|
386
|
+
// removeAiFiles
|
|
616
387
|
// ---------------------------------------------------------------------------
|
|
617
388
|
|
|
618
389
|
describe("removeAiFiles", () => {
|
|
@@ -622,10 +393,13 @@ describe("removeAiFiles", () => {
|
|
|
622
393
|
beforeEach(() => {
|
|
623
394
|
vi.clearAllMocks();
|
|
624
395
|
mockGetVersion.mockResolvedValue({
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
396
|
+
kind: "ok",
|
|
397
|
+
data: {
|
|
398
|
+
message: null,
|
|
399
|
+
guidelinesHash: null,
|
|
400
|
+
agentSkillsSha: "canonical-sha-abc123",
|
|
401
|
+
disableSkillsCli: false,
|
|
402
|
+
},
|
|
629
403
|
});
|
|
630
404
|
tmpDir = fs.mkdtempSync(`${os.tmpdir()}${path.sep}`);
|
|
631
405
|
convexDir = path.join(tmpDir, "convex");
|
|
@@ -639,41 +413,47 @@ describe("removeAiFiles", () => {
|
|
|
639
413
|
vi.resetAllMocks();
|
|
640
414
|
});
|
|
641
415
|
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
fs.
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
416
|
+
test("logs nothing-to-remove when no state and no artifacts exist", async () => {
|
|
417
|
+
mockAttemptReadAiState.mockResolvedValue({ kind: "no-file" });
|
|
418
|
+
fs.rmSync(path.join(convexDir, "_generated", "ai"), { recursive: true });
|
|
419
|
+
|
|
420
|
+
await removeAiFiles({ projectDir: tmpDir, convexDir });
|
|
421
|
+
|
|
422
|
+
expect(mockLogMessage).toHaveBeenCalledWith(
|
|
423
|
+
expect.stringContaining("nothing to remove"),
|
|
648
424
|
);
|
|
649
|
-
}
|
|
425
|
+
});
|
|
650
426
|
|
|
651
|
-
test("
|
|
652
|
-
|
|
653
|
-
mockReadAiConfig.mockResolvedValue(null);
|
|
427
|
+
test("removes ai dir even when no state file exists", async () => {
|
|
428
|
+
mockAttemptReadAiState.mockResolvedValue({ kind: "no-file" });
|
|
654
429
|
|
|
655
|
-
await removeAiFiles(tmpDir, convexDir);
|
|
430
|
+
await removeAiFiles({ projectDir: tmpDir, convexDir });
|
|
656
431
|
|
|
657
432
|
expect(mockLogMessage).toHaveBeenCalledWith(
|
|
658
|
-
expect.stringContaining("
|
|
433
|
+
expect.stringContaining("Convex AI files removed"),
|
|
659
434
|
);
|
|
435
|
+
expect(fs.existsSync(path.join(convexDir, "_generated", "ai"))).toBe(false);
|
|
660
436
|
});
|
|
661
437
|
|
|
662
438
|
test("deletes AGENTS.md if stripping the Convex section leaves it empty", async () => {
|
|
663
|
-
|
|
664
|
-
|
|
439
|
+
mockAttemptReadAiState.mockResolvedValue({
|
|
440
|
+
kind: "ok",
|
|
441
|
+
state: baseState,
|
|
442
|
+
});
|
|
665
443
|
|
|
666
444
|
const agentsMdContent = `${AGENTS_MD_START_MARKER}\n## Convex\nGuidelines.\n${AGENTS_MD_END_MARKER}\n`;
|
|
667
445
|
fs.writeFileSync(path.join(tmpDir, "AGENTS.md"), agentsMdContent, "utf8");
|
|
668
446
|
|
|
669
|
-
await removeAiFiles(tmpDir, convexDir);
|
|
447
|
+
await removeAiFiles({ projectDir: tmpDir, convexDir });
|
|
670
448
|
|
|
671
449
|
expect(fs.existsSync(path.join(tmpDir, "AGENTS.md"))).toBe(false);
|
|
672
450
|
});
|
|
673
451
|
|
|
674
452
|
test("strips Convex section from AGENTS.md", async () => {
|
|
675
|
-
|
|
676
|
-
|
|
453
|
+
mockAttemptReadAiState.mockResolvedValue({
|
|
454
|
+
kind: "ok",
|
|
455
|
+
state: baseState,
|
|
456
|
+
});
|
|
677
457
|
|
|
678
458
|
const agentsMdContent =
|
|
679
459
|
`# My project\n\n` +
|
|
@@ -681,7 +461,7 @@ describe("removeAiFiles", () => {
|
|
|
681
461
|
`# After\n`;
|
|
682
462
|
fs.writeFileSync(path.join(tmpDir, "AGENTS.md"), agentsMdContent, "utf8");
|
|
683
463
|
|
|
684
|
-
await removeAiFiles(tmpDir, convexDir);
|
|
464
|
+
await removeAiFiles({ projectDir: tmpDir, convexDir });
|
|
685
465
|
|
|
686
466
|
const result = fs.readFileSync(path.join(tmpDir, "AGENTS.md"), "utf8");
|
|
687
467
|
expect(result).toContain("# My project");
|
|
@@ -691,30 +471,36 @@ describe("removeAiFiles", () => {
|
|
|
691
471
|
});
|
|
692
472
|
|
|
693
473
|
test("deletes CLAUDE.md when it only contains the managed section", async () => {
|
|
694
|
-
|
|
695
|
-
|
|
474
|
+
mockAttemptReadAiState.mockResolvedValue({
|
|
475
|
+
kind: "ok",
|
|
476
|
+
state: baseState,
|
|
477
|
+
});
|
|
696
478
|
const managed = `${CLAUDE_MD_START_MARKER}\n## Convex\nRead guidelines.\n${CLAUDE_MD_END_MARKER}\n`;
|
|
697
479
|
fs.writeFileSync(path.join(tmpDir, "CLAUDE.md"), managed, "utf8");
|
|
698
480
|
|
|
699
|
-
await removeAiFiles(tmpDir, convexDir);
|
|
481
|
+
await removeAiFiles({ projectDir: tmpDir, convexDir });
|
|
700
482
|
|
|
701
483
|
expect(fs.existsSync(path.join(tmpDir, "CLAUDE.md"))).toBe(false);
|
|
702
484
|
});
|
|
703
485
|
|
|
704
486
|
test("leaves CLAUDE.md when it has no managed markers", async () => {
|
|
705
|
-
|
|
706
|
-
|
|
487
|
+
mockAttemptReadAiState.mockResolvedValue({
|
|
488
|
+
kind: "ok",
|
|
489
|
+
state: baseState,
|
|
490
|
+
});
|
|
707
491
|
|
|
708
492
|
fs.writeFileSync(path.join(tmpDir, "CLAUDE.md"), "User content\n", "utf8");
|
|
709
493
|
|
|
710
|
-
await removeAiFiles(tmpDir, convexDir);
|
|
494
|
+
await removeAiFiles({ projectDir: tmpDir, convexDir });
|
|
711
495
|
|
|
712
496
|
expect(fs.existsSync(path.join(tmpDir, "CLAUDE.md"))).toBe(true);
|
|
713
497
|
});
|
|
714
498
|
|
|
715
499
|
test("strips only the Convex section from CLAUDE.md", async () => {
|
|
716
|
-
|
|
717
|
-
|
|
500
|
+
mockAttemptReadAiState.mockResolvedValue({
|
|
501
|
+
kind: "ok",
|
|
502
|
+
state: baseState,
|
|
503
|
+
});
|
|
718
504
|
const managed = `${CLAUDE_MD_START_MARKER}\n## Convex\nRead guidelines.\n${CLAUDE_MD_END_MARKER}`;
|
|
719
505
|
fs.writeFileSync(
|
|
720
506
|
path.join(tmpDir, "CLAUDE.md"),
|
|
@@ -722,7 +508,7 @@ describe("removeAiFiles", () => {
|
|
|
722
508
|
"utf8",
|
|
723
509
|
);
|
|
724
510
|
|
|
725
|
-
await removeAiFiles(tmpDir, convexDir);
|
|
511
|
+
await removeAiFiles({ projectDir: tmpDir, convexDir });
|
|
726
512
|
|
|
727
513
|
const content = fs.readFileSync(path.join(tmpDir, "CLAUDE.md"), "utf8");
|
|
728
514
|
expect(content).toContain("# User header");
|
|
@@ -732,9 +518,9 @@ describe("removeAiFiles", () => {
|
|
|
732
518
|
});
|
|
733
519
|
|
|
734
520
|
test("leaves CLAUDE.md alone when it has no managed markers (legacy)", async () => {
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
claudeMdHash: "some-hash",
|
|
521
|
+
mockAttemptReadAiState.mockResolvedValue({
|
|
522
|
+
kind: "ok",
|
|
523
|
+
state: { ...baseState, claudeMdHash: "some-hash" },
|
|
738
524
|
});
|
|
739
525
|
|
|
740
526
|
fs.writeFileSync(
|
|
@@ -743,7 +529,7 @@ describe("removeAiFiles", () => {
|
|
|
743
529
|
"utf8",
|
|
744
530
|
);
|
|
745
531
|
|
|
746
|
-
await removeAiFiles(tmpDir, convexDir);
|
|
532
|
+
await removeAiFiles({ projectDir: tmpDir, convexDir });
|
|
747
533
|
|
|
748
534
|
expect(fs.existsSync(path.join(tmpDir, "CLAUDE.md"))).toBe(true);
|
|
749
535
|
expect(fs.readFileSync(path.join(tmpDir, "CLAUDE.md"), "utf8")).toBe(
|
|
@@ -753,14 +539,13 @@ describe("removeAiFiles", () => {
|
|
|
753
539
|
|
|
754
540
|
test("calls skills remove for each tracked skill name", async () => {
|
|
755
541
|
const skillNames = ["migration-helper", "schema-builder"];
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
installedSkillNames: skillNames,
|
|
542
|
+
mockAttemptReadAiState.mockResolvedValue({
|
|
543
|
+
kind: "ok",
|
|
544
|
+
state: { ...baseState, installedSkillNames: skillNames },
|
|
759
545
|
});
|
|
760
546
|
|
|
761
|
-
await removeAiFiles(tmpDir, convexDir);
|
|
547
|
+
await removeAiFiles({ projectDir: tmpDir, convexDir });
|
|
762
548
|
|
|
763
|
-
// child_process.spawn should have been called with the skill names.
|
|
764
549
|
const { default: cp } = await import("child_process");
|
|
765
550
|
const spawnCalls = vi.mocked(cp.spawn).mock.calls;
|
|
766
551
|
const removeCall = spawnCalls.find(
|
|
@@ -773,10 +558,9 @@ describe("removeAiFiles", () => {
|
|
|
773
558
|
|
|
774
559
|
test("deletes skills-lock.json if it becomes empty after removing our skills", async () => {
|
|
775
560
|
const skillNames = ["migration-helper"];
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
...
|
|
779
|
-
installedSkillNames: skillNames,
|
|
561
|
+
mockAttemptReadAiState.mockResolvedValue({
|
|
562
|
+
kind: "ok",
|
|
563
|
+
state: { ...baseState, installedSkillNames: skillNames },
|
|
780
564
|
});
|
|
781
565
|
|
|
782
566
|
const lockfileContent = {
|
|
@@ -791,17 +575,16 @@ describe("removeAiFiles", () => {
|
|
|
791
575
|
"utf8",
|
|
792
576
|
);
|
|
793
577
|
|
|
794
|
-
await removeAiFiles(tmpDir, convexDir);
|
|
578
|
+
await removeAiFiles({ projectDir: tmpDir, convexDir });
|
|
795
579
|
|
|
796
580
|
expect(fs.existsSync(path.join(tmpDir, "skills-lock.json"))).toBe(false);
|
|
797
581
|
});
|
|
798
582
|
|
|
799
583
|
test("preserves skills-lock.json if it contains other skills", async () => {
|
|
800
584
|
const skillNames = ["migration-helper"];
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
...
|
|
804
|
-
installedSkillNames: skillNames,
|
|
585
|
+
mockAttemptReadAiState.mockResolvedValue({
|
|
586
|
+
kind: "ok",
|
|
587
|
+
state: { ...baseState, installedSkillNames: skillNames },
|
|
805
588
|
});
|
|
806
589
|
|
|
807
590
|
const lockfileContent = {
|
|
@@ -817,25 +600,28 @@ describe("removeAiFiles", () => {
|
|
|
817
600
|
"utf8",
|
|
818
601
|
);
|
|
819
602
|
|
|
820
|
-
await removeAiFiles(tmpDir, convexDir);
|
|
603
|
+
await removeAiFiles({ projectDir: tmpDir, convexDir });
|
|
821
604
|
|
|
822
605
|
expect(fs.existsSync(path.join(tmpDir, "skills-lock.json"))).toBe(true);
|
|
823
606
|
});
|
|
824
607
|
|
|
825
608
|
test("skips skills remove when server kill switch is enabled", async () => {
|
|
826
609
|
const skillNames = ["migration-helper"];
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
installedSkillNames: skillNames,
|
|
610
|
+
mockAttemptReadAiState.mockResolvedValue({
|
|
611
|
+
kind: "ok",
|
|
612
|
+
state: { ...baseState, installedSkillNames: skillNames },
|
|
830
613
|
});
|
|
831
614
|
mockGetVersion.mockResolvedValue({
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
615
|
+
kind: "ok",
|
|
616
|
+
data: {
|
|
617
|
+
message: null,
|
|
618
|
+
guidelinesHash: null,
|
|
619
|
+
agentSkillsSha: null,
|
|
620
|
+
disableSkillsCli: true,
|
|
621
|
+
},
|
|
836
622
|
});
|
|
837
623
|
|
|
838
|
-
await removeAiFiles(tmpDir, convexDir);
|
|
624
|
+
await removeAiFiles({ projectDir: tmpDir, convexDir });
|
|
839
625
|
|
|
840
626
|
const { default: cp } = await import("child_process");
|
|
841
627
|
const spawnCalls = vi.mocked(cp.spawn).mock.calls;
|
|
@@ -848,51 +634,20 @@ describe("removeAiFiles", () => {
|
|
|
848
634
|
);
|
|
849
635
|
});
|
|
850
636
|
|
|
851
|
-
test("does NOT write
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
// removeAiFiles should not call writeAiConfig — that is disableAiFiles's job.
|
|
858
|
-
expect(mockWriteAiConfig).not.toHaveBeenCalled();
|
|
859
|
-
});
|
|
860
|
-
|
|
861
|
-
test("disableAiFiles writes disableStalenessMessage=true without removing files", async () => {
|
|
862
|
-
writeConfig({ guidelinesHash: null });
|
|
863
|
-
mockReadAiConfig.mockResolvedValue(baseConfig);
|
|
864
|
-
|
|
865
|
-
fs.writeFileSync(
|
|
866
|
-
path.join(convexDir, "_generated", "ai", "guidelines.md"),
|
|
867
|
-
"guidelines content",
|
|
868
|
-
"utf8",
|
|
869
|
-
);
|
|
870
|
-
|
|
871
|
-
await disableAiFiles(tmpDir);
|
|
872
|
-
|
|
873
|
-
expect(mockWriteAiDisabledToProjectConfig).toHaveBeenCalledWith(
|
|
874
|
-
true,
|
|
875
|
-
tmpDir,
|
|
876
|
-
);
|
|
877
|
-
expect(
|
|
878
|
-
fs.existsSync(path.join(convexDir, "_generated", "ai", "guidelines.md")),
|
|
879
|
-
).toBe(true);
|
|
880
|
-
});
|
|
881
|
-
|
|
882
|
-
test("disableAiFiles writes config to project root, not convex dir", async () => {
|
|
883
|
-
mockReadAiConfig.mockResolvedValue(null);
|
|
637
|
+
test("does NOT write state after plain remove", async () => {
|
|
638
|
+
mockAttemptReadAiState.mockResolvedValue({
|
|
639
|
+
kind: "ok",
|
|
640
|
+
state: baseState,
|
|
641
|
+
});
|
|
884
642
|
|
|
885
|
-
await
|
|
643
|
+
await removeAiFiles({ projectDir: tmpDir, convexDir });
|
|
886
644
|
|
|
887
|
-
expect(
|
|
888
|
-
true,
|
|
889
|
-
tmpDir,
|
|
890
|
-
);
|
|
645
|
+
expect(mockWriteAiState).not.toHaveBeenCalled();
|
|
891
646
|
});
|
|
892
647
|
});
|
|
893
648
|
|
|
894
649
|
// ---------------------------------------------------------------------------
|
|
895
|
-
// statusAiFiles
|
|
650
|
+
// statusAiFiles
|
|
896
651
|
// ---------------------------------------------------------------------------
|
|
897
652
|
|
|
898
653
|
describe("statusAiFiles", () => {
|
|
@@ -902,18 +657,24 @@ describe("statusAiFiles", () => {
|
|
|
902
657
|
beforeEach(() => {
|
|
903
658
|
vi.clearAllMocks();
|
|
904
659
|
mockGetVersion.mockResolvedValue({
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
660
|
+
kind: "ok",
|
|
661
|
+
data: {
|
|
662
|
+
message: null,
|
|
663
|
+
guidelinesHash: "canonical-guidelines-hash",
|
|
664
|
+
agentSkillsSha: "canonical-skills-sha",
|
|
665
|
+
disableSkillsCli: false,
|
|
666
|
+
},
|
|
909
667
|
});
|
|
910
668
|
});
|
|
911
669
|
afterEach(() => vi.resetAllMocks());
|
|
912
670
|
|
|
913
|
-
test("reports not installed when
|
|
914
|
-
|
|
671
|
+
test("reports not installed when state is missing", async () => {
|
|
672
|
+
mockAttemptReadAiState.mockResolvedValue({ kind: "no-file" });
|
|
915
673
|
|
|
916
|
-
await statusAiFiles(
|
|
674
|
+
await statusAiFiles({
|
|
675
|
+
projectDir: dummyProjectDir,
|
|
676
|
+
convexDir: dummyConvexDir,
|
|
677
|
+
});
|
|
917
678
|
|
|
918
679
|
expect(mockLogMessage).toHaveBeenCalledWith(
|
|
919
680
|
expect.stringContaining("not installed"),
|
|
@@ -923,14 +684,13 @@ describe("statusAiFiles", () => {
|
|
|
923
684
|
);
|
|
924
685
|
});
|
|
925
686
|
|
|
926
|
-
test("reports disabled when config has
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
687
|
+
test("reports disabled when config has enabled=false", async () => {
|
|
688
|
+
await statusAiFiles({
|
|
689
|
+
projectDir: dummyProjectDir,
|
|
690
|
+
convexDir: dummyConvexDir,
|
|
691
|
+
aiFilesConfig: { enabled: false },
|
|
930
692
|
});
|
|
931
693
|
|
|
932
|
-
await statusAiFiles(dummyProjectDir, dummyConvexDir);
|
|
933
|
-
|
|
934
694
|
expect(mockLogMessage).toHaveBeenCalledWith(
|
|
935
695
|
expect.stringContaining("disabled"),
|
|
936
696
|
);
|
|
@@ -939,10 +699,16 @@ describe("statusAiFiles", () => {
|
|
|
939
699
|
);
|
|
940
700
|
});
|
|
941
701
|
|
|
942
|
-
test("reports enabled when
|
|
943
|
-
|
|
702
|
+
test("reports enabled when state exists and messages are not disabled", async () => {
|
|
703
|
+
mockAttemptReadAiState.mockResolvedValue({
|
|
704
|
+
kind: "ok",
|
|
705
|
+
state: baseState,
|
|
706
|
+
});
|
|
944
707
|
|
|
945
|
-
await statusAiFiles(
|
|
708
|
+
await statusAiFiles({
|
|
709
|
+
projectDir: dummyProjectDir,
|
|
710
|
+
convexDir: dummyConvexDir,
|
|
711
|
+
});
|
|
946
712
|
|
|
947
713
|
expect(mockLogMessage).toHaveBeenCalledWith(
|
|
948
714
|
expect.stringContaining("enabled"),
|
|
@@ -966,18 +732,21 @@ describe("statusAiFiles", () => {
|
|
|
966
732
|
"utf8",
|
|
967
733
|
);
|
|
968
734
|
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
guidelinesHash: hash,
|
|
735
|
+
mockAttemptReadAiState.mockResolvedValue({
|
|
736
|
+
kind: "ok",
|
|
737
|
+
state: { ...baseState, guidelinesHash: hash },
|
|
972
738
|
});
|
|
973
739
|
mockGetVersion.mockResolvedValue({
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
740
|
+
kind: "ok",
|
|
741
|
+
data: {
|
|
742
|
+
message: null,
|
|
743
|
+
guidelinesHash: hash,
|
|
744
|
+
agentSkillsSha: null,
|
|
745
|
+
disableSkillsCli: false,
|
|
746
|
+
},
|
|
978
747
|
});
|
|
979
748
|
|
|
980
|
-
await statusAiFiles(tmpDir, convexDir);
|
|
749
|
+
await statusAiFiles({ projectDir: tmpDir, convexDir });
|
|
981
750
|
|
|
982
751
|
const calls = mockLogMessage.mock.calls.map((c) => c[0]);
|
|
983
752
|
expect(calls.some((m) => /guidelines\.md.*up to date/.test(m))).toBe(
|
|
@@ -1004,18 +773,21 @@ describe("statusAiFiles", () => {
|
|
|
1004
773
|
"utf8",
|
|
1005
774
|
);
|
|
1006
775
|
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
guidelinesHash: hashSha256(content),
|
|
776
|
+
mockAttemptReadAiState.mockResolvedValue({
|
|
777
|
+
kind: "ok",
|
|
778
|
+
state: { ...baseState, guidelinesHash: hashSha256(content) },
|
|
1010
779
|
});
|
|
1011
780
|
mockGetVersion.mockResolvedValue({
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
781
|
+
kind: "ok",
|
|
782
|
+
data: {
|
|
783
|
+
message: null,
|
|
784
|
+
guidelinesHash: "new-canonical-hash",
|
|
785
|
+
agentSkillsSha: null,
|
|
786
|
+
disableSkillsCli: false,
|
|
787
|
+
},
|
|
1016
788
|
});
|
|
1017
789
|
|
|
1018
|
-
await statusAiFiles(tmpDir, convexDir);
|
|
790
|
+
await statusAiFiles({ projectDir: tmpDir, convexDir });
|
|
1019
791
|
|
|
1020
792
|
expect(mockLogMessage).toHaveBeenCalledWith(
|
|
1021
793
|
expect.stringContaining("out of date"),
|
|
@@ -1043,12 +815,15 @@ describe("statusAiFiles", () => {
|
|
|
1043
815
|
"utf8",
|
|
1044
816
|
);
|
|
1045
817
|
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
818
|
+
mockAttemptReadAiState.mockResolvedValue({
|
|
819
|
+
kind: "ok",
|
|
820
|
+
state: {
|
|
821
|
+
...baseState,
|
|
822
|
+
guidelinesHash: hashSha256("original content"),
|
|
823
|
+
},
|
|
1049
824
|
});
|
|
1050
825
|
|
|
1051
|
-
await statusAiFiles(tmpDir, convexDir);
|
|
826
|
+
await statusAiFiles({ projectDir: tmpDir, convexDir });
|
|
1052
827
|
|
|
1053
828
|
expect(mockLogMessage).toHaveBeenCalledWith(
|
|
1054
829
|
expect.stringContaining("modified locally"),
|
|
@@ -1058,20 +833,57 @@ describe("statusAiFiles", () => {
|
|
|
1058
833
|
}
|
|
1059
834
|
});
|
|
1060
835
|
|
|
836
|
+
test("reports guidelines as missing when guidelines.md is empty", async () => {
|
|
837
|
+
const tmpDir = fs.mkdtempSync(`${os.tmpdir()}${path.sep}`);
|
|
838
|
+
const convexDir = path.join(tmpDir, "convex");
|
|
839
|
+
try {
|
|
840
|
+
fs.mkdirSync(path.join(convexDir, "_generated", "ai"), {
|
|
841
|
+
recursive: true,
|
|
842
|
+
});
|
|
843
|
+
fs.writeFileSync(
|
|
844
|
+
path.join(convexDir, "_generated", "ai", "guidelines.md"),
|
|
845
|
+
"",
|
|
846
|
+
"utf8",
|
|
847
|
+
);
|
|
848
|
+
|
|
849
|
+
mockAttemptReadAiState.mockResolvedValue({
|
|
850
|
+
kind: "ok",
|
|
851
|
+
state: baseState,
|
|
852
|
+
});
|
|
853
|
+
|
|
854
|
+
await statusAiFiles({ projectDir: tmpDir, convexDir });
|
|
855
|
+
|
|
856
|
+
expect(mockLogMessage).toHaveBeenCalledWith(
|
|
857
|
+
expect.stringContaining("guidelines.md: not on disk"),
|
|
858
|
+
);
|
|
859
|
+
} finally {
|
|
860
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
861
|
+
}
|
|
862
|
+
});
|
|
863
|
+
|
|
1061
864
|
test("reports agent skills as out of date when SHA differs from canonical", async () => {
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
865
|
+
mockAttemptReadAiState.mockResolvedValue({
|
|
866
|
+
kind: "ok",
|
|
867
|
+
state: {
|
|
868
|
+
...baseState,
|
|
869
|
+
installedSkillNames: ["migration-helper"],
|
|
870
|
+
agentSkillsSha: "old-sha",
|
|
871
|
+
},
|
|
1066
872
|
});
|
|
1067
873
|
mockGetVersion.mockResolvedValue({
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
874
|
+
kind: "ok",
|
|
875
|
+
data: {
|
|
876
|
+
message: null,
|
|
877
|
+
guidelinesHash: null,
|
|
878
|
+
agentSkillsSha: "new-sha",
|
|
879
|
+
disableSkillsCli: false,
|
|
880
|
+
},
|
|
1072
881
|
});
|
|
1073
882
|
|
|
1074
|
-
await statusAiFiles(
|
|
883
|
+
await statusAiFiles({
|
|
884
|
+
projectDir: dummyProjectDir,
|
|
885
|
+
convexDir: dummyConvexDir,
|
|
886
|
+
});
|
|
1075
887
|
|
|
1076
888
|
expect(mockLogMessage).toHaveBeenCalledWith(
|
|
1077
889
|
expect.stringContaining("out of date"),
|
|
@@ -1082,28 +894,40 @@ describe("statusAiFiles", () => {
|
|
|
1082
894
|
});
|
|
1083
895
|
|
|
1084
896
|
test("skips staleness check when network is unavailable", async () => {
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
897
|
+
mockAttemptReadAiState.mockResolvedValue({
|
|
898
|
+
kind: "ok",
|
|
899
|
+
state: {
|
|
900
|
+
...baseState,
|
|
901
|
+
guidelinesHash: "old-hash",
|
|
902
|
+
agentSkillsSha: "old-sha",
|
|
903
|
+
installedSkillNames: ["migration-helper"],
|
|
904
|
+
},
|
|
1090
905
|
});
|
|
1091
|
-
mockGetVersion.mockResolvedValue(
|
|
906
|
+
mockGetVersion.mockResolvedValue({ kind: "error" });
|
|
1092
907
|
|
|
1093
|
-
await statusAiFiles(
|
|
908
|
+
await statusAiFiles({
|
|
909
|
+
projectDir: dummyProjectDir,
|
|
910
|
+
convexDir: dummyConvexDir,
|
|
911
|
+
});
|
|
1094
912
|
|
|
1095
913
|
const calls = mockLogMessage.mock.calls.map((c) => c[0]);
|
|
1096
914
|
expect(calls.some((m) => /out of date/.test(m))).toBe(false);
|
|
1097
915
|
});
|
|
1098
916
|
|
|
1099
917
|
test("reports skills with names when installed", async () => {
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
918
|
+
mockAttemptReadAiState.mockResolvedValue({
|
|
919
|
+
kind: "ok",
|
|
920
|
+
state: {
|
|
921
|
+
...baseState,
|
|
922
|
+
installedSkillNames: ["migration-helper", "schema-builder"],
|
|
923
|
+
agentSkillsSha: "canonical-skills-sha",
|
|
924
|
+
},
|
|
1104
925
|
});
|
|
1105
926
|
|
|
1106
|
-
await statusAiFiles(
|
|
927
|
+
await statusAiFiles({
|
|
928
|
+
projectDir: dummyProjectDir,
|
|
929
|
+
convexDir: dummyConvexDir,
|
|
930
|
+
});
|
|
1107
931
|
|
|
1108
932
|
expect(mockLogMessage).toHaveBeenCalledWith(
|
|
1109
933
|
expect.stringContaining("migration-helper"),
|
|
@@ -1122,9 +946,12 @@ describe("statusAiFiles", () => {
|
|
|
1122
946
|
"User content\n",
|
|
1123
947
|
"utf8",
|
|
1124
948
|
);
|
|
1125
|
-
|
|
949
|
+
mockAttemptReadAiState.mockResolvedValue({
|
|
950
|
+
kind: "ok",
|
|
951
|
+
state: baseState,
|
|
952
|
+
});
|
|
1126
953
|
|
|
1127
|
-
await statusAiFiles(tmpDir, convexDir);
|
|
954
|
+
await statusAiFiles({ projectDir: tmpDir, convexDir });
|
|
1128
955
|
|
|
1129
956
|
expect(mockLogMessage).toHaveBeenCalledWith(
|
|
1130
957
|
expect.stringContaining("CLAUDE.md: no Convex section present"),
|