From ddd5fa0ad3d2302c1b5a9326579fa16e747eb3ed Mon Sep 17 00:00:00 2001 From: Kosta Petan Date: Fri, 3 Nov 2023 21:46:25 +0100 Subject: [PATCH] Ingest repo (C# only) (#7) * ingest WIP function * ingest WIP * analyze WIP * WIP * ingester WIP * ingester WIP * ingester WIP * fix github download * working ingester --- .devcontainer/Dockerfile | 6 +- .devcontainer/devcontainer.json | 11 +- .gitignore | 3 +- .vscode/launch.json | 25 +- .vscode/settings.json | 9 +- .vscode/tasks.json | 176 ++-- .../Activities/PullRequestActivities.cs | 1 - src/apps/gh-flow/Program.cs | 8 + .../Services/GithubWebHookProcessor.cs | 19 + src/apps/gh-flow/gh-flow.csproj | 1 + src/apps/ingest/.funcignore | 10 + src/apps/ingest/.gitignore | 99 +++ src/apps/ingest/host.json | 15 + src/apps/ingest/package-lock.json | 818 ++++++++++++++++++ src/apps/ingest/package.json | 17 + src/apps/ingest/src/functions/AnalyzeCode.js | 42 + .../Actors/Ingester/IIngestRepo.cs | 9 + .../Actors/Ingester/Ingester.cs | 39 + .../Options/ServiceOptions.cs | 4 + .../Services/CodeAnalyzer.cs | 45 + .../Services/GithubService.cs | 54 +- 21 files changed, 1309 insertions(+), 102 deletions(-) create mode 100644 src/apps/ingest/.funcignore create mode 100644 src/apps/ingest/.gitignore create mode 100644 src/apps/ingest/host.json create mode 100644 src/apps/ingest/package-lock.json create mode 100644 src/apps/ingest/package.json create mode 100644 src/apps/ingest/src/functions/AnalyzeCode.js create mode 100644 src/libs/Microsoft.AI.DevTeam/Actors/Ingester/IIngestRepo.cs create mode 100644 src/libs/Microsoft.AI.DevTeam/Actors/Ingester/Ingester.cs create mode 100644 src/libs/Microsoft.AI.DevTeam/Options/ServiceOptions.cs create mode 100644 src/libs/Microsoft.AI.DevTeam/Services/CodeAnalyzer.cs diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index ed0bd230c..3aacb89db 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,6 +1,6 @@ FROM mcr.microsoft.com/devcontainers/dotnet:0-7.0 # Install the xz-utils package -RUN apt-get update && apt-get install -y xz-utils nodejs npm +RUN apt-get update && apt-get install -y xz-utils ca-certificates curl gnupg RUN curl -fsSL https://aka.ms/install-azd.sh | bash @@ -8,6 +8,4 @@ RUN curl -s https://ngrok-agent.s3.amazonaws.com/ngrok.asc | \ sudo tee /etc/apt/trusted.gpg.d/ngrok.asc >/dev/null && \ echo "deb https://ngrok-agent.s3.amazonaws.com buster main" | \ sudo tee /etc/apt/sources.list.d/ngrok.list && \ - sudo apt update && sudo apt install ngrok - -RUN npm i -g azure-functions-core-tools@4 --unsafe-perm true \ No newline at end of file + sudo apt update && sudo apt install ngrok \ No newline at end of file diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 61446950c..c0a345e21 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -10,7 +10,16 @@ "ghcr.io/devcontainers/features/azure-cli:1": {}, "ghcr.io/devcontainers/features/common-utils:2": {}, "ghcr.io/devcontainers/features/docker-in-docker:2": {}, - "ghcr.io/azure/azure-dev/azd:latest": {} + "ghcr.io/azure/azure-dev/azd:latest": {}, + "ghcr.io/devcontainers/features/node:1": { + "nodeGypDependencies": true, + "version": "18", + "nvmVersion": "latest" + }, + "ghcr.io/azure/azure-dev/azd:0": { + "version": "stable" + }, + "ghcr.io/jlaundry/devcontainer-features/azure-functions-core-tools:1": {} }, "postCreateCommand": "bash .devcontainer/startup.sh", "hostRequirements": { diff --git a/.gitignore b/.gitignore index af040acbd..dc3d5b131 100644 --- a/.gitignore +++ b/.gitignore @@ -495,4 +495,5 @@ elsa.sqlite.* elsa-core/ sk-azfunc-server/local.settings.json .azure -temp \ No newline at end of file +temp + diff --git a/.vscode/launch.json b/.vscode/launch.json index 894cbe6aa..f3ac25524 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,11 +1,18 @@ { - "version": "0.2.0", - "configurations": [ - { - "name": "Attach to .NET Functions", - "type": "coreclr", - "request": "attach", - "processId": "${command:azureFunctions.pickProcess}" - } - ] + "version": "0.2.0", + "configurations": [ + { + "name": "Attach to .NET Functions", + "type": "coreclr", + "request": "attach", + "processId": "${command:azureFunctions.pickProcess}" + }, + { + "name": "Attach to Node Functions", + "type": "node", + "request": "attach", + "port": 9229, + "preLaunchTask": "func: host start" + } + ] } \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 765a2c0e3..a13b8792c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,8 +1,11 @@ { "dotnet.defaultSolution": "sk-dev-team.sln", - "azureFunctions.deploySubpath": "sk-azfunc-server/bin/Release/net7.0/publish", - "azureFunctions.projectLanguage": "C#", + "azureFunctions.deploySubpath": "src/apps/ingest", + "azureFunctions.projectLanguage": "JavaScript", "azureFunctions.projectRuntime": "~4", "debug.internalConsoleOptions": "neverOpen", - "azureFunctions.preDeployTask": "publish (functions)" + "azureFunctions.preDeployTask": "npm prune (functions)", + "azureFunctions.postDeployTask": "npm install (functions)", + "azureFunctions.projectLanguageModel": 4, + "azureFunctions.projectSubpath": "src/apps/ingest" } \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 91399018e..ef996066e 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -1,81 +1,99 @@ { - "version": "2.0.0", - "tasks": [ - { - "label": "clean (functions)", - "command": "dotnet", - "args": [ - "clean", - "/property:GenerateFullPaths=true", - "/consoleloggerparameters:NoSummary" - ], - "type": "process", - "problemMatcher": "$msCompile", - "options": { - "cwd": "${workspaceFolder}/sk-azfunc-server" - } - }, - { - "label": "build (functions)", - "command": "dotnet", - "args": [ - "build", - "/property:GenerateFullPaths=true", - "/consoleloggerparameters:NoSummary" - ], - "type": "process", - "dependsOn": "clean (functions)", - "group": { - "kind": "build", - "isDefault": true - }, - "problemMatcher": "$msCompile", - "options": { - "cwd": "${workspaceFolder}/sk-azfunc-server" - } - }, - { - "label": "clean release (functions)", - "command": "dotnet", - "args": [ - "clean", - "--configuration", - "Release", - "/property:GenerateFullPaths=true", - "/consoleloggerparameters:NoSummary" - ], - "type": "process", - "problemMatcher": "$msCompile", - "options": { - "cwd": "${workspaceFolder}/sk-azfunc-server" - } - }, - { - "label": "publish (functions)", - "command": "dotnet", - "args": [ - "publish", - "--configuration", - "Release", - "/property:GenerateFullPaths=true", - "/consoleloggerparameters:NoSummary" - ], - "type": "process", - "dependsOn": "clean release (functions)", - "problemMatcher": "$msCompile", - "options": { - "cwd": "${workspaceFolder}/sk-azfunc-server" - } - }, - { - "type": "func", - "dependsOn": "build (functions)", - "options": { - "cwd": "${workspaceFolder}/sk-azfunc-server/bin/Debug/net7.0" - }, - "command": "host start", - "isBackground": true, - "problemMatcher": "$func-dotnet-watch" - } - ] + "version": "2.0.0", + "tasks": [ + { + "label": "clean (functions)", + "command": "dotnet", + "args": [ + "clean", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "type": "process", + "problemMatcher": "$msCompile", + "options": { + "cwd": "${workspaceFolder}/sk-azfunc-server" + } + }, + { + "label": "build (functions)", + "command": "dotnet", + "args": [ + "build", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "type": "process", + "dependsOn": "clean (functions)", + "group": { + "kind": "build", + "isDefault": true + }, + "problemMatcher": "$msCompile", + "options": { + "cwd": "${workspaceFolder}/sk-azfunc-server" + } + }, + { + "label": "clean release (functions)", + "command": "dotnet", + "args": [ + "clean", + "--configuration", + "Release", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "type": "process", + "problemMatcher": "$msCompile", + "options": { + "cwd": "${workspaceFolder}/sk-azfunc-server" + } + }, + { + "label": "publish (functions)", + "command": "dotnet", + "args": [ + "publish", + "--configuration", + "Release", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "type": "process", + "dependsOn": "clean release (functions)", + "problemMatcher": "$msCompile", + "options": { + "cwd": "${workspaceFolder}/sk-azfunc-server" + } + }, + { + "type": "func", + "label": "func: host start", + "command": "host start", + "problemMatcher": "$func-node-watch", + "isBackground": true, + "dependsOn": "npm install (functions)", + "options": { + "cwd": "${workspaceFolder}/src/apps/ingest" + } + }, + { + "type": "shell", + "label": "npm install (functions)", + "command": "npm install", + "options": { + "cwd": "${workspaceFolder}/src/apps/ingest" + } + }, + { + "type": "shell", + "label": "npm prune (functions)", + "command": "npm prune --production", + "problemMatcher": [], + "options": { + "cwd": "${workspaceFolder}/src/apps/ingest" + } + } + ] } \ No newline at end of file diff --git a/src/apps/gh-flow-df/Activities/PullRequestActivities.cs b/src/apps/gh-flow-df/Activities/PullRequestActivities.cs index f8794b0c2..d9734ee55 100644 --- a/src/apps/gh-flow-df/Activities/PullRequestActivities.cs +++ b/src/apps/gh-flow-df/Activities/PullRequestActivities.cs @@ -8,7 +8,6 @@ using Azure.ResourceManager.ContainerInstance; using Azure.ResourceManager.ContainerInstance.Models; using Azure.ResourceManager.Resources; using Azure.Storage.Files.Shares; -using Microsoft.AspNetCore.Http; using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; using Microsoft.DurableTask.Client; diff --git a/src/apps/gh-flow/Program.cs b/src/apps/gh-flow/Program.cs index c8a7da568..1a7418828 100644 --- a/src/apps/gh-flow/Program.cs +++ b/src/apps/gh-flow/Program.cs @@ -12,6 +12,7 @@ using Orleans.Configuration; var builder = WebApplication.CreateBuilder(args); builder.Services.AddSingleton(); builder.Services.AddTransient(CreateKernel); +builder.Services.AddHttpClient(); builder.Services.AddSingleton(s => { @@ -43,9 +44,15 @@ builder.Services.AddOptions() { configuration.GetSection("QdrantOptions").Bind(settings); }); +builder.Services.AddOptions() + .Configure((settings, configuration) => + { + configuration.GetSection("ServiceOptions").Bind(settings); + }); builder.Services.AddSingleton(); builder.Services.AddSingleton(); +builder.Services.AddSingleton(); builder.Host.UseOrleans(siloBuilder => @@ -130,6 +137,7 @@ app.UseEndpoints(endpoints => endpoints.MapGitHubWebhooks(); }); + app.Run(); static IKernel CreateKernel(IServiceProvider provider) diff --git a/src/apps/gh-flow/Services/GithubWebHookProcessor.cs b/src/apps/gh-flow/Services/GithubWebHookProcessor.cs index f873b73c7..708e7bff1 100644 --- a/src/apps/gh-flow/Services/GithubWebHookProcessor.cs +++ b/src/apps/gh-flow/Services/GithubWebHookProcessor.cs @@ -2,6 +2,7 @@ using Microsoft.AI.DevTeam; using Microsoft.AI.DevTeam.Skills; using Octokit.Webhooks; using Octokit.Webhooks.Events; +using Octokit.Webhooks.Events.CommitComment; using Octokit.Webhooks.Events.IssueComment; using Octokit.Webhooks.Events.Issues; using Octokit.Webhooks.Models; @@ -62,6 +63,19 @@ public sealed class GithubWebHookProcessor : WebhookEventProcessor } } + // TODO: implement + protected override Task ProcessPushWebhookAsync(WebhookHeaders headers, PushEvent pushEvent) + { + var org = pushEvent.Organization.Login; + var repo = pushEvent.Repository.Name; + // Assumes the label follows the following convention: Skill.Function example: PM.Readme + + var suffix = $"{org}-{repo}"; + var ingester = _grains.GetGrain(suffix); + + return Task.CompletedTask; + } + private async Task HandleClosingIssue(long issueNumber, string skillName, string functionName, string suffix, string org, string repo) { if (skillName == nameof(PM) && functionName == nameof(PM.Readme)) @@ -183,6 +197,11 @@ public sealed class GithubWebHookProcessor : WebhookEventProcessor var conductor = _grains.GetGrain(issueNumber, suffix); await conductor.InitialFlow(input, org, repo, issueNumber); } + else if (skillName == "Repo" && functionName == "Ingest") + { + var ingestor = _grains.GetGrain(suffix); + await ingestor.IngestionFlow(org, repo, "main"); + } else if (skillName == nameof(PM) && functionName == nameof(PM.Readme)) { var pm = _grains.GetGrain(issueNumber, suffix); diff --git a/src/apps/gh-flow/gh-flow.csproj b/src/apps/gh-flow/gh-flow.csproj index f9716304a..3596510a5 100644 --- a/src/apps/gh-flow/gh-flow.csproj +++ b/src/apps/gh-flow/gh-flow.csproj @@ -21,6 +21,7 @@ + diff --git a/src/apps/ingest/.funcignore b/src/apps/ingest/.funcignore new file mode 100644 index 000000000..d5b3b4a26 --- /dev/null +++ b/src/apps/ingest/.funcignore @@ -0,0 +1,10 @@ +*.js.map +*.ts +.git* +.vscode +__azurite_db*__.json +__blobstorage__ +__queuestorage__ +local.settings.json +test +tsconfig.json \ No newline at end of file diff --git a/src/apps/ingest/.gitignore b/src/apps/ingest/.gitignore new file mode 100644 index 000000000..01774db7f --- /dev/null +++ b/src/apps/ingest/.gitignore @@ -0,0 +1,99 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test + +# parcel-bundler cache (https://parceljs.org/) +.cache + +# next.js build output +.next + +# nuxt.js build output +.nuxt + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TypeScript output +dist +out + +# Azure Functions artifacts +bin +obj +appsettings.json +local.settings.json + +# Azurite artifacts +__blobstorage__ +__queuestorage__ +__azurite_db*__.json \ No newline at end of file diff --git a/src/apps/ingest/host.json b/src/apps/ingest/host.json new file mode 100644 index 000000000..fd4bee790 --- /dev/null +++ b/src/apps/ingest/host.json @@ -0,0 +1,15 @@ +{ + "version": "2.0", + "logging": { + "applicationInsights": { + "samplingSettings": { + "isEnabled": true, + "excludedTypes": "Request" + } + } + }, + "extensionBundle": { + "id": "Microsoft.Azure.Functions.ExtensionBundle", + "version": "[3.*, 4.0.0)" + } +} \ No newline at end of file diff --git a/src/apps/ingest/package-lock.json b/src/apps/ingest/package-lock.json new file mode 100644 index 000000000..1d6d5a7a1 --- /dev/null +++ b/src/apps/ingest/package-lock.json @@ -0,0 +1,818 @@ +{ + "name": "ingest", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "ingest", + "version": "1.0.0", + "dependencies": { + "@azure/functions": "^4.0.0", + "tree-sitter": "^0.20.6", + "tree-sitter-c-sharp": "^0.20.0", + "tree-sitter-javascript": "^0.20.1" + }, + "devDependencies": {} + }, + "node_modules/@azure/functions": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@azure/functions/-/functions-4.0.1.tgz", + "integrity": "sha512-Ol38b4XOlu6IDkLnO91HaYeo2utMixG0LIA1NR9Qehu17U/cGjNx+bAcOEdNlSJWNYh5ChhzjxA/uFB5dQJtmg==", + "dependencies": { + "long": "^4.0.0", + "undici": "^5.13.0" + }, + "engines": { + "node": ">=18.0" + } + }, + "node_modules/@fastify/busboy": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.0.0.tgz", + "integrity": "sha512-JUFJad5lv7jxj926GPgymrWQxxjPYuJNiNjNMzqT+HiuP6Vl3dk5xzG+8sTX96np0ZAluvaMzPsjhHZ5rNuNQQ==", + "engines": { + "node": ">=14" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/detect-libc": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", + "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==" + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + }, + "node_modules/long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" + }, + "node_modules/nan": { + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.18.0.tgz", + "integrity": "sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w==" + }, + "node_modules/napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==" + }, + "node_modules/node-abi": { + "version": "3.51.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.51.0.tgz", + "integrity": "sha512-SQkEP4hmNWjlniS5zdnfIXTk1x7Ome85RDzHlTbBtzE97Gfwz/Ipw4v/Ryk20DWIy3yCNVLVlGKApCnmvYoJbA==", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/prebuild-install": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", + "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tree-sitter": { + "version": "0.20.6", + "resolved": "https://registry.npmjs.org/tree-sitter/-/tree-sitter-0.20.6.tgz", + "integrity": "sha512-GxJodajVpfgb3UREzzIbtA1hyRnTxVbWVXrbC6sk4xTMH5ERMBJk9HJNq4c8jOJeUaIOmLcwg+t6mez/PDvGqg==", + "hasInstallScript": true, + "dependencies": { + "nan": "^2.18.0", + "prebuild-install": "^7.1.1" + } + }, + "node_modules/tree-sitter-c-sharp": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/tree-sitter-c-sharp/-/tree-sitter-c-sharp-0.20.0.tgz", + "integrity": "sha512-HOR6fQtghA7hp/LC6fQzzCyRv8TINh/hqYUULYHOYmwsCV73j4PHLYg1536qv/vff1KaRd7Qx3Fs3VLzx1/WIQ==", + "hasInstallScript": true, + "dependencies": { + "nan": "^2.14.0" + } + }, + "node_modules/tree-sitter-javascript": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/tree-sitter-javascript/-/tree-sitter-javascript-0.20.1.tgz", + "integrity": "sha512-2LNRAw6vd6NDGf5DvAZTaIJDv0j7519bbDsQQ9jnT7uC91efvbn2BxOagNs7u41LSbmsuScjkM8VeN0mnya1iw==", + "hasInstallScript": true, + "dependencies": { + "nan": "^2.17.0" + } + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/undici": { + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.27.0.tgz", + "integrity": "sha512-l3ydWhlhOJzMVOYkymLykcRRXqbUaQriERtR70B9LzNkZ4bX52Fc8wbTDneMiwo8T+AemZXvXaTx+9o5ROxrXg==", + "dependencies": { + "@fastify/busboy": "^2.0.0" + }, + "engines": { + "node": ">=14.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + }, + "dependencies": { + "@azure/functions": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@azure/functions/-/functions-4.0.1.tgz", + "integrity": "sha512-Ol38b4XOlu6IDkLnO91HaYeo2utMixG0LIA1NR9Qehu17U/cGjNx+bAcOEdNlSJWNYh5ChhzjxA/uFB5dQJtmg==", + "requires": { + "long": "^4.0.0", + "undici": "^5.13.0" + } + }, + "@fastify/busboy": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.0.0.tgz", + "integrity": "sha512-JUFJad5lv7jxj926GPgymrWQxxjPYuJNiNjNMzqT+HiuP6Vl3dk5xzG+8sTX96np0ZAluvaMzPsjhHZ5rNuNQQ==" + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, + "bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + }, + "decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "requires": { + "mimic-response": "^3.1.0" + } + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" + }, + "detect-libc": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", + "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==" + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "requires": { + "once": "^1.4.0" + } + }, + "expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==" + }, + "fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + }, + "github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==" + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==" + }, + "minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==" + }, + "mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" + }, + "nan": { + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.18.0.tgz", + "integrity": "sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w==" + }, + "napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==" + }, + "node-abi": { + "version": "3.51.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.51.0.tgz", + "integrity": "sha512-SQkEP4hmNWjlniS5zdnfIXTk1x7Ome85RDzHlTbBtzE97Gfwz/Ipw4v/Ryk20DWIy3yCNVLVlGKApCnmvYoJbA==", + "requires": { + "semver": "^7.3.5" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "requires": { + "wrappy": "1" + } + }, + "prebuild-install": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", + "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", + "requires": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + } + }, + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==" + }, + "simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "requires": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==" + }, + "tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "requires": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "requires": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + } + }, + "tree-sitter": { + "version": "0.20.6", + "resolved": "https://registry.npmjs.org/tree-sitter/-/tree-sitter-0.20.6.tgz", + "integrity": "sha512-GxJodajVpfgb3UREzzIbtA1hyRnTxVbWVXrbC6sk4xTMH5ERMBJk9HJNq4c8jOJeUaIOmLcwg+t6mez/PDvGqg==", + "requires": { + "nan": "^2.18.0", + "prebuild-install": "^7.1.1" + } + }, + "tree-sitter-c-sharp": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/tree-sitter-c-sharp/-/tree-sitter-c-sharp-0.20.0.tgz", + "integrity": "sha512-HOR6fQtghA7hp/LC6fQzzCyRv8TINh/hqYUULYHOYmwsCV73j4PHLYg1536qv/vff1KaRd7Qx3Fs3VLzx1/WIQ==", + "requires": { + "nan": "^2.14.0" + } + }, + "tree-sitter-javascript": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/tree-sitter-javascript/-/tree-sitter-javascript-0.20.1.tgz", + "integrity": "sha512-2LNRAw6vd6NDGf5DvAZTaIJDv0j7519bbDsQQ9jnT7uC91efvbn2BxOagNs7u41LSbmsuScjkM8VeN0mnya1iw==", + "requires": { + "nan": "^2.17.0" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "undici": { + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.27.0.tgz", + "integrity": "sha512-l3ydWhlhOJzMVOYkymLykcRRXqbUaQriERtR70B9LzNkZ4bX52Fc8wbTDneMiwo8T+AemZXvXaTx+9o5ROxrXg==", + "requires": { + "@fastify/busboy": "^2.0.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } +} diff --git a/src/apps/ingest/package.json b/src/apps/ingest/package.json new file mode 100644 index 000000000..eda27a2e7 --- /dev/null +++ b/src/apps/ingest/package.json @@ -0,0 +1,17 @@ +{ + "name": "ingest", + "version": "1.0.0", + "description": "", + "scripts": { + "start": "func start", + "test": "echo \"No tests yet...\"" + }, + "dependencies": { + "@azure/functions": "^4.0.0", + "tree-sitter": "^0.20.6", + "tree-sitter-c-sharp": "^0.20.0", + "tree-sitter-javascript": "^0.20.1" + }, + "devDependencies": {}, + "main": "src/functions/*.js" +} diff --git a/src/apps/ingest/src/functions/AnalyzeCode.js b/src/apps/ingest/src/functions/AnalyzeCode.js new file mode 100644 index 000000000..b5c458c37 --- /dev/null +++ b/src/apps/ingest/src/functions/AnalyzeCode.js @@ -0,0 +1,42 @@ +const { app } = require("@azure/functions"); + +const Parser = require("tree-sitter"); +const CSharp = require("tree-sitter-c-sharp"); +const {Query, QueryCursor} = Parser +const parser = new Parser(); +parser.setLanguage(CSharp); + +app.http("AnalyzeCode", { + methods: ["POST"], + authLevel: "anonymous", + handler: async (request, context) => { + const sourceCode = await request.json(); + context.log(`File contents: ${sourceCode.Content}`); + const tree = parser.parse(sourceCode.Content); + // TODO: add a query to find all comments with classes + const query = new Query(CSharp, `((comment) @comment + [(method_declaration) @method-declaration + (class_declaration) @class-declaration])`); + + const matches = query.matches(tree.rootNode); + var items = []; + for (let match of matches) { + const captures = match.captures; + var item = {}; + for (let capture of captures) { + if (capture.name === 'comment') { + item.Meaning = tree.getText(capture.node); + } + else if (capture.name === 'method-declaration') { + item.CodeBlock = tree.getText(capture.node); + } + else if (capture.name === 'class-declaration') { + item.CodeBlock = tree.getText(capture.node); + } + } + items.push(item); + } + + return { jsonBody: items}; + }, +}); diff --git a/src/libs/Microsoft.AI.DevTeam/Actors/Ingester/IIngestRepo.cs b/src/libs/Microsoft.AI.DevTeam/Actors/Ingester/IIngestRepo.cs new file mode 100644 index 000000000..3ceb1ed99 --- /dev/null +++ b/src/libs/Microsoft.AI.DevTeam/Actors/Ingester/IIngestRepo.cs @@ -0,0 +1,9 @@ +using Orleans.Concurrency; + +namespace Microsoft.AI.DevTeam; + +public interface IIngestRepo : IGrainWithStringKey +{ + [OneWay] + Task IngestionFlow(string org, string repo, string branch); +} \ No newline at end of file diff --git a/src/libs/Microsoft.AI.DevTeam/Actors/Ingester/Ingester.cs b/src/libs/Microsoft.AI.DevTeam/Actors/Ingester/Ingester.cs new file mode 100644 index 000000000..3952bbf33 --- /dev/null +++ b/src/libs/Microsoft.AI.DevTeam/Actors/Ingester/Ingester.cs @@ -0,0 +1,39 @@ +using Microsoft.SemanticKernel; +using Octokit; +using Orleans.Runtime; + +namespace Microsoft.AI.DevTeam; + +public class Ingester : SemanticPersona, IIngestRepo +{ + protected override string MemorySegment => "code-analysis"; + private readonly IManageGithub _ghService; + private readonly IKernel _kernel; + private readonly IAnalyzeCode _codeAnalyzer; + public Ingester([PersistentState("state", "messages")] IPersistentState state, IManageGithub ghService, IKernel kernel, IAnalyzeCode codeAnalyzer) : base(state) + { + _ghService = ghService; + _kernel = kernel; + _codeAnalyzer = codeAnalyzer; + } + + public async Task IngestionFlow(string org, string repo, string branch) + { + var language = await _ghService.GetMainLanguage(org, repo); + var files = await _ghService.GetFiles(org, repo, branch, Language.Filters[language]); + foreach (var file in files) + { + var codeAnalysis = await _codeAnalyzer.Analyze(file.Content); + codeAnalysis.ToList() + .ForEach(async c => + await _kernel.Memory.SaveInformationAsync(MemorySegment, c.CodeBlock, Guid.NewGuid().ToString(), c.Meaning)); + } + } +} + +public static class Language +{ + public static Dictionary> Filters = new Dictionary> { + {"C#", f => f.Name.EndsWith(".cs") } + }; +} \ No newline at end of file diff --git a/src/libs/Microsoft.AI.DevTeam/Options/ServiceOptions.cs b/src/libs/Microsoft.AI.DevTeam/Options/ServiceOptions.cs new file mode 100644 index 000000000..cb253c233 --- /dev/null +++ b/src/libs/Microsoft.AI.DevTeam/Options/ServiceOptions.cs @@ -0,0 +1,4 @@ +public class ServiceOptions +{ + public string IngesterUrl { get; set; } +} \ No newline at end of file diff --git a/src/libs/Microsoft.AI.DevTeam/Services/CodeAnalyzer.cs b/src/libs/Microsoft.AI.DevTeam/Services/CodeAnalyzer.cs new file mode 100644 index 000000000..7153805ed --- /dev/null +++ b/src/libs/Microsoft.AI.DevTeam/Services/CodeAnalyzer.cs @@ -0,0 +1,45 @@ +using System.Net.Http.Json; +using System.Text; +using System.Text.Json; +using Microsoft.Extensions.Options; +using Octokit.Internal; + +namespace Microsoft.AI.DevTeam; + +public interface IAnalyzeCode +{ + Task> Analyze(string content); +} +public class CodeAnalyzer : IAnalyzeCode +{ + private readonly ServiceOptions _serviceOptions; + private readonly HttpClient _httpClient; + + public CodeAnalyzer(IOptions serviceOptions, HttpClient httpClient) + { + _serviceOptions = serviceOptions.Value; + _httpClient = httpClient; + _httpClient.BaseAddress = new Uri(_serviceOptions.IngesterUrl); + + } + public async Task> Analyze(string content) + { + var request = new CodeAnalysisRequest { Content = content }; + var body = new StringContent(JsonSerializer.Serialize(request), Encoding.UTF8, "application/json"); + var response = await _httpClient.PostAsync("api/AnalyzeCode", body); + var stringResult = await response.Content.ReadAsStringAsync(); + var result = JsonSerializer.Deserialize>(stringResult); + return result; + } +} + +public class CodeAnalysisRequest +{ + public string Content { get; set; } +} + +public class CodeAnalysis +{ + public string Meaning { get; set; } + public string CodeBlock { get; set; } +} diff --git a/src/libs/Microsoft.AI.DevTeam/Services/GithubService.cs b/src/libs/Microsoft.AI.DevTeam/Services/GithubService.cs index 05d313caf..f480b1f3b 100644 --- a/src/libs/Microsoft.AI.DevTeam/Services/GithubService.cs +++ b/src/libs/Microsoft.AI.DevTeam/Services/GithubService.cs @@ -12,13 +12,15 @@ public class GithubService : IManageGithub { private readonly GitHubClient _ghClient; private readonly AzureOptions _azSettings; - private readonly ILogger logger; + private readonly ILogger _logger; + private readonly HttpClient _httpClient; - public GithubService(GitHubClient ghClient, IOptions azOptions, ILogger logger) + public GithubService(GitHubClient ghClient, IOptions azOptions, ILogger logger, HttpClient httpClient) { _ghClient = ghClient; _azSettings = azOptions.Value; - this.logger = logger; + _logger = logger; + _httpClient = httpClient; } public async Task CommitToBranch(CommitRequest request) @@ -55,7 +57,7 @@ public class GithubService : IManageGithub } catch (Exception ex) { - logger.LogError(ex, $"Error while uploading file {item.Name}"); + _logger.LogError(ex, $"Error while uploading file {item.Name}"); } } else if (item.IsDirectory) @@ -72,6 +74,13 @@ public class GithubService : IManageGithub await _ghClient.Git.Reference.CreateBranch(request.Org, request.Repo, request.Branch, ghRepo.DefaultBranch); } + public async Task GetMainLanguage(string org, string repo) + { + var languages = await _ghClient.Repository.GetAllLanguages(org, repo); + var mainLanguage = languages.OrderByDescending(l => l.NumberOfBytes).First(); + return mainLanguage.Name; + } + public async Task CreateIssue(CreateIssueRequest request) { var newIssue = new NewIssue($"{request.Label} chain for #{request.ParentNumber}") @@ -108,6 +117,41 @@ public class GithubService : IManageGithub { await _ghClient.Issue.Comment.Create(request.Org, request.Repo, request.Number, request.Content); } + + public async Task> GetFiles(string org, string repo, string branch, Func filter) + { + var items = await _ghClient.Repository.Content.GetAllContentsByRef(org, repo, branch); + return await CollectFiles(org, repo, branch, items, filter); + } + + private async Task> CollectFiles(string org, string repo, string branch, IReadOnlyList items, Func filter) + { + var result = new List(); + foreach(var item in items) + { + if (item.Type == ContentType.File && filter(item)) + { + var content = await _httpClient.GetStringAsync(item.DownloadUrl); + result.Add(new FileResponse + { + Name = item.Name, + Content = content + }); + } + else if (item.Type == ContentType.Dir) + { + var subItems = await _ghClient.Repository.Content.GetAllContentsByRef(org, repo,item.Path, branch); + result.AddRange(await CollectFiles(org, repo, branch, subItems, filter)); + } + } + return result; + } +} + +public class FileResponse +{ + public string Name { get; set; } + public string Content { get; set; } } public interface IManageGithub @@ -120,6 +164,8 @@ public interface IManageGithub Task CommitToBranch(CommitRequest request); Task PostComment(PostCommentRequest request); + Task> GetFiles(string org, string repo, string branch, Func filter); + Task GetMainLanguage(string org, string repo); } [GenerateSerializer]