├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.yaml │ └── feature_request.yaml └── workflows │ ├── deploy-vscode.yml │ ├── discord-bot_discord-app.yml │ ├── pr-checks.yml │ └── web-app_web-app-prod.yml ├── .gitignore ├── LICENSE ├── assets ├── commanddash-logo.png ├── docs │ ├── agent-usage.gif │ ├── command.png │ └── poster.jpg └── llm-matching-human-capabilities.png ├── discord ├── .gitignore ├── index.js ├── package.json └── web.config ├── readme.md ├── vscode ├── .eslintrc.json ├── .gitignore ├── .vscode │ ├── extensions.json │ ├── launch.json │ ├── settings.json │ └── tasks.json ├── .vscodeignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── assets │ ├── pebbles │ │ ├── api.js │ │ ├── auth_page.html │ │ ├── savePebblePanel.html │ │ └── searchPebblePanel.html │ └── prismjs │ │ └── prism.min.css ├── media │ ├── .DS_Store │ ├── activity-icon.png │ ├── agent-provider │ │ └── agent-provider.js │ ├── agent-ui-builder │ │ └── agent-ui-builder.js │ ├── command-deck │ │ └── command-deck.js │ ├── header.png │ ├── icon.png │ ├── input.css │ ├── loading-animation.json │ ├── market-place │ │ ├── market-place.css │ │ ├── market-place.html │ │ └── market-place.js │ ├── onboarding │ │ ├── onboarding.css │ │ ├── onboarding.html │ │ └── onboarding.js │ ├── output.css │ └── questionnaire │ │ └── questionnaire.js ├── package-lock.json ├── package.json ├── resources │ ├── dark │ │ ├── back.svg │ │ ├── market-place.svg │ │ └── trash.svg │ └── light │ │ ├── back.svg │ │ ├── market-place.svg │ │ └── trash.svg ├── src │ ├── .DS_Store │ ├── action-managers │ │ └── diff-view-agent.ts │ ├── extension.ts │ ├── pebbles │ │ ├── pebble-pabel-provider.ts │ │ └── pebble_repository.ts │ ├── providers │ │ ├── chat_view_provider.ts │ │ └── error_code_actions_provider.ts │ ├── repository │ │ ├── generation-repository.ts │ │ ├── http-utils.ts │ │ └── welltested-repository.ts │ ├── shared │ │ ├── types │ │ │ ├── constants.ts │ │ │ ├── custom_protocols.ts │ │ │ ├── interfaces.ts │ │ │ ├── outline.ts │ │ │ └── token.ts │ │ └── utils.ts │ ├── test │ │ ├── runTest.ts │ │ └── suite │ │ │ ├── extension.test.ts │ │ │ ├── index.ts │ │ │ └── src │ │ │ └── utilities │ │ │ └── virtual-document-provider.test.ts │ ├── tools │ │ ├── create │ │ │ ├── class_model_from_json.ts │ │ │ ├── class_repository_from_json.ts │ │ │ ├── code_from_blueprint.ts │ │ │ └── code_from_description.ts │ │ ├── inline-hints │ │ │ └── inlint-hints-utils.ts │ │ ├── refactor │ │ │ ├── fix_errors.ts │ │ │ └── optimize_code.ts │ │ └── reference │ │ │ └── add_reference.ts │ └── utilities │ │ ├── api-communicator.ts │ │ ├── auth │ │ └── auth.ts │ │ ├── cache-manager.ts │ │ ├── code-processing.ts │ │ ├── command-manager.ts │ │ ├── commanddash-integration │ │ ├── dart-cli-client.ts │ │ └── task.ts │ │ ├── contextual-code.ts │ │ ├── diff-utils.ts │ │ ├── prompt_helpers.ts │ │ ├── setup-manager │ │ └── setup-manager.ts │ │ ├── shortcut-hint-utils.ts │ │ ├── state-objects.ts │ │ ├── storage-manager.ts │ │ ├── telemetry-reporter.ts │ │ ├── update-check.ts │ │ ├── update-manager.ts │ │ └── virtual-document-provider.ts ├── tailwind.config.js ├── target │ └── npmlist.json ├── tsconfig.json └── vsc-extension-quickstart.md └── web ├── .gitignore ├── .npmrc ├── .vscode └── launch.json ├── README.md ├── package.json ├── postcss.config.js ├── src ├── app.d.ts ├── app.html ├── lib │ ├── actions │ │ └── clickOutside.ts │ ├── components │ │ ├── CreateAgentDialog.svelte │ │ ├── ExpandNavigation.svelte │ │ ├── LoadingPage.svelte │ │ ├── MobileNav.svelte │ │ ├── NavConversationItem.svelte │ │ ├── NavMenu.svelte │ │ ├── PrivateAgentDialog.svelte │ │ ├── SettingsAgent.svelte │ │ ├── Toast.svelte │ │ ├── chat │ │ │ ├── ChatInput.svelte │ │ │ ├── ChatIntroduction.svelte │ │ │ ├── ChatMessage.svelte │ │ │ └── ChatWindow.svelte │ │ └── icons │ │ │ ├── IconDazzled.svelte │ │ │ ├── IconInternet.svelte │ │ │ ├── IconNew.svelte │ │ │ └── IconVisualStudio.svelte │ ├── index.ts │ ├── stores │ │ ├── QuestionnaireStores.ts │ │ └── ToastStores.ts │ ├── types │ │ ├── Agent.ts │ │ ├── MarketPlace.ts │ │ ├── Message.ts │ │ ├── Questionnaires.ts │ │ └── Toast.ts │ └── utils │ │ ├── appInsights.ts │ │ ├── authenticate.ts │ │ ├── copyToClipboard.ts │ │ ├── debounce.ts │ │ ├── isDesktop.ts │ │ └── validateURL.ts ├── routes │ ├── +error.svelte │ ├── +layout.svelte │ ├── +page.svelte │ └── agent │ │ ├── +page.svelte │ │ └── [id] │ │ └── +page.svelte └── styles │ ├── highlight-js.css │ └── main.css ├── static ├── code-snippet.svg ├── favicon.png ├── github.png ├── go.png ├── icons8-dart-96.png ├── icons8-github-80.png ├── lottie │ └── loading-animation.json ├── market-place.svg ├── mellowtel.png ├── npm.png ├── python.png ├── question-mark.svg └── whoosh.mp3 ├── svelte.config.js ├── tailwind.config.js ├── tsconfig.json └── vite.config.ts /.github/ISSUE_TEMPLATE/bug_report.yaml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: Create a report to help us improve 3 | labels: [bug] 4 | body: 5 | - type: markdown 6 | attributes: 7 | value: | 8 | Thanks for taking the time to fill out this bug report! 9 | - type: textarea 10 | id: version 11 | attributes: 12 | label: What version are you using? 13 | description: Please specify the names and versions. Check below! 14 | placeholder: "Eg. v0.2.0" 15 | validations: 16 | required: true 17 | - type: markdown 18 | attributes: 19 | value: '' 20 | - type: textarea 21 | id: what-happened 22 | attributes: 23 | label: What happened? 24 | description: Also, what did you expect to happen? 25 | placeholder: Description of the bug and what was expected. 26 | validations: 27 | required: true 28 | - type: textarea 29 | id: repro-steps 30 | attributes: 31 | label: Steps to reproduce 32 | description: How do you trigger this bug? Please walk us through it step by step. 33 | value: | 34 | 1. Go to '...' 35 | 2. Click on '...' 36 | 3. Scroll down to '...' 37 | ... 38 | render: bash 39 | validations: 40 | required: true 41 | - type: textarea 42 | id: reproduce 43 | attributes: 44 | label: Supporting info to reproduce 45 | description: Please add any relevant code, screenshots and info needed to reproduce this issue. 46 | - type: textarea 47 | id: logs 48 | attributes: 49 | label: Relevant log output 50 | description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. 51 | render: Shell 52 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yaml: -------------------------------------------------------------------------------- 1 | name: Feature Request 2 | description: Suggest an idea for this project 3 | title: "[Feat]: " 4 | labels: [enhancement] 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: | 9 | Thanks for taking the time to help us improve! 10 | 11 | - type: textarea 12 | id: issue 13 | attributes: 14 | label: "Describe the problem and solution that you'd like." 15 | description: A clear description of what you want to happen. 16 | placeholder: "Example: When clicking this I want that." 17 | 18 | - type: textarea 19 | id: alternatives 20 | attributes: 21 | label: "Describe alternatives that you have considered." 22 | description: "A clear description of any alternative solutions or features you've considered." 23 | placeholder: "Example: Instead of this it should do that." 24 | 25 | - type: textarea 26 | id: additional-information 27 | attributes: 28 | label: Additional Information 29 | description: Any additional information or resources related to this feature request. 30 | placeholder: "e.g., links to resources, screenshots, etc." 31 | 32 | - type: textarea 33 | id: acceptance-criteria 34 | attributes: 35 | label: Acceptance Criteria 36 | description: Please list the criteria that will determine when this feature is considered complete. 37 | placeholder: "List the acceptance criteria..." 38 | -------------------------------------------------------------------------------- /.github/workflows/deploy-vscode.yml: -------------------------------------------------------------------------------- 1 | 2 | name: VSCode Publish 3 | 4 | on: 5 | push: 6 | tags: 7 | - 'v[0-9]+.[0-9]+.[0-9]+*' 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout repo at the pushed tag 14 | uses: actions/checkout@v4 15 | with: 16 | # This configures the action to checkout the commit that was tagged, 17 | # which is effectively the code state you want to work with. 18 | ref: ${{ github.ref }} 19 | 20 | - name: Set up Node.js 21 | uses: actions/setup-node@v4 22 | with: 23 | node-version: '20.x' 24 | 25 | - name: Cache NPM 26 | uses: actions/cache@v4 27 | with: 28 | path: ~/.npm 29 | key: ${{ runner.os }}-node-${{ hashFiles('**/vscode/package-lock.json') }} 30 | restore-keys: | 31 | ${{ runner.os }}-node- 32 | 33 | - name: Install Dependencies 34 | run: | 35 | cd vscode 36 | npm ci 37 | 38 | - name: Publish Release 39 | if: startsWith(github.ref, 'refs/tags/') 40 | run: | 41 | cd vscode 42 | npx vsce publish 43 | env: 44 | VSCE_PAT: ${{ secrets.VSCE_PAT }} -------------------------------------------------------------------------------- /.github/workflows/discord-bot_discord-app.yml: -------------------------------------------------------------------------------- 1 | # Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy 2 | # More GitHub Actions for Azure: https://github.com/Azure/actions 3 | 4 | name: Build and deploy Node.js app to Azure Web App - discord-app 5 | 6 | on: 7 | push: 8 | branches: 9 | - discord-bot 10 | workflow_dispatch: 11 | 12 | jobs: 13 | build: 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/checkout@v4 18 | 19 | - name: Set up Node.js version 20 | uses: actions/setup-node@v3 21 | with: 22 | node-version: '18.x' 23 | 24 | - name: npm install, build, and test 25 | run: | 26 | cd discord 27 | npm install 28 | npm run build --if-present 29 | npm run test --if-present 30 | 31 | - name: Zip artifact for deployment 32 | run: | 33 | cd discord 34 | zip -r ../release.zip ./* 35 | 36 | - name: Upload artifact for deployment job 37 | uses: actions/upload-artifact@v4 38 | with: 39 | name: node-app 40 | path: release.zip 41 | 42 | deploy: 43 | runs-on: ubuntu-latest 44 | needs: build 45 | environment: 46 | name: 'Production' 47 | url: ${{ steps.deploy-to-webapp.outputs.webapp-url }} 48 | permissions: 49 | id-token: write #This is required for requesting the JWT 50 | 51 | steps: 52 | - name: Download artifact from build job 53 | uses: actions/download-artifact@v4 54 | with: 55 | name: node-app 56 | 57 | - name: Unzip artifact for deployment 58 | run: unzip release.zip 59 | 60 | - name: Login to Azure 61 | uses: azure/login@v2 62 | with: 63 | client-id: ${{ secrets.AZUREAPPSERVICE_CLIENTID_F79B5525A24E4DD1B0474AE8E88AC734 }} 64 | tenant-id: ${{ secrets.AZUREAPPSERVICE_TENANTID_82993AB6E0F44B589C524B05273985DB }} 65 | subscription-id: ${{ secrets.AZUREAPPSERVICE_SUBSCRIPTIONID_BD59F4177F7646289B41D15D6119C77B }} 66 | 67 | - name: 'Deploy to Azure Web App' 68 | id: deploy-to-webapp 69 | uses: azure/webapps-deploy@v3 70 | with: 71 | app-name: 'discord-app' 72 | slot-name: 'Production' 73 | package: . 74 | -------------------------------------------------------------------------------- /.github/workflows/pr-checks.yml: -------------------------------------------------------------------------------- 1 | name: PR Check 2 | 3 | on: [pull_request] # Triggers on commits to PRs only. 4 | 5 | jobs: 6 | lint: # Job name. 7 | runs-on: ubuntu-latest # Host's operating system. 8 | steps: 9 | - name: Checkout commit # Download the code from triggering commit. 10 | uses: actions/checkout@v4 11 | 12 | - name: Use Node.js 13 | uses: actions/setup-node@v4 14 | with: 15 | node-version: '20.x' 16 | 17 | - name: Cache NPM # Leverage npm cache on repeated workflow runs if package.json didn't change. 18 | uses: actions/cache@v4 19 | with: 20 | path: ~/.npm 21 | key: ${{ runner.os }}-node-${{ hashFiles('**/vscode/package-lock.json') }} # Make sure to target the `vscode` directory. 22 | restore-keys: | 23 | ${{ runner.os }}-node- 24 | 25 | - name: Install Dependencies 26 | run: | 27 | cd vscode # Change directory to `vscode`. 28 | npm ci 29 | 30 | - name: Run linter 31 | run: | 32 | cd vscode # Again, ensure we're inside the `vscode` directory. 33 | npm run lint -------------------------------------------------------------------------------- /.github/workflows/web-app_web-app-prod.yml: -------------------------------------------------------------------------------- 1 | name: Build and deploy SvelteKit app to Azure Web App - web-app-prod 2 | 3 | on: 4 | push: 5 | branches: 6 | - web-app 7 | workflow_dispatch: 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v4 15 | 16 | - name: Set up Node.js version 17 | uses: actions/setup-node@v3 18 | with: 19 | node-version: "18.x" 20 | 21 | - name: npm install, build, and test 22 | run: | 23 | cd web 24 | npm install 25 | npm run build --if-present 26 | npm run test --if-present 27 | env: 28 | VITE_INSTRUMENTATION_KEY: ${{ secrets.VITE_INSTRUMENTATION_KEY }} 29 | 30 | - name: Zip artifact for deployment 31 | run: | 32 | cd web 33 | zip -r ../release.zip build node_modules package.json package-lock.json -x "*.git*" 34 | 35 | - name: Upload artifact for deployment job 36 | uses: actions/upload-artifact@v3 37 | with: 38 | name: sveltekit-app 39 | path: release.zip 40 | 41 | deploy: 42 | runs-on: ubuntu-latest 43 | needs: build 44 | environment: 45 | name: "Production" 46 | url: ${{ steps.deploy-to-webapp.outputs.webapp-url }} 47 | permissions: 48 | id-token: write #This is required for requesting the JWT 49 | 50 | steps: 51 | - name: Download artifact from build job 52 | uses: actions/download-artifact@v3 53 | with: 54 | name: sveltekit-app 55 | 56 | - name: Unzip artifact for deployment 57 | run: unzip release.zip -d deploy 58 | 59 | - name: Install Node.js dependencies on Azure 60 | run: | 61 | cd deploy 62 | npm install --production 63 | 64 | - name: Login to Azure 65 | uses: azure/login@v1 66 | with: 67 | client-id: ${{ secrets.AZUREAPPSERVICE_CLIENTID_818727A488FB487EA3BCC61BEC337FDD }} 68 | tenant-id: ${{ secrets.AZUREAPPSERVICE_TENANTID_58CC6F3841FB49A38469650AD296DCC8 }} 69 | subscription-id: ${{ secrets.AZUREAPPSERVICE_SUBSCRIPTIONID_7B7BF9D41759471DBA0ED64C44AF88AE }} 70 | 71 | - name: "Deploy to Azure Web App" 72 | id: deploy-to-webapp 73 | uses: azure/webapps-deploy@v2 74 | with: 75 | app-name: "web-app-prod" 76 | slot-name: "Production" 77 | package: deploy 78 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store -------------------------------------------------------------------------------- /assets/commanddash-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommandDash/commanddash/8d5d61379a47641c85d93fcbcda4f9175d44f5fc/assets/commanddash-logo.png -------------------------------------------------------------------------------- /assets/docs/agent-usage.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommandDash/commanddash/8d5d61379a47641c85d93fcbcda4f9175d44f5fc/assets/docs/agent-usage.gif -------------------------------------------------------------------------------- /assets/docs/command.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommandDash/commanddash/8d5d61379a47641c85d93fcbcda4f9175d44f5fc/assets/docs/command.png -------------------------------------------------------------------------------- /assets/docs/poster.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommandDash/commanddash/8d5d61379a47641c85d93fcbcda4f9175d44f5fc/assets/docs/poster.jpg -------------------------------------------------------------------------------- /assets/llm-matching-human-capabilities.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommandDash/commanddash/8d5d61379a47641c85d93fcbcda4f9175d44f5fc/assets/llm-matching-human-capabilities.png -------------------------------------------------------------------------------- /discord/.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | ./node_modules/ 3 | package-lock.json -------------------------------------------------------------------------------- /discord/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "discord", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node index.js" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "discord.js": "^14.15.3", 14 | "dotenv": "^16.4.5", 15 | "express": "^4.19.2", 16 | "node-fetch": "^3.3.2" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /discord/web.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | 2 |

3 | 4 | 5 |

6 |

CommandDash

7 |
8 | 9 | [![VScode Downloads](https://img.shields.io/visual-studio-marketplace/d/WelltestedAI.fluttergpt?style=for-the-badge)](https://marketplace.visualstudio.com/items?itemName=WelltestedAI.fluttergpt&ssr=false#overview) [![License: APACHE](https://img.shields.io/badge/License-APACHE%202.0-yellow?style=for-the-badge)](/LICENSE) 10 | 11 |
12 | 13 |

Integrate APIs, SDKs or Packages with AI Agents

14 | 15 | 16 | ----------------- 17 | Modern software is built on top of 3rd party APIs and SDKs. But integrating them is time consuming, requiring to manually read docs and copy-paste snippets. 18 | 19 | [CommandDash](https://commanddash.io) enables you to **skip reading documentation, and integrate any API or SDK with an IDE agent upto date with latest documentation, examples and issues.** 20 | 21 |

22 | Chat with Gemini inside VSCODE 23 |

24 | 25 | ##### 🙌🏼 Open Marketplace of IDE Agents 26 | ##### 🎯 Supports every programming language 27 | ##### 💙 Free to every developer. 28 | 29 | Our vision is to enable developers to seamlessly integrate APIs and SDKs without leaving their IDEs. 30 | 31 | ## FAQs 32 | 33 | 1. **What are the data safety aspects?** 34 | - CommandDash uses processed metadata from your interactions to improve it's generations without using your shared code. 35 | 36 | 2. **Do I need to pay to use CommandDash?** 37 | - CommandDash is free to use for every developer. 38 | 39 | 3. **I am an Android Studio user. Can I use CommandDash?** 40 | - We are coming soon for IntelliJ-based IDEs. *🤫 Secret: most of our core logic is written in Dart, allowing us to ship on any platform very very fast!* 41 | 42 | ## Contributing 43 | 44 | CommanDash is hub of AI agents on docs of any APIs, SDKs and more. 45 | 46 | You can suggest agents to add to the marketplace, or contribute to the VSCODE or IntelliJ extension or also to the shared [engine](https://github.com/CommandDash/packages). 47 | 48 | - **File feature requests**: Suggest features that'll make your development process easier in the [issues board](https://github.com/CommandDash/commanddash//issues). 49 | 50 | - **Pick up open issues**: Pick up and fix existing issues open to the community in [issues board](https://github.com/CommandDash/commanddash/issues). 51 | 52 | - **Request agents in the marketplace**: You can submit requests to add agents for your most used APIs or SDKs. [Fill Form](https://airtable.com/app22SBaii3xYD5aR/shrLv4mDsEtnFjmtj). 53 | 54 | ## Community 55 | 56 | Do you love devtools but hate documentation? Join our community and help developers build without leaving their IDE: [Join Now](https://join.slack.com/t/welltested-ai/shared_invite/zt-25u09fty8-gaggH9HbmopB~4tialTrlA) 👋🏼 57 | 58 | ## License 59 | 60 | CommandDash is released under the Apache License Version 2.0. See the [LICENSE](LICENSE) file for more information. -------------------------------------------------------------------------------- /vscode/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parser": "@typescript-eslint/parser", 4 | "parserOptions": { 5 | "ecmaVersion": 6, 6 | "sourceType": "module" 7 | }, 8 | "plugins": [ 9 | "@typescript-eslint" 10 | ], 11 | "rules": { 12 | "@typescript-eslint/naming-convention": "warn", 13 | "@typescript-eslint/semi": "warn", 14 | "curly": "warn", 15 | "eqeqeq": "warn", 16 | "no-throw-literal": "warn", 17 | "semi": "off" 18 | }, 19 | "ignorePatterns": [ 20 | "out", 21 | "dist", 22 | "**/*.d.ts" 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /vscode/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore node_modules directory 2 | node_modules/ 3 | 4 | # Ignore build output directory 5 | out/ 6 | 7 | 8 | 9 | # Ignore any temporary files 10 | *.tmp 11 | *.temp 12 | 13 | # Ignore any log files 14 | *.log 15 | 16 | # Ignore any configuration files 17 | *.cfg 18 | *.conf 19 | *.config 20 | 21 | # Ignore any test or example files 22 | example/ 23 | demo/ 24 | 25 | # Ignore any files generated by your build process 26 | build/ 27 | dist/ 28 | .env 29 | user_config.json 30 | .vscode-test/ 31 | *.vsix 32 | 33 | #Ignore lock files 34 | 35 | package-lock.json 36 | yarn.lock -------------------------------------------------------------------------------- /vscode/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | "dbaeumer.vscode-eslint", 6 | "connor4312.esbuild-problem-matchers" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /vscode/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that compiles the extension and then opens it inside a new window 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | { 6 | "version": "0.2.0", 7 | "configurations": [ 8 | { 9 | "name": "Run Extension", 10 | "type": "extensionHost", 11 | "request": "launch", 12 | "args": [ 13 | "--extensionDevelopmentPath=${workspaceFolder}" 14 | ], 15 | "outFiles": [ 16 | "${workspaceFolder}/out/**/*.js" 17 | ], 18 | "preLaunchTask": "npm: watch" 19 | }, 20 | { 21 | "name": "Extension Tests", 22 | "type": "extensionHost", 23 | "request": "launch", 24 | "args": [ 25 | "--extensionDevelopmentPath=${workspaceFolder}", 26 | "--extensionTestsPath=${workspaceFolder}/out/test/suite/index" 27 | ], 28 | "outFiles": [ 29 | "${workspaceFolder}/out/test/**/*.js" 30 | ], 31 | "preLaunchTask": "npm: watch" 32 | } 33 | ] 34 | } 35 | -------------------------------------------------------------------------------- /vscode/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "files.exclude": { 4 | "out": false // set this to true to hide the "out" folder with the compiled JS files 5 | }, 6 | "search.exclude": { 7 | "out": true // set this to false to include "out" folder in search results 8 | }, 9 | // Turn off tsc task auto detection since we have the necessary tasks as npm scripts 10 | "typescript.tsc.autoDetect": "off" 11 | } -------------------------------------------------------------------------------- /vscode/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // See https://go.microsoft.com/fwlink/?LinkId=733558 2 | // for the documentation about the tasks.json format 3 | { 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "type": "npm", 8 | "script": "watch", 9 | "group": "build", 10 | "problemMatcher": "$esbuild-watch", 11 | "isBackground": true, 12 | "label": "npm: watch", 13 | }, 14 | { 15 | "type": "npm", 16 | "script": "build", 17 | "group": "build", 18 | "problemMatcher": "$esbuild", 19 | "label": "npm: build", 20 | } 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /vscode/.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | .vscode-test/ 3 | src/ 4 | .gitignore 5 | .yarnrc 6 | vsc-extension-quickstart.md 7 | **/tsconfig.json 8 | **/.eslintrc.json 9 | **/*.map 10 | **/*.ts 11 | node_modules 12 | out/* 13 | !out/extension.js 14 | tsconfig.json 15 | webpack.config.js 16 | -------------------------------------------------------------------------------- /vscode/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to the "commanddash" extension will be documented in this file. 4 | 5 | Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file. 6 | 7 | 8 | ## [0.5.2] 9 | - Fixed UX issues when using agents 10 | 11 | ## [0.5.1] 12 | - Replacing CLI with REST APIs to interact with model 13 | - Crashing fixes 14 | 15 | ## [0.5.0] 16 | - User Experience Improvements 17 | 18 | ## [0.4.9] 19 | - Set minimum VSCode engine to 1.77.0 20 | 21 | ## [0.4.8] 22 | - Don't ask for Gemini API Key 23 | - Removed google generative ai package dependencies 24 | 25 | ## [0.4.7] 26 | - Code Block Indentation issues resolved 27 | 28 | ## [0.4.6] 29 | - Onboarding in first session bug fix 30 | - Updated tutorial cards 31 | 32 | ## [0.4.5] 33 | - Show onboarding in steps 34 | 35 | ## [0.4.4] 36 | - Removed dependency on Dart extension 37 | - Show agent name and avatar in received message 38 | 39 | ## [0.4.3] 40 | - Show agent display name in sent message tile 41 | 42 | ## [0.4.2] 43 | - Minor bug fix 44 | 45 | ## [0.4.1] 46 | - Introduced Chat Mode for agents 47 | - Enhanced marketplace 48 | - Disabled other non-primary features like code from blueprint and inline code generation 49 | 50 | ## [0.3.91] 51 | - Upgarde to Gemini 1.5 Flash 52 | - Fix agent slug and marketplace glitches 53 | 54 | ## [0.3.9] 55 | - Support processing files loader 56 | - Attach Contextual Code within the agent requests 57 | 58 | ## [0.3.8] 59 | - Added support to send contextual code to engine 60 | 61 | v## [0.3.7] 62 | - Added Dash Agents Marketplace 63 | - Fix Github signin issue in Cursor Editor 64 | 65 | ## [0.3.6] 66 | - Tip for Code Input usage 67 | - Engine update failing on windows issue 68 | - Bug Fixes 69 | 70 | ## [0.3.5] 71 | 72 | - Minor Bug Fixes 73 | 74 | ## [0.3.4] 75 | 76 | - Retain embedding cache for better performance 77 | 78 | ## [0.3.3] 79 | 80 | - Server path mismatch 81 | 82 | ## [0.3.2] 83 | 84 | - Switch to CommandDash Engine 85 | - Introduce new agents (flutter & test) 86 | 87 | ## [0.3.1] 88 | 89 | - Fix: Pasting text into field erases existing input. 90 | - Enhanced: Embedding caching mechanism 91 | 92 | ## [0.3.0] 93 | 94 | - Rebrand to CommandDash (Dash AI) 95 | 96 | ## [0.2.10] 97 | 98 | - References can be added to command deck 99 | - Better diff-view 100 | - Improved inline code generations 101 | - Better tutorials 102 | - Bug fixes and improvements 103 | 104 | ## [0.2.9] 105 | 106 | - New User Onboarding 107 | - Upgraded Chat UI (💙) 108 | - Bug fixes and improvements 109 | 110 | ## [0.2.8] 111 | 112 | - Improved contextual code for inline code completion. 113 | - Minor fixes. 114 | 115 | ## [0.2.7] 116 | 117 | - Added better error reporting. 118 | 119 | ## [0.2.6] 120 | 121 | - Minor fixes. 122 | 123 | ## [0.2.5] 124 | 125 | - Added hints for new features. 126 | - Improved contextual code for inline code completion. 127 | 128 | ## [0.2.4] 129 | 130 | - Added inline code generation feature 131 | - Created a centralised command registration method 132 | 133 | ## [0.2.3] 134 | 135 | - Added dart extension as dependency 136 | - Gracefully handles missing gemini api key 137 | - Improved copy & merge functionality 138 | 139 | ## [0.2.2] 140 | 141 | - Major improvement in workspace chat user experience. 142 | - Feature to provide workspace as context in chat history. 143 | - Added a clear chat button. -------------------------------------------------------------------------------- /vscode/README.md: -------------------------------------------------------------------------------- 1 |
2 |

Integrate Packages and SDKs with AI Agents

3 | 4 | [![VScode Downloads](https://img.shields.io/visual-studio-marketplace/d/WelltestedAI.fluttergpt)](https://marketplace.visualstudio.com/items?itemName=WelltestedAI.fluttergpt&ssr=false#overview) [![VScode version](https://img.shields.io/visual-studio-marketplace/v/WelltestedAI.fluttergpt)](https://marketplace.visualstudio.com/items?itemName=WelltestedAI.fluttergpt&ssr=false#overview) [![License: APACHE](https://img.shields.io/badge/License-APACHE%202.0-yellow)](/LICENSE) 5 |
6 | 7 | 8 | ----------------- 9 | CommandDash is a marketplace of AI agents that are expert at integrating Packages and SDKs. 10 | 11 | Dash Agents are trained on the latest documentation, examples and issues enabling you to integrate any library without reading its docs by generating integration code contextualized to your codebase. 12 | 13 | ##### ✨ Skip the documentation 14 | ##### 🤝 Supports all languages 15 | ##### 👨🏼‍💻 Free for every developer 16 | 17 | CommandDash is being built in [open-sourced](https://github.com/CommandDash/commanddash) with the community. 18 | 19 | ----------------- 20 | 21 | ## 🚀 @Agents and /Commands 22 | 23 | Explore 100s of agents available in the marketplace - from LLMs, Payment Gateways APIs to Messaging SDKs. 24 | 25 | **You can activate an agent and chat with it:** 26 | 27 |

28 | Multi code chat with VSCode inside Gemini 29 |

30 | 31 | Also, you can select and attach multiple code snippets from different files in your inline chat using **"Attach Snippet to Dash"** from the right-click menu. 32 | 33 | 🤝 With full-context code context passed and expertise of Dash Agents, receive accurate integration code across multiple files. 34 | 35 | **Run commands meant to perform specific tasks:** 36 | 37 | For example, `@GoRouter` agent offers a `/generate` command: 38 |

39 | Refactoring code with CommandDash 40 |

41 | 42 | Note: Commands are optionally offered by agents depending on the usecase. 43 | 44 | ## FAQs 45 | 46 | 1. **What are the data safety aspects?** 47 | - CommandDash uses processed metadata from your interactions to improve it's generations without using your shared code. 48 | 49 | 2. **Do I need to pay to use CommandDash?** 50 | - CommandDash is free to use for every developer. 51 | 52 | 3. **I am an Android Studio user. Can I use CommandDash?** 53 | - We are coming soon for IntelliJ-based IDEs. *🤫 Secret: most of our core logic is written in Dart, allowing us to ship on any platform very very fast!* 54 | 55 | ## Contributing 56 | 57 | CommanDash is hub of AI agents on docs of any Packages, SDKs and Github Libraries. 58 | 59 | You can suggest agents to add to the marketplace, or contribute to the VSCODE or IntelliJ extension or also to the shared [engine](https://github.com/CommandDash/packages). 60 | 61 | - **File feature requests**: Suggest features that'll make your development process easier in the [issues board](https://github.com/CommandDash/commanddash//issues). 62 | 63 | - **Pick up open issues**: Pick up and fix existing issues open to the community in [issues board](https://github.com/CommandDash/commanddash/issues). 64 | 65 | - **Create agents in the marketplace**: You can create agents for any Packages or SDKs in one-click. [Create Here](https://app.commanddash.io/?create=true). 66 | 67 | ## Community 68 | 69 | Do you love devtools but hate documentation? Join our community and help developers build without leaving their IDE: [Join Now](https://discord.gg/szUCAnrsHQ) 👋🏼 70 | 71 | ## License 72 | 73 | CommandDash is released under the Apache License Version 2.0. See the [LICENSE](LICENSE) file for more information. -------------------------------------------------------------------------------- /vscode/assets/pebbles/auth_page.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Auth Page 5 | 26 | 27 | 28 | 29 | 40 | 46 | 47 | 48 | Log in with GitHub 49 | 50 | 51 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /vscode/assets/prismjs/prism.min.css: -------------------------------------------------------------------------------- 1 | code[class*=language-], 2 | pre[class*=language-] { 3 | background: 0 0; 4 | font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; 5 | text-align: left; 6 | white-space: pre; 7 | word-spacing: normal; 8 | word-break: normal; 9 | word-wrap: normal; 10 | line-height: 1.5; 11 | -moz-tab-size: 4; 12 | -o-tab-size: 4; 13 | tab-size: 4; 14 | -webkit-hyphens: none; 15 | -moz-hyphens: none; 16 | -ms-hyphens: none; 17 | hyphens: none; 18 | white-space: pre-wrap; 19 | font-size: .65rem; 20 | word-break: break-word; 21 | color: var(--vscode-editorWidget-foreground); 22 | } 23 | 24 | pre[class*=language-] { 25 | padding: 1em; 26 | margin: .5em 0 27 | } 28 | 29 | :not(pre)>code[class*=language-], 30 | pre[class*=language-] { 31 | background: var(--vscode-editorWidget-background); 32 | border: 1px solid; 33 | border-color: var(--vscode-input-border); 34 | border-radius: .25rem; 35 | overflow: visible 36 | } 37 | 38 | pre[class*=language-]:hover { 39 | background: var(--vscode-editorWidget-background); 40 | border: 1px solid; 41 | border-color: var(--vscode-inputOption-activeBorder); 42 | border-radius: .25rem 43 | } 44 | 45 | :not(pre)>code[class*=language-] { 46 | border: 0 solid; 47 | } 48 | 49 | .token.block-comment, 50 | .token.cdata, 51 | .token.comment, 52 | .token.doctype, 53 | .token.prolog { 54 | color: #999 55 | } 56 | 57 | .token.punctuation { 58 | color: #ccc 59 | } 60 | 61 | .token.attr-name, 62 | .token.deleted, 63 | .token.namespace, 64 | .token.tag { 65 | color: #e2777a 66 | } 67 | 68 | .token.function-name { 69 | color: #6196cc 70 | } 71 | 72 | .token.boolean, 73 | .token.function, 74 | .token.number { 75 | color: #f08d49 76 | } 77 | 78 | .token.class-name, 79 | .token.constant, 80 | .token.property, 81 | .token.symbol { 82 | color: #f5b11b 83 | } 84 | 85 | .token.atrule, 86 | .token.builtin, 87 | .token.important, 88 | .token.keyword, 89 | .token.selector { 90 | color: #cc99cd 91 | } 92 | 93 | .token.attr-value, 94 | .token.char, 95 | .token.regex, 96 | .token.string, 97 | .token.variable { 98 | color: #7ec699 99 | } 100 | 101 | .token.entity, 102 | .token.operator, 103 | .token.url { 104 | color: #67cdcc 105 | } 106 | 107 | .token.bold, 108 | .token.important { 109 | font-weight: 700 110 | } 111 | 112 | .token.italic { 113 | font-style: italic 114 | } 115 | 116 | .token.entity { 117 | cursor: help 118 | } 119 | 120 | .token.inserted { 121 | color: green 122 | } 123 | 124 | #text { 125 | color: white; 126 | } -------------------------------------------------------------------------------- /vscode/media/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommandDash/commanddash/8d5d61379a47641c85d93fcbcda4f9175d44f5fc/vscode/media/.DS_Store -------------------------------------------------------------------------------- /vscode/media/activity-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommandDash/commanddash/8d5d61379a47641c85d93fcbcda4f9175d44f5fc/vscode/media/activity-icon.png -------------------------------------------------------------------------------- /vscode/media/agent-provider/agent-provider.js: -------------------------------------------------------------------------------- 1 | class AgentProvider { 2 | constructor(json) { 3 | this.json = json; 4 | } 5 | getInputs(inputString, activeAgent) { 6 | for (const item of this.json) { 7 | for (const command of item.supported_commands) { 8 | if (command.slug === inputString && item.name === activeAgent) { 9 | return JSON.parse(JSON.stringify({...command, testing: item.testing})); 10 | } 11 | } 12 | } 13 | return []; 14 | } 15 | } -------------------------------------------------------------------------------- /vscode/media/agent-ui-builder/agent-ui-builder.js: -------------------------------------------------------------------------------- 1 | class AgentUIBuilder { 2 | constructor(ref) { 3 | this.ref = ref; 4 | 5 | this.onStringInput = this.onStringInput.bind(this); 6 | this.buildAgentUI = this.buildAgentUI.bind(this); 7 | 8 | this.container = document.createElement("div"); 9 | 10 | this.codeInputIds = []; 11 | } 12 | 13 | buildAgentUI() { 14 | const { text_field_layout, registered_inputs, slug } = agentInputsJson[0]; 15 | let textHtml = text_field_layout; 16 | registered_inputs.forEach(input => { 17 | const inputElement = this.createInputElement(input); 18 | this.container.appendChild(inputElement); 19 | textHtml = textHtml.replace(`<${input.id}>`, inputElement.outerHTML); 20 | }); 21 | 22 | // activeCommandsAttach.textContent = `${slug}`; 23 | this.container.innerHTML = `${textHtml}`; 24 | this.ref.appendChild(this.container); 25 | this.registerCodeInputListener(); 26 | this.registerCodeInputTippy(); 27 | } 28 | 29 | createInputElement(input) { 30 | const { id, display_text, type, optional } = input; 31 | const _optional = optional ? "(O)" : ""; 32 | if (type === "string_input") { 33 | const inputContainer = document.createElement("span"); 34 | const inputSpan = document.createElement("span"); 35 | inputContainer.innerHTML = `${_optional} ${display_text}`; 36 | inputContainer.classList.add("inline-block"); 37 | 38 | inputSpan.id = id; 39 | inputSpan.contentEditable = true; 40 | inputSpan.tabIndex = 0; 41 | inputSpan.classList.add("px-2", "inline-block", "rounded-tr-[4px]", "rounded-br-[4px]", "string_input", id, "mb-1", "ml-[1px]", "mr-[1px]"); 42 | inputSpan.textContent = '\u200B'; 43 | 44 | this.ref.addEventListener('input', (event) => this.onStringInput(event, id)); 45 | this.ref.addEventListener('paste', () => this.onTextPaste(id)); 46 | 47 | inputContainer.appendChild(inputSpan); 48 | 49 | requestAnimationFrame(() => { 50 | if (!optional) { 51 | const input = document.getElementById(id); 52 | const selection = window.getSelection(); 53 | const range = document.createRange(); 54 | range.selectNodeContents(input); 55 | range.collapse(false); 56 | selection.removeAllRanges(); 57 | selection.addRange(range); 58 | } 59 | }); 60 | 61 | return inputContainer; 62 | } 63 | 64 | if (type === "code_input") { 65 | const codeContainer = document.createElement("span"); 66 | const codePlaceholder = document.createElement("span"); 67 | 68 | codeContainer.classList.add("code-input-container"); 69 | 70 | codePlaceholder.id = id; 71 | codePlaceholder.contentEditable = "false"; 72 | codePlaceholder.tabIndex = 0; 73 | codePlaceholder.classList.add("ml-1", "mb-1", "px-[7px]", "inline-flex", "cursor-pointer", "rounded-[4px]", "mt-1", "code_input", "items-center"); 74 | codePlaceholder.innerHTML = `${dartIcon}${_optional} ${display_text}`; 75 | codeContainer.id = "code-container"; 76 | codeContainer.appendChild(codePlaceholder); 77 | this.codeInputIds.push(id); 78 | 79 | return codeContainer; 80 | } 81 | } 82 | 83 | registerCodeInputListener() { 84 | this.codeInputIds.forEach((_codeInputId) => { 85 | const codeInput = document.getElementById(_codeInputId); 86 | codeInput.addEventListener("focus", () => { 87 | codeInputId = _codeInputId; 88 | }); 89 | }); 90 | } 91 | 92 | registerCodeInputTippy() { 93 | tippy(".code_input", { 94 | content: `Use 'Attach Snippet to Dash' or ${shortCutHints} after selecting the code in editor`, 95 | theme: "flutter-blue" 96 | }); 97 | } 98 | 99 | onTextPaste(id) { 100 | const inputSpan = document.getElementById(id); 101 | inputSpan.dispatchEvent(new Event('input', { bubbles: true })); 102 | } 103 | 104 | onStringInput(event, id) { 105 | const sel = window.getSelection(); 106 | const inputSpan = document.getElementById(id); 107 | if (event.target === inputSpan || (sel.anchorNode && sel.anchorNode.parentNode && sel.anchorNode.parentNode.classList.contains(id))) { 108 | const inputIndex = agentInputsJson[0].registered_inputs.findIndex(_input => _input.id === id); 109 | if (inputIndex !== -1) { 110 | agentInputsJson[0].registered_inputs[inputIndex].value = inputSpan.textContent.trim(); 111 | } 112 | } 113 | } 114 | 115 | onCodeInput(chipsData, chipName) { 116 | const firstCodeInput = agentInputsJson[0].registered_inputs.find(input => input.type === "code_input" && ( codeInputId === 0 ? input.value === undefined : input.id === codeInputId)); 117 | 118 | if (firstCodeInput) { 119 | const codeInputSpan = document.getElementById(firstCodeInput.id); 120 | firstCodeInput.value = JSON.stringify(chipsData); 121 | codeInputSpan.innerHTML = `${dartIcon}${chipName}`; 122 | codeInputId = 0; 123 | } 124 | } 125 | } -------------------------------------------------------------------------------- /vscode/media/header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommandDash/commanddash/8d5d61379a47641c85d93fcbcda4f9175d44f5fc/vscode/media/header.png -------------------------------------------------------------------------------- /vscode/media/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommandDash/commanddash/8d5d61379a47641c85d93fcbcda4f9175d44f5fc/vscode/media/icon.png -------------------------------------------------------------------------------- /vscode/media/input.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; -------------------------------------------------------------------------------- /vscode/media/loading-animation.json: -------------------------------------------------------------------------------- 1 | {"v":"5.6.6","fr":30,"ip":0,"op":217,"w":1080,"h":1080,"nm":"1 Loader","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[540,540,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[38.519,38.519,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[1080,1080],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.41],"y":[1]},"o":{"x":[0.59],"y":[0]},"t":1,"s":[0]},{"i":{"x":[0.015],"y":[1]},"o":{"x":[0.59],"y":[0]},"t":53.402,"s":[38]},{"i":{"x":[0],"y":[1]},"o":{"x":[0.59],"y":[0]},"t":99.414,"s":[100]},{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":137.758,"s":[100]},{"t":217,"s":[0]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.41],"y":[1]},"o":{"x":[0.59],"y":[0]},"t":1,"s":[28]},{"i":{"x":[0.439],"y":[1]},"o":{"x":[0.59],"y":[0]},"t":53.402,"s":[28]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":99.414,"s":[28]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":137.758,"s":[28]},{"t":217,"s":[28]}],"ix":2},"o":{"a":1,"k":[{"i":{"x":[0.41],"y":[0.73]},"o":{"x":[0.59],"y":[0.167]},"t":1,"s":[0]},{"i":{"x":[0.29],"y":[1]},"o":{"x":[0.258],"y":[-0.113]},"t":53.402,"s":[528]},{"i":{"x":[0],"y":[0.687]},"o":{"x":[0.371],"y":[0]},"t":137.758,"s":[-360]},{"t":217,"s":[360]}],"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[0.180392141903,0.740668921377,0.901960784314,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.41],"y":[1]},"o":{"x":[0.59],"y":[0]},"t":67,"s":[237]},{"i":{"x":[0.29],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":84.894,"s":[73]},{"i":{"x":[0.29],"y":[1]},"o":{"x":[0.71],"y":[0]},"t":137.758,"s":[73]},{"t":169.7099609375,"s":[237]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.41,0.41],"y":[1,1]},"o":{"x":[0.59,0.59],"y":[0,0]},"t":67,"s":[100,100]},{"i":{"x":[0.29,0.29],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":84.894,"s":[137,137]},{"i":{"x":[0.29,0.29],"y":[1,1]},"o":{"x":[0.71,0.71],"y":[0,0]},"t":137.758,"s":[137,137]},{"t":169.7099609375,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":901,"st":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[540,540,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[38.519,38.519,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[1080,1080],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.41],"y":[1]},"o":{"x":[0.59],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.015],"y":[1]},"o":{"x":[0.59],"y":[0]},"t":52.402,"s":[38]},{"i":{"x":[0],"y":[1]},"o":{"x":[0.59],"y":[0]},"t":98.414,"s":[100]},{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":136.758,"s":[100]},{"t":216,"s":[0]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.41],"y":[1]},"o":{"x":[0.59],"y":[0]},"t":0,"s":[28]},{"i":{"x":[0.439],"y":[1]},"o":{"x":[0.59],"y":[0]},"t":52.402,"s":[28]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":98.414,"s":[28]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":136.758,"s":[28]},{"t":216,"s":[28]}],"ix":2},"o":{"a":1,"k":[{"i":{"x":[0.41],"y":[0.73]},"o":{"x":[0.59],"y":[0.168]},"t":0,"s":[0]},{"i":{"x":[0.29],"y":[1]},"o":{"x":[0.258],"y":[-0.113]},"t":52.402,"s":[528]},{"i":{"x":[0],"y":[0.687]},"o":{"x":[0.371],"y":[0]},"t":136.758,"s":[-360]},{"t":216,"s":[360]}],"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[0.227358724557,0.109803914089,0.823529411765,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.41],"y":[1]},"o":{"x":[0.59],"y":[0]},"t":66,"s":[237]},{"i":{"x":[0.29],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":83.894,"s":[73]},{"i":{"x":[0.29],"y":[1]},"o":{"x":[0.71],"y":[0]},"t":136.758,"s":[73]},{"t":168.7099609375,"s":[237]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.41,0.41],"y":[1,1]},"o":{"x":[0.59,0.59],"y":[0,0]},"t":66,"s":[100,100]},{"i":{"x":[0.29,0.29],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":83.894,"s":[137,137]},{"i":{"x":[0.29,0.29],"y":[1,1]},"o":{"x":[0.71,0.71],"y":[0,0]},"t":136.758,"s":[137,137]},{"t":168.7099609375,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[540,540,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.008,0.008,0.29],"y":[1,1,1]},"o":{"x":[0.389,0.389,0.71],"y":[0,0,0]},"t":66,"s":[38.519,38.519,100]},{"i":{"x":[0.008,0.008,0.29],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":94,"s":[23.519,23.519,100]},{"i":{"x":[0,0,0.29],"y":[1,1,1]},"o":{"x":[0.367,0.367,0.167],"y":[0,0,0]},"t":137,"s":[23.519,23.519,100]},{"t":177,"s":[38.519,38.519,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-298.234,0],[0,-298.234],[298.234,0],[0,298.234]],"o":[[298.234,0],[0,298.234],[-298.234,0],[0,-298.234]],"v":[[0,-540],[540,0],[0,540],[-540,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.98431372549,0.964705882353,0.941176470588,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":34,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0}],"markers":[]} -------------------------------------------------------------------------------- /vscode/media/market-place/market-place.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | flex-direction: column; 5 | align-items: left; 6 | justify-content: flex-end; 7 | height: 100vh; 8 | } 9 | 10 | .market-place-list-background { 11 | background-color: var(--vscode-panel-background); 12 | } 13 | 14 | .input-container { 15 | padding-top: 4px; 16 | position: relative; 17 | color: var(--vscode-editor-foreground); 18 | display: inline-flex; 19 | justify-content: center; 20 | align-items: center; 21 | width: 100%; 22 | padding-right: 4px; 23 | padding-left: 4px; 24 | } 25 | 26 | .search-input { 27 | border-width: .5px; 28 | border-color: rgb(209 213 219); 29 | height: 1.75rem; 30 | /* 28px */ 31 | width: 100%; 32 | /* dynamic in size */ 33 | padding-left: 0.75rem; 34 | /* 12px */ 35 | padding-right: 1.25rem; 36 | /* 20px */ 37 | font-size: 0.875rem; 38 | /* 14px */ 39 | line-height: 1.25rem; 40 | /* 20px */ 41 | background-color: var(--vscode-panel-background); 42 | } 43 | 44 | .search-input:focus { 45 | outline: none; 46 | } 47 | 48 | .search-icon { 49 | position: absolute; 50 | right: 0; 51 | top: 0; 52 | margin-top: 0.625rem; 53 | /* 12px */ 54 | margin-right: 1rem; 55 | /* 16px */ 56 | fill: var(--vscode-editor-foreground); 57 | } 58 | 59 | .skeleton-loader { 60 | width: 100%; 61 | height: 15px; 62 | display: block; 63 | background: linear-gradient(to right, 64 | rgba(255, 255, 255, 0), 65 | rgba(255, 255, 255, 0.5) 50%, 66 | rgba(255, 255, 255, 0) 80%), 67 | lightgray; 68 | background-repeat: repeat-y; 69 | background-size: 50px 500px; 70 | background-position: 0 0; 71 | animation: shine 1s infinite; 72 | } 73 | 74 | @keyframes shine { 75 | to { 76 | background-position: 100% 0; 77 | } 78 | } -------------------------------------------------------------------------------- /vscode/media/market-place/market-place.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 16 |
17 |
18 |
19 | 21 |
22 | 26 | 28 | 29 |
30 |
31 | 33 | 37 | 38 | 39 | Create new agent 40 | 41 |
42 |
43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /vscode/media/questionnaire/questionnaire.js: -------------------------------------------------------------------------------- 1 | class Questionnaire { 2 | constructor(json, ref) { 3 | this.json = json; 4 | this.ref = ref; 5 | 6 | this.container = document.createElement("div"); 7 | } 8 | 9 | buildQuestionnaire() { 10 | const grid = document.getElementById("questionnaire-grid"); 11 | grid.innerHTML = ""; 12 | let container = null; 13 | this.json.forEach(({ id, message, onclick, icon, isGradient }) => { 14 | container = document.createElement("div"); 15 | container.id = id; 16 | container.classList.add("max-w-full", "p-1", "cursor-pointer"); 17 | 18 | const cardContainer = document.createElement("div"); 19 | cardContainer.classList.add("w-full", "rounded-lg", isGradient ? "questionnaire-card-gradient" : "questionnaire-card", "py-3", "px-3", "relative", "text-center"); 20 | cardContainer.addEventListener("click", () => onclick(this.ref)); 21 | 22 | const _message = document.createElement("span"); 23 | _message.style.fontSize = ".85rem"; 24 | _message.style.lineHeight = ".75rem"; 25 | _message.classList.add("font-bold"); 26 | _message.textContent = message; 27 | 28 | // const iconContainer = document.createElement("div"); 29 | // iconContainer.classList.add("absolute", "bottom-1", "right-1", "border", "border-black", "rounded-full", "p-1", "bg-white"); 30 | // iconContainer.innerHTML = icon; 31 | 32 | cardContainer.appendChild(_message); 33 | container.appendChild(cardContainer); 34 | grid.appendChild(container); 35 | }); 36 | } 37 | } -------------------------------------------------------------------------------- /vscode/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fluttergpt", 3 | "displayName": "CommandDash: AI Code Agents for libraries", 4 | "description": "Only AI Copilot to integrate libraries with expert agents", 5 | "version": "0.5.2", 6 | "publisher": "WelltestedAI", 7 | "icon": "media/icon.png", 8 | "engines": { 9 | "vscode": "^1.77.0" 10 | }, 11 | "repository": { 12 | "url": "https://github.com/CommandDash/commanddash" 13 | }, 14 | "bugs": { 15 | "url": "https://github.com/CommandDash/commanddash/issues", 16 | "email": "team@commanddash.io" 17 | }, 18 | "homepage": "https://commanddash.io", 19 | "categories": [ 20 | "Programming Languages", 21 | "Snippets", 22 | "Education" 23 | ], 24 | "keywords": [ 25 | "chat", 26 | "copilot", 27 | "coding", 28 | "gpt", 29 | "command", 30 | "autopilot", 31 | "dash", 32 | "comandash", 33 | "comanddash", 34 | "commandash" 35 | ], 36 | "activationEvents": [], 37 | "extensionDependencies": [], 38 | "main": "./out/extension.js", 39 | "contributes": { 40 | "extensionKind": [ 41 | "ui" 42 | ], 43 | "viewsContainers": { 44 | "activitybar": [ 45 | { 46 | "id": "webview", 47 | "title": "CommandDash", 48 | "icon": "./media/activity-icon.png" 49 | } 50 | ] 51 | }, 52 | "views": { 53 | "webview": [ 54 | { 55 | "type": "webview", 56 | "id": "dash.chatView", 57 | "name": "Panel" 58 | } 59 | ] 60 | }, 61 | "configuration": { 62 | "title": "CommandDash", 63 | "type": "object", 64 | "properties": { 65 | "fluttergpt.apiKey": { 66 | "type": "string", 67 | "markdownDescription": "Gemini API KEY (https://aistudio.google.com/)" 68 | } 69 | } 70 | }, 71 | "keybindings": [ 72 | { 73 | "command": "dash.attachToDash.menu", 74 | "key": "ctrl+R", 75 | "mac": "cmd+R" 76 | } 77 | ], 78 | "commands": [ 79 | { 80 | "command": "dash.attachToDash", 81 | "title": "Dash: Attach Snippet to Dash" 82 | }, 83 | { 84 | "command": "dash.attachToDash.menu", 85 | "title": "Attach Snippet to Dash" 86 | }, 87 | { 88 | "command": "dash.clearChat", 89 | "title": "Clear Chat", 90 | "icon": { 91 | "light": "resources/light/trash.svg", 92 | "dark": "resources/dark/trash.svg" 93 | } 94 | }, 95 | { 96 | "command": "dash.marketPlace", 97 | "title": "Market Place", 98 | "icon": { 99 | "light": "resources/light/market-place.svg", 100 | "dark": "resources/dark/market-place.svg" 101 | } 102 | }, 103 | { 104 | "command": "dash.backButton", 105 | "title": "Back", 106 | "icon": { 107 | "light": "resources/light/back.svg", 108 | "dark": "resources/dark/back.svg" 109 | } 110 | } 111 | ], 112 | "menus": { 113 | "commandPalette": [ 114 | { 115 | "command": "dash.attachToDash", 116 | "when": "editorHasSelection" 117 | }, 118 | { 119 | "command": "dash.attachToDash.menu", 120 | "when": "false" 121 | } 122 | ], 123 | "editor/context": [ 124 | { 125 | "command": "dash.attachToDash.menu", 126 | "when": "editorHasSelection", 127 | "group": "dash-menu-group@3" 128 | } 129 | ], 130 | "view/title": [ 131 | { 132 | "command": "dash.clearChat", 133 | "group": "navigation", 134 | "when": "view == dash.chatView && !dash:isMarketPlace" 135 | }, 136 | { 137 | "command": "dash.marketPlace", 138 | "group": "navigation", 139 | "when": "view == dash.chatView && !dash:isMarketPlace" 140 | }, 141 | { 142 | "command": "dash.backButton", 143 | "group": "navigation", 144 | "when": "view == dash.chatView && dash:isMarketPlace" 145 | } 146 | ], 147 | "dash.createMenu": [] 148 | }, 149 | "submenus": [] 150 | }, 151 | "scripts": { 152 | "vscode:prepublish": "npm run -S esbuild-base", 153 | "esbuild-base": "esbuild ./src/extension.ts --bundle --outfile=out/extension.js --external:vscode --format=cjs --platform=node", 154 | "build": "npm run -S esbuild-base -- --sourcemap", 155 | "watch": "npm run -S esbuild-base -- --sourcemap --watch", 156 | "pretest": "npm run compile && npm run lint", 157 | "lint": "eslint src --ext ts", 158 | "test": "node ./out/test/runTest.js" 159 | }, 160 | "devDependencies": { 161 | "@types/glob": "^8.1.0", 162 | "@types/js-yaml": "^4.0.5", 163 | "@types/mocha": "^10.0.1", 164 | "@types/node": "20.x", 165 | "@types/vscode": "^1.77.0", 166 | "@typescript-eslint/eslint-plugin": "^5.59.2", 167 | "@typescript-eslint/parser": "^5.59.2", 168 | "@vscode/test-electron": "^2.3.0", 169 | "esbuild": "^0.20.1", 170 | "eslint": "^8.39.0", 171 | "glob": "^10.2.2", 172 | "mocha": "^10.2.0", 173 | "typescript": "^5.0.4" 174 | }, 175 | "dependencies": { 176 | "@vscode/extension-telemetry": "^0.8.1", 177 | "axios": "^1.4.0", 178 | "dotenv": "^16.3.1", 179 | "js-yaml": "^4.1.0", 180 | "tailwindcss": "^3.4.3", 181 | "url-metadata": "^3.3.1", 182 | "vscode-languageclient": "^9.0.1" 183 | } 184 | } -------------------------------------------------------------------------------- /vscode/resources/dark/back.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /vscode/resources/dark/market-place.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /vscode/resources/dark/trash.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /vscode/resources/light/back.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | -------------------------------------------------------------------------------- /vscode/resources/light/market-place.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /vscode/resources/light/trash.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /vscode/src/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommandDash/commanddash/8d5d61379a47641c85d93fcbcda4f9175d44f5fc/vscode/src/.DS_Store -------------------------------------------------------------------------------- /vscode/src/action-managers/diff-view-agent.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | 3 | export class DiffViewAgent { 4 | static async handleResponse(userChoice: string, data: any, messageId: string) { 5 | const selection = data.selection; 6 | const optimizedCode = data.optimizedCode; 7 | const originalCodeUri = data.path; 8 | 9 | 10 | let document = vscode.workspace.textDocuments.find(function (e) { 11 | console.log(e.uri.toString(), originalCodeUri); 12 | return e.uri.toString() === originalCodeUri; 13 | }); 14 | 15 | // const selection = chip.referenceData.selection; 16 | if (!document) { 17 | // if document is not founds, open the document 18 | let uri = vscode.Uri.parse(originalCodeUri); 19 | document = await vscode.workspace.openTextDocument(uri); 20 | if (!document) { 21 | return; 22 | } 23 | } 24 | if (userChoice === 'accept') { 25 | 26 | vscode.commands.executeCommand('workbench.action.closeActiveEditor'); // assuming apply edit time will be enough for the diff to close so user doesn't see a jank. 27 | // Apply the optimized code 28 | const workspaceEdit = new vscode.WorkspaceEdit(); 29 | const entireDocumentRange = new vscode.Range( 30 | document.positionAt(0), 31 | document.positionAt(document.getText().length) 32 | ); 33 | workspaceEdit.replace(vscode.Uri.parse(originalCodeUri), entireDocumentRange, optimizedCode); 34 | const isSuccess = await vscode.workspace.applyEdit(workspaceEdit); 35 | if (isSuccess) { 36 | if (vscode.window.activeTextEditor?.document.uri.toString() !== document.uri.toString()) { 37 | await vscode.window.showTextDocument(document, { 38 | viewColumn: selection.start.character, 39 | preserveFocus: false, 40 | selection: new vscode.Range(new vscode.Position(selection.start.line, selection.start.character), new vscode.Position(selection.start.line, selection.start.character)) 41 | }); 42 | } 43 | } 44 | 45 | } else { 46 | await vscode.commands.executeCommand('workbench.action.closeActiveEditor'); 47 | let openDocument = await vscode.workspace.openTextDocument(document.uri); 48 | // show text document if the document is not open 49 | if (vscode.window.activeTextEditor?.document.uri.toString() !== document.uri.toString()) { 50 | await vscode.window.showTextDocument(openDocument, { 51 | viewColumn: selection.start.character, 52 | preserveFocus: false, 53 | selection: new vscode.Range(new vscode.Position(selection.start.line, selection.start.character), new vscode.Position(selection.start.line, selection.start.character)) 54 | }); 55 | } 56 | 57 | } 58 | return { role: "dash", parts: 'Code refactored successfully!', messageId: messageId, data: {}, buttons: [], agent: "messageView" }; 59 | } 60 | } -------------------------------------------------------------------------------- /vscode/src/extension.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/naming-convention */ 2 | // The module 'vscode' contains the VS Code extensibility API 3 | // Import the module and reference it with the alias vscode in your code below 4 | import * as vscode from 'vscode'; 5 | 6 | import { activateTelemetry, logEvent } from './utilities/telemetry-reporter'; 7 | import * as dotenv from 'dotenv'; 8 | import path = require('path'); 9 | // import { ExtensionVersionManager } from './utilities/update-check'; 10 | import { FlutterGPTViewProvider } from './providers/chat_view_provider'; 11 | import { initCommands, registerCommand } from './utilities/command-manager'; 12 | import { CacheManager } from './utilities/cache-manager'; 13 | import { tempScheme, virtualDocumentProvider } from './utilities/virtual-document-provider'; 14 | import { SetupManager, SetupStep } from './utilities/setup-manager/setup-manager'; 15 | import { StorageManager } from './utilities/storage-manager'; 16 | 17 | export const DART_MODE: vscode.DocumentFilter & { language: string } = { language: "dart", scheme: "file" }; 18 | 19 | const activeFileFilters: vscode.DocumentFilter[] = [DART_MODE]; 20 | 21 | export async function activate(context: vscode.ExtensionContext) { 22 | // handleAgents(); 23 | StorageManager.instance.loadContext(context); 24 | 25 | activateTelemetry(context); 26 | 27 | 28 | // Initiate cache manager 29 | const cacheManager = CacheManager.getInstance(context.globalState, context.workspaceState); 30 | 31 | const setupManager = SetupManager.getInstance(); 32 | try { 33 | await setupManager.init(context); 34 | } catch (error) { 35 | console.log(`Error: ${error}`); 36 | } 37 | 38 | dotenv.config({ path: path.join(__dirname, '../.env') }); 39 | const chatViewProvider = initWebview(context); 40 | 41 | var _inlineErrorCommand: vscode.Disposable; 42 | 43 | initFlutterExtension(context, chatViewProvider); 44 | 45 | setupManager.onDidChangeSetup((event) => { 46 | switch (event) { 47 | case SetupStep.github: 48 | // Handle any login related side-effects. 49 | break; 50 | case SetupStep.executable: 51 | // Handle any executable related side-effects 52 | break; 53 | } 54 | }); 55 | 56 | vscode.workspace.registerTextDocumentContentProvider(tempScheme, virtualDocumentProvider); 57 | logEvent('activated'); 58 | } 59 | 60 | function initWebview(context: vscode.ExtensionContext) { 61 | // Create a new FlutterGPTViewProvider instance and register it with the extension's context 62 | const chatProvider = new FlutterGPTViewProvider(context.extensionUri, context); 63 | // Register the provider with the extension's context 64 | context.subscriptions.push( 65 | vscode.window.registerWebviewViewProvider(FlutterGPTViewProvider.viewType, chatProvider, 66 | { 67 | webviewOptions: { retainContextWhenHidden: true }, 68 | } 69 | ) 70 | ); 71 | 72 | return chatProvider; 73 | } 74 | 75 | function initFlutterExtension(context: vscode.ExtensionContext, chatViewProvider: FlutterGPTViewProvider) { 76 | 77 | // const refactorActionProvider = new RefactorActionProvider(analyzer, geminiRepo, context); 78 | // context.subscriptions.push(vscode.languages.registerCodeActionsProvider(activeFileFilters, refactorActionProvider)); 79 | 80 | // const hoverProvider = new AIHoverProvider(geminiRepo, analyzer); 81 | // context.subscriptions.push(vscode.languages.registerHoverProvider(activeFileFilters, hoverProvider)); 82 | 83 | //TODO: Renable after moving to CommandDash 84 | // const errorActionProvider = new ErrorCodeActionProvider(analyzer, geminiRepo, context); 85 | // context.subscriptions.push(vscode.languages.registerCodeActionsProvider(activeFileFilters, errorActionProvider)); 86 | 87 | initCommands(context, chatViewProvider); 88 | 89 | } 90 | 91 | // This method is called when your extension is deactivated 92 | export function deactivate() { 93 | console.log("FlutterGPT deactivated"); 94 | } 95 | 96 | function showMissingApiKey() { 97 | vscode.window.showInformationMessage( 98 | 'Please add your Gemini Key to use FlutterGPT.', 99 | 'Add Now' 100 | ).then(selection => { 101 | if (selection === 'Add Now') { 102 | vscode.commands.executeCommand(FlutterGPTViewProvider.viewType + '.focus'); 103 | } 104 | }); 105 | } 106 | -------------------------------------------------------------------------------- /vscode/src/providers/error_code_actions_provider.ts: -------------------------------------------------------------------------------- 1 | 2 | import * as vscode from "vscode"; 3 | import { CodeAction } from "vscode"; 4 | import { Outline } from "../shared/types/custom_protocols"; 5 | import { cursorIsAt } from "../shared/utils"; 6 | import { ILspAnalyzer } from "../shared/types/LspAnalyzer"; 7 | 8 | 9 | export class ErrorCodeActionProvider implements vscode.CodeActionProvider { 10 | constructor(private readonly analyzer: ILspAnalyzer, private readonly extcontext: vscode.ExtensionContext) { } 11 | 12 | 13 | async provideCodeActions(document: vscode.TextDocument, range: vscode.Range | vscode.Selection, context: vscode.CodeActionContext, token: vscode.CancellationToken): Promise { 14 | let functionAction = []; 15 | 16 | //We current need some scope for fixing errors since we can only replace range code and not append code anywhere in the file. 17 | const manualSelectionRange: vscode.Range | undefined = range.start.line !== range.end.line || range.start.character !== range.end.character ? range : undefined; 18 | let functionRange: { symbolRange: vscode.Range, symbol: Outline } | undefined = await cursorIsAt("METHOD", this.analyzer, document, vscode.window.activeTextEditor, range, false); 19 | 20 | const selectedRange = manualSelectionRange !== undefined ? manualSelectionRange : functionRange?.symbolRange; 21 | 22 | if (selectedRange !== undefined) { 23 | // quick fix for the function if there are errors 24 | const errors = context.diagnostics.filter((d) => d.range.intersection(selectedRange!) !== undefined); 25 | if (errors.length > 0) { 26 | const fixErrorsAction = new vscode.CodeAction("✨ Auto-Fix", vscode.CodeActionKind.QuickFix); 27 | fixErrorsAction.command = { 28 | arguments: [this.analyzer, errors, this.extcontext.globalState, selectedRange, this.analyzer, manualSelectionRange !== undefined ? undefined : functionRange?.symbol.element.name], 29 | command: "dash.fixErrors", 30 | title: "Fix errors", 31 | }; 32 | functionAction.push(fixErrorsAction); 33 | } 34 | 35 | return functionAction; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /vscode/src/repository/generation-repository.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | export abstract class GenerationRepository { 3 | protected apiKey?: string; 4 | 5 | constructor(apiKey: string) { 6 | this.apiKey = apiKey; 7 | } 8 | public abstract optimizeCode(finalString: string, contextualCode: String | undefined, globalState: vscode.Memento): Promise; 9 | public abstract fixErrors(finalString: string, contextualCode: String | undefined, errorsDescription: string, globalState: vscode.Memento): Promise; 10 | public abstract refactorCode(finalString: string, contextualCode: String | undefined, instructions: string, globalState: vscode.Memento): Promise; 11 | public abstract createModelClass(library: string | undefined, jsonStructure: string, includeHelpers: string | undefined, globalState: vscode.Memento): Promise; 12 | public abstract createRepositoryFromJson(description: string, globalState: vscode.Memento): Promise; 13 | public abstract createCodeFromBlueprint(blueprint: string, globalState: vscode.Memento): Promise; 14 | public abstract createCodeFromDescription(aboveText: string, belowText: string, instructions: string, globalState: vscode.Memento): Promise; 15 | } 16 | -------------------------------------------------------------------------------- /vscode/src/repository/welltested-repository.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/naming-convention */ 2 | import { APICommunicator } from "../utilities/api-communicator"; 3 | import { appendReferences } from "../utilities/prompt_helpers"; 4 | import { getReferenceEditor } from "../utilities/state-objects"; 5 | import * as vscode from 'vscode'; 6 | import { GenerationRepository } from "./generation-repository"; 7 | 8 | /** 9 | * This class is not currently active and will be implemented in a later phase of the roadmap 10 | * Represents the Welltested Repository. 11 | * This class is responsible for interacting with the Welltested API and performing code generation operations. 12 | * @extends GenerationRepository 13 | */ 14 | export class WelltestedRepostiory extends GenerationRepository { 15 | private api: APICommunicator; 16 | private static instance: WelltestedRepostiory; 17 | 18 | constructor(apiKey: string) { 19 | super(apiKey); 20 | this.api = new APICommunicator(); 21 | } 22 | 23 | public static getInstance(apiKey: string): WelltestedRepostiory { 24 | if (!WelltestedRepostiory.instance) { 25 | WelltestedRepostiory.instance = new WelltestedRepostiory(apiKey); 26 | } 27 | return WelltestedRepostiory.instance; 28 | } 29 | 30 | // TODO: Add proper error handling here 31 | public async optimizeCode(finalString: string, contextualCode: String | undefined, globalState: vscode.Memento): Promise { 32 | let referenceEditor = getReferenceEditor(globalState); 33 | let refrenceEditorText = appendReferences(referenceEditor, ''); 34 | const response = await this.api.post( 35 | '/ai/dev/optimizecode', { 36 | 'reference_editor_code': refrenceEditorText, 37 | 'contextual_code': contextualCode, 38 | 'document_code_string': finalString, 39 | } 40 | ); 41 | if (response === null) { 42 | return undefined; 43 | } 44 | return response; 45 | } 46 | public fixErrors(finalString: string, contextualCode: String | undefined, errorsDescription: string, globalState: vscode.Memento): Promise { 47 | throw new Error("Method not implemented."); 48 | } 49 | public refactorCode(finalString: string, contextualCode: String | undefined, instructions: string, globalState: vscode.Memento): Promise { 50 | throw new Error("Method not implemented."); 51 | } 52 | public createCodeFromBlueprint(blueprint: string, globalState: vscode.Memento): Promise { 53 | throw new Error("Method not implemented."); 54 | } 55 | public createCodeFromDescription(aboveText: string, belowText: string, instructions: string, globalState: vscode.Memento): Promise { 56 | throw new Error("Method not implemented."); 57 | } 58 | public createModelClass(library: string | undefined, jsonStructure: string, includeHelpers: string | undefined, globalState: vscode.Memento): Promise { 59 | throw new Error("Method not implemented."); 60 | } 61 | public createRepositoryFromJson(description: string, globalState: vscode.Memento): Promise { 62 | throw new Error("Method not implemented."); 63 | } 64 | } -------------------------------------------------------------------------------- /vscode/src/shared/types/constants.ts: -------------------------------------------------------------------------------- 1 | import * as fs from 'fs'; 2 | 3 | export const isCI = !!process.env.CI; 4 | export const isDartCodeTestRun = !!process.env.DART_CODE_IS_TEST_RUN; 5 | export const isWin = process.platform.startsWith("win"); 6 | export const isMac = process.platform === "darwin"; 7 | export const isLinux = !isWin && !isMac; 8 | export const isChromeOS = isLinux && fs.existsSync("/dev/.cros_milestone"); 9 | -------------------------------------------------------------------------------- /vscode/src/shared/types/custom_protocols.ts: -------------------------------------------------------------------------------- 1 | import { Location, NotificationType, Range, RequestType, RequestType0, TextDocumentPositionParams, URI, WorkspaceEdit } from "vscode-languageclient"; 2 | 3 | export class AnalyzerStatusNotification { 4 | public static type = new NotificationType("$/analyzerStatus"); 5 | } 6 | 7 | export interface AnalyzerStatusParams { 8 | readonly isAnalyzing: boolean; 9 | } 10 | 11 | export class OpenUriNotification { 12 | public static type = new NotificationType("dart/openUri"); 13 | } 14 | 15 | export interface OpenUriParams { 16 | readonly uri: URI; 17 | } 18 | 19 | export class PublishClosingLabelsNotification { 20 | public static type = new NotificationType("dart/textDocument/publishClosingLabels"); 21 | } 22 | 23 | export class PublishOutlineNotification { 24 | public static type = new NotificationType("dart/textDocument/publishOutline"); 25 | } 26 | 27 | export class PublishFlutterOutlineNotification { 28 | public static type = new NotificationType("dart/textDocument/publishFlutterOutline"); 29 | } 30 | 31 | export class SuperRequest { 32 | public static type = new RequestType("dart/textDocument/super"); 33 | } 34 | 35 | export class DiagnosticServerRequest { 36 | public static type = new RequestType0<{ port: number }, void>("dart/diagnosticServer"); 37 | } 38 | 39 | export class ReanalyzeRequest { 40 | public static type = new RequestType0("dart/reanalyze"); 41 | } 42 | 43 | export class CompleteStatementRequest { 44 | public static type = new RequestType("dart/completeStatement"); 45 | } 46 | 47 | export interface ClosingLabelsParams { 48 | readonly uri: string; 49 | readonly labels: ClosingLabel[]; 50 | } 51 | 52 | export interface ClosingLabel { 53 | readonly label: string; 54 | readonly range: Range; 55 | } 56 | 57 | export interface OutlineParams { 58 | readonly uri: string; 59 | readonly outline: Outline; 60 | } 61 | 62 | export interface Outline { 63 | readonly element: Element; 64 | readonly range: Range; 65 | readonly codeRange: Range; 66 | readonly children: Outline[] | undefined; 67 | } 68 | 69 | export interface FlutterOutlineParams { 70 | readonly uri: string; 71 | readonly outline: FlutterOutline; 72 | } 73 | 74 | export interface FlutterOutline { 75 | readonly attributes?: FlutterOutlineAttribute[]; 76 | readonly variableName?: string; 77 | readonly className?: string; 78 | readonly label?: string; 79 | readonly dartElement?: Element; 80 | readonly range: Range; 81 | readonly codeRange: Range; 82 | readonly children?: FlutterOutline[]; 83 | readonly kind: string; 84 | } 85 | 86 | export interface FlutterOutlineAttribute { 87 | name: string; 88 | label: string; 89 | valueRange: Range; 90 | } 91 | 92 | export interface Element { 93 | readonly name: string; 94 | readonly range: Range | undefined; 95 | readonly kind: string; 96 | readonly parameters?: string; 97 | readonly typeParameters?: string; 98 | readonly returnType?: string; 99 | } 100 | export interface WorkspaceContext { 101 | // Define the interface for WorkspaceContext 102 | } 103 | -------------------------------------------------------------------------------- /vscode/src/shared/types/interfaces.ts: -------------------------------------------------------------------------------- 1 | import * as child_process from "child_process"; 2 | import * as stream from "stream"; 3 | import { Event } from "vscode"; 4 | import { WorkspaceContext } from "./custom_protocols"; 5 | 6 | export interface SdkSearchResults { 7 | // The fully resolved path to the SDK. 8 | sdkPath?: string; 9 | // The original path (before following symlinks) that led us to [sdkPath]. 10 | originalPath?: string; 11 | candidatePaths: string[]; 12 | sdkInitScript: string | undefined; 13 | } 14 | 15 | export interface SdkSearchResult { 16 | // The fully resolved path to the SDK. 17 | sdkPath: string; 18 | // The original path (before following symlinks) that led us to [sdkPath]. 19 | originalPath: string; 20 | } 21 | 22 | export interface Sdks { 23 | readonly dart?: string; 24 | readonly dartVersion?: string; 25 | readonly flutter?: string; 26 | readonly flutterVersion?: string; 27 | readonly dartSdkIsFromFlutter: boolean; 28 | } 29 | 30 | export interface DartSdks extends Sdks { 31 | readonly dart: string; 32 | } 33 | 34 | export interface FlutterSdks extends Sdks { 35 | readonly flutter: string; 36 | } 37 | 38 | export interface DartWorkspaceContext extends WorkspaceContext { 39 | readonly sdks: DartSdks; 40 | } 41 | 42 | // TODO(dantup): Move capabilities onto here? 43 | export interface FlutterWorkspaceContext extends WorkspaceContext { 44 | readonly sdks: FlutterSdks; 45 | } 46 | 47 | export interface WritableWorkspaceConfig { 48 | // All fields here should handle undefined, and the default (undefined) state 49 | // should be what is expected from a standard workspace without any additional 50 | // config. 51 | 52 | startDevToolsServerEagerly?: boolean; 53 | startDevToolsFromDaemon?: boolean; 54 | disableAnalytics?: boolean; 55 | disableAutomaticPackageGet?: boolean; 56 | disableSdkUpdateChecks?: boolean; 57 | disableStartupPrompts?: boolean; 58 | flutterDaemonScript?: CustomScript; 59 | flutterDevToolsScript?: CustomScript; 60 | flutterDoctorScript?: CustomScript; 61 | flutterRunScript?: CustomScript; 62 | flutterSdkHome?: string; 63 | flutterTestScript?: CustomScript; 64 | flutterToolsScript?: CustomScript; 65 | flutterVersion?: string; 66 | useLegacyProtocol?: boolean; 67 | forceFlutterWorkspace?: boolean; 68 | forceFlutterDebug?: boolean; 69 | skipFlutterInitialization?: boolean; 70 | omitTargetFlag?: boolean; 71 | defaultDartSdk?: string; 72 | restartMacDaemonMessage?: string; 73 | localDeviceCommandAdviceMessage?: string; 74 | localMacWarningMessage?: string; 75 | /// Whether or not we can use pkg:test for running tests. This means the tool supports 76 | /// arguments like "--plain-name", "--name". 77 | /// 78 | /// true: definitely does support it (Bazel) 79 | /// false: definitely does not support it (Dart SDK) 80 | /// undefined: only if there's a pubspec 81 | supportsPackageTest?: boolean; 82 | /// Similar to [supportsPackageTest], but whether we can successfully run 83 | /// commands like "dart run test:test --version". 84 | supportsDartRunTest?: boolean; 85 | } 86 | 87 | export type WorkspaceConfig = Readonly; 88 | export interface CustomScript { 89 | script: string | undefined; 90 | replacesArgs: number | undefined; 91 | } 92 | 93 | export interface DartProjectTemplate { 94 | readonly name: string; 95 | readonly label: string; 96 | readonly description: string; 97 | readonly categories: string[]; 98 | readonly entrypoint: string; 99 | } 100 | 101 | export interface FlutterProjectTemplate { 102 | readonly id: string; 103 | readonly empty?: boolean; 104 | } 105 | 106 | export interface FlutterCreateTriggerData { 107 | readonly sample?: string; 108 | readonly template?: string; 109 | readonly empty?: boolean; 110 | } 111 | 112 | 113 | export interface IAmDisposable { 114 | dispose(): void | Promise; 115 | } 116 | 117 | export interface CancellationToken { 118 | isCancellationRequested: boolean; 119 | onCancellationRequested: Event; 120 | } 121 | 122 | export interface FlutterCreateCommandArgs { 123 | projectPath?: string; 124 | projectName?: string; 125 | triggerData?: FlutterCreateTriggerData; 126 | platform?: string; 127 | } 128 | 129 | export interface CustomEmulatorDefinition { 130 | id: string; 131 | name: string; 132 | executable: string; 133 | args?: string[]; 134 | } 135 | 136 | export interface Location { 137 | startLine: number; 138 | startColumn: number; 139 | length: number; 140 | } 141 | 142 | export interface FlutterRawSurveyData { 143 | uniqueId: string; 144 | title: string; 145 | url: string; 146 | startDate: string; 147 | endDate: string; 148 | } 149 | 150 | export interface FlutterSurveyData { 151 | uniqueId: string; 152 | title: string; 153 | url: string; 154 | startDate: number; 155 | endDate: number; 156 | } 157 | 158 | export type SpawnedProcess = child_process.ChildProcess & { 159 | stdin: stream.Writable, 160 | stdout: stream.Readable, 161 | stderr: stream.Readable, 162 | }; 163 | 164 | export interface OpenedFileInformation { 165 | readonly contents: string; 166 | readonly selectionOffset: number; 167 | readonly selectionLength: number; 168 | } 169 | 170 | export interface DevToolsPage { 171 | id: string; 172 | commandId: string; 173 | routeId?: (flutterVersion: string | undefined) => string; 174 | title: string; 175 | } 176 | 177 | export interface WidgetErrorInspectData { 178 | errorDescription: string; 179 | devToolsUrl: string; 180 | inspectorReference: string; 181 | } 182 | 183 | export interface Range { 184 | start: Position; 185 | end: Position; 186 | } 187 | 188 | export interface Position { 189 | // Zero-based line number. 190 | line: number; 191 | // Zero-based line number. 192 | character: number; 193 | } 194 | 195 | export interface Analytics { 196 | logFlutterSurveyShown(): void; 197 | logFlutterSurveyClicked(): void; 198 | logFlutterSurveyDismissed(): void; 199 | } 200 | 201 | export interface MyCancellationToken { 202 | isCancellationRequested: boolean; 203 | } 204 | 205 | export interface CustomDevToolsConfig { 206 | args?: string[]; 207 | path?: string; 208 | env?: { [key: string]: string }; 209 | } 210 | 211 | export interface ExtensionConfig { 212 | get experimentalTestRunnerInSdk(): boolean; 213 | } 214 | -------------------------------------------------------------------------------- /vscode/src/shared/types/outline.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommandDash/commanddash/8d5d61379a47641c85d93fcbcda4f9175d44f5fc/vscode/src/shared/types/outline.ts -------------------------------------------------------------------------------- /vscode/src/shared/types/token.ts: -------------------------------------------------------------------------------- 1 | export type Token = { 2 | line: number; 3 | start: number; 4 | length: number; 5 | tokenTypeNumber: number; 6 | tokenType: string | undefined; 7 | tokenModifiers: number; 8 | name: string; 9 | code: string | undefined; 10 | path: string; 11 | }; -------------------------------------------------------------------------------- /vscode/src/test/runTest.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | 3 | import { runTests } from '@vscode/test-electron'; 4 | 5 | async function main() { 6 | try { 7 | // The folder containing the Extension Manifest package.json 8 | // Passed to `--extensionDevelopmentPath` 9 | const extensionDevelopmentPath = path.resolve(__dirname, '../../'); 10 | 11 | // The path to test runner 12 | // Passed to --extensionTestsPath 13 | const extensionTestsPath = path.resolve(__dirname, './suite/index'); 14 | 15 | // Download VS Code, unzip it and run the integration test 16 | await runTests({ extensionDevelopmentPath, extensionTestsPath }); 17 | } catch (err) { 18 | console.error('Failed to run tests', err); 19 | process.exit(1); 20 | } 21 | } 22 | 23 | main(); 24 | -------------------------------------------------------------------------------- /vscode/src/test/suite/index.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | import * as Mocha from 'mocha'; 3 | import {glob} from 'glob'; 4 | 5 | export function run(): Promise { 6 | // Create the mocha test 7 | const mocha = new Mocha({ 8 | ui: 'tdd', 9 | color: true 10 | }); 11 | 12 | const testsRoot = path.resolve(__dirname, '..'); 13 | 14 | return new Promise((c, e) => { 15 | glob('**/**.test.js', { cwd: testsRoot }).then((files) =>{ 16 | // Add files to the test suite 17 | files.forEach(f => mocha.addFile(path.resolve(testsRoot, f))); 18 | 19 | try { 20 | // Run the mocha test 21 | mocha.run(failures => { 22 | if (failures > 0) { 23 | e(new Error(`${failures} tests failed.`)); 24 | } else { 25 | c(); 26 | } 27 | }); 28 | } catch (err) { 29 | console.error(err); 30 | e(err); 31 | } 32 | }); 33 | }); 34 | } 35 | -------------------------------------------------------------------------------- /vscode/src/test/suite/src/utilities/virtual-document-provider.test.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import * as assert from 'assert'; 3 | import { tempScheme, virtualDocumentProvider } from '../../../../utilities/virtual-document-provider'; 4 | 5 | suite('VirtualDocumentProvider Test Suite', () => { 6 | vscode.window.showInformationMessage('Start all tests for VirtualDocumentProvider.'); 7 | 8 | test('Add and provide document content successfully', async () => { 9 | const testUri = vscode.Uri.parse(`${tempScheme}:///test-doc`); 10 | const testContent = 'Test content for our document'; 11 | 12 | // Simulate adding a document 13 | virtualDocumentProvider.addDocument(testUri, testContent); 14 | 15 | // Attempt to retrieve the document's content 16 | const returnedContent = await virtualDocumentProvider.provideTextDocumentContent(testUri, new vscode.CancellationTokenSource().token); 17 | 18 | // Assert that the returned content matches what we added 19 | assert.strictEqual(returnedContent, testContent); 20 | }); 21 | 22 | test('Remove a document and ensure it\'s gone', async () => { 23 | const testUri = vscode.Uri.parse(`${tempScheme}:///to-be-removed-doc`); 24 | const testContent = 'This document will be removed'; 25 | 26 | // Add then remove a document 27 | virtualDocumentProvider.addDocument(testUri, testContent); 28 | virtualDocumentProvider.removeDocument(testUri); 29 | 30 | // Attempt to retrieve the now-removed document's content 31 | try { 32 | await virtualDocumentProvider.provideTextDocumentContent(testUri, new vscode.CancellationTokenSource().token); 33 | // If the above line does not throw, the test should fail 34 | assert.fail('Expected provideTextDocumentContent to throw for removed document, but it did not.'); 35 | } catch (error) { 36 | if (error instanceof Error){ 37 | assert.strictEqual(error.message, 'No Document Found Error'); 38 | } 39 | else {throw new Error('error is not Error');} 40 | } 41 | }); 42 | 43 | test('Attempt to fetch content of a non-existent document', async () => { 44 | // Define a URI for a document we know does not exist 45 | const nonexistentUri = vscode.Uri.parse(`${tempScheme}:///nonexistent-doc`); 46 | 47 | // Attempt to fetch this document's content, expecting an error 48 | try { 49 | await virtualDocumentProvider.provideTextDocumentContent(nonexistentUri, new vscode.CancellationTokenSource().token); 50 | // If the above line does not throw, the test should fail 51 | assert.fail('Expected an error for non-existent document content, but did not get one.'); 52 | } catch (error) { 53 | 54 | if (error instanceof Error){ 55 | assert.strictEqual(error.message, 'No Document Found Error'); 56 | } 57 | else {throw new Error('error is not Error');} 58 | 59 | } 60 | }); 61 | }); -------------------------------------------------------------------------------- /vscode/src/tools/create/class_model_from_json.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import { extractDartCode, extractExplanation, extractReferenceTextFromEditor } from '../../utilities/code-processing'; 3 | import { getReferenceEditor } from '../../utilities/state-objects'; 4 | import { logEvent } from '../../utilities/telemetry-reporter'; 5 | import { GenerationRepository } from '../../repository/generation-repository'; 6 | 7 | //not active currently. to be thought out and revised again. 8 | export async function createModelClass(generationRepository: GenerationRepository, globalState: vscode.Memento) { 9 | logEvent("create-model-class", { 'type': "create" }); 10 | try { 11 | const jsonStructure = await vscode.window.showInputBox({ 12 | prompt: "Enter JSON structure", 13 | value: "", 14 | valueSelection: undefined, 15 | placeHolder: "Paste your JSON structure here", 16 | password: false, 17 | ignoreFocusOut: false, 18 | validateInput: (value: string) => { 19 | try { 20 | JSON.parse(value); 21 | return null; 22 | } catch (e: any) { 23 | return e.message; 24 | } 25 | }, 26 | }); 27 | if (!jsonStructure) { 28 | return; 29 | } 30 | 31 | const library = await vscode.window.showQuickPick(["None", "Freezed", "JsonSerializable"], { 32 | placeHolder: "Select a library", 33 | }); 34 | 35 | const includeHelpers = await vscode.window.showQuickPick(["Yes", "No"], { 36 | placeHolder: "Include toJson, fromJson, and copyWith methods?", 37 | }); 38 | 39 | await vscode.window.withProgress( 40 | { 41 | location: vscode.ProgressLocation.Notification, 42 | title: "Creating Model Class", 43 | cancellable: false, 44 | }, 45 | async (progress) => { 46 | let progressPercentage = 0; 47 | let prevProgressPercentage = 0; 48 | const progressInterval = setInterval(() => { 49 | prevProgressPercentage = progressPercentage; 50 | progressPercentage = (progressPercentage + 10) % 100; 51 | const increment = progressPercentage - prevProgressPercentage; 52 | progress.report({ increment }); 53 | }, 200); 54 | let prompt = `You're an expert Flutter/Dart coding assistant. Follow the user instructions carefully and to the letter.\n\n`; 55 | let referenceEditor = getReferenceEditor(globalState); 56 | if (referenceEditor !== undefined) { 57 | const referenceText = extractReferenceTextFromEditor(referenceEditor); 58 | if (referenceText !== '') { 59 | prompt += `Keeping in mind these references/context:\n${referenceText}\n`; 60 | } 61 | } 62 | prompt += `Create a Flutter model class, keeping null safety in mind for from the following JSON structure: ${jsonStructure}.`; 63 | 64 | if (library !== 'None') { 65 | prompt += `Use ${library}`; 66 | } 67 | if (includeHelpers === 'Yes') { 68 | prompt += `Make sure toJson, fromJson, and copyWith methods are included.`; 69 | } 70 | prompt += `Output the model class code in a single block.`; 71 | 72 | const result = await generationRepository.createModelClass(library, jsonStructure, includeHelpers, globalState); 73 | clearInterval(progressInterval); 74 | progress.report({ increment: 100 }); 75 | if (!result) { 76 | vscode.window.showErrorMessage("Failed to create model class. Please try again."); 77 | return; 78 | } 79 | 80 | const dartCode = extractDartCode(result); 81 | const editor = vscode.window.activeTextEditor; 82 | if (editor) { 83 | editor.edit((editBuilder) => { 84 | const position = editor.selection.active; 85 | editBuilder.insert(position, dartCode); 86 | }); 87 | vscode.window.showInformationMessage("Model class created successfully!"); 88 | } else { 89 | vscode.window.showErrorMessage("No active editor"); 90 | } 91 | } 92 | ); 93 | 94 | } catch (error: Error | unknown) { 95 | if (error instanceof Error) { 96 | vscode.window.showErrorMessage(`${error.message}`); 97 | } else { 98 | vscode.window.showErrorMessage(`Failed to create model class ${error}`); 99 | } 100 | } 101 | 102 | } -------------------------------------------------------------------------------- /vscode/src/tools/create/class_repository_from_json.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import { extractDartCode, extractReferenceTextFromEditor } from '../../utilities/code-processing'; 3 | import { getReferenceEditor } from '../../utilities/state-objects'; 4 | import { logEvent } from '../../utilities/telemetry-reporter'; 5 | import { GenerationRepository } from '../../repository/generation-repository'; 6 | //not active currently. to be thought out and revised again. 7 | export async function createRepoClassFromPostman(generationRepository: GenerationRepository, globalState: vscode.Memento) { 8 | logEvent('create-repo-class-from-postman', { 'type': "create" }); 9 | try { 10 | await vscode.window.withProgress({ 11 | location: vscode.ProgressLocation.Notification, 12 | title: "Generating API repository", 13 | cancellable: false 14 | }, async (progress) => { 15 | let progressPercentage = 0; 16 | let prevProgressPercentage = 0; 17 | const progressInterval = setInterval(() => { 18 | prevProgressPercentage = progressPercentage; 19 | progressPercentage = (progressPercentage + 10) % 100; 20 | const increment = progressPercentage - prevProgressPercentage; 21 | progress.report({ increment }); 22 | }, 200); 23 | 24 | let description = "placeholder"; 25 | const editor = vscode.window.activeTextEditor; 26 | if (editor) { 27 | const document = editor.document; 28 | try { 29 | description = JSON.stringify(JSON.parse(document.getText())); 30 | } catch (error) { 31 | vscode.window.showErrorMessage(`File content doesn't seem to be a json`); 32 | } 33 | } 34 | 35 | if (description === "placeholder") { 36 | return; 37 | } 38 | 39 | const result = await generationRepository.createRepositoryFromJson(description, globalState); 40 | clearInterval(progressInterval); 41 | progress.report({ increment: 100 }); 42 | if (!result) { 43 | vscode.window.showErrorMessage(`Failed to create api service`); 44 | return; 45 | } 46 | 47 | const dartCode = extractDartCode(result); 48 | if (editor) { 49 | const document = editor.document; 50 | const range = new vscode.Range( 51 | document.positionAt(0), 52 | document.positionAt(document.getText().length) 53 | ); 54 | editor.edit(editBuilder => { 55 | editBuilder.replace(range, dartCode); 56 | }); 57 | } 58 | }); 59 | } catch (error: Error | unknown) { 60 | if (error instanceof Error) { 61 | vscode.window.showErrorMessage(`${error.message}`); 62 | } else { 63 | vscode.window.showErrorMessage(`Failed to create api service ${error}`); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /vscode/src/tools/create/code_from_blueprint.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import { extractDartCode, extractExplanation, extractReferenceTextFromEditor } from '../../utilities/code-processing'; 3 | import { getReferenceEditor } from '../../utilities/state-objects'; 4 | import { logError, logEvent } from '../../utilities/telemetry-reporter'; 5 | import { GenerationRepository } from '../../repository/generation-repository'; 6 | 7 | export async function createCodeFromBlueprint(generationRepository: GenerationRepository, globalState: vscode.Memento) { 8 | logEvent('create-code-from-blueprint', { 'type': "create" }); 9 | const editor = vscode.window.activeTextEditor; 10 | if (!editor) { 11 | vscode.window.showErrorMessage('No active editor'); 12 | return; 13 | } 14 | 15 | const blueprint = editor.document.getText(editor.selection); 16 | if (!blueprint) { 17 | vscode.window.showErrorMessage('No blueprint selected'); 18 | return; 19 | } 20 | 21 | try { 22 | 23 | await vscode.window.withProgress({ 24 | location: vscode.ProgressLocation.Notification, 25 | title: "Creating Code", 26 | cancellable: false 27 | }, async (progress) => { 28 | let progressPercentage = 0; 29 | let prevProgressPercentage = 0; 30 | const progressInterval = setInterval(() => { 31 | prevProgressPercentage = progressPercentage; 32 | progressPercentage = (progressPercentage + 10) % 100; 33 | const increment = progressPercentage - prevProgressPercentage; 34 | progress.report({ increment }); 35 | }, 200); 36 | const result = await generationRepository.createCodeFromBlueprint(blueprint, globalState); 37 | clearInterval(progressInterval); 38 | progress.report({ increment: 100 }); 39 | if (!result) { 40 | vscode.window.showErrorMessage('Failed to create code'); 41 | return; 42 | } 43 | 44 | const dartCode = extractDartCode(result); 45 | editor.edit((editBuilder) => { 46 | 47 | editBuilder.replace(editor.selection, dartCode); 48 | 49 | }); 50 | vscode.window.showInformationMessage('Code added successfully!'); 51 | }); 52 | 53 | } catch (error: Error | unknown) { 54 | logError('code-from-blueprint-error', error); 55 | if (error instanceof Error) { 56 | vscode.window.showErrorMessage(`${error.message}`); 57 | } else { 58 | vscode.window.showErrorMessage(`Failed to create code: ${error}`); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /vscode/src/tools/create/code_from_description.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import { extractDartCode, extractReferenceTextFromEditor } from '../../utilities/code-processing'; 3 | import { getReferenceEditor } from '../../utilities/state-objects'; 4 | import { logEvent } from '../../utilities/telemetry-reporter'; 5 | import { GenerationRepository } from '../../repository/generation-repository'; 6 | 7 | export async function createCodeFromDescription(generationRepository: GenerationRepository, globalState: vscode.Memento) { 8 | logEvent('create-code-from-description', { 'type': "create" }); 9 | try { 10 | const editor = vscode.window.activeTextEditor; 11 | if (!editor) { 12 | vscode.window.showErrorMessage('No active editor'); 13 | return; 14 | } 15 | 16 | var { aboveText, belowText, cursorLine } = getCodeAroundCursor(editor); 17 | 18 | const instructions = await vscode.window.showInputBox({ prompt: "Enter refactor instructions" }); 19 | if (!instructions) { 20 | return; 21 | } 22 | 23 | await vscode.window.withProgress({ 24 | location: vscode.ProgressLocation.Notification, 25 | title: "Generating code", 26 | cancellable: false 27 | }, async (progress) => { 28 | let progressPercentage = 0; 29 | let prevProgressPercentage = 0; 30 | const progressInterval = setInterval(() => { 31 | prevProgressPercentage = progressPercentage; 32 | progressPercentage = (progressPercentage + 10) % 100; 33 | const increment = progressPercentage - prevProgressPercentage; 34 | progress.report({ increment }); 35 | }, 200); 36 | let prompt = `You're an expert Flutter/Dart coding assistant. Follow the user instructions carefully and to the letter.\n\n`; 37 | let referenceEditor = getReferenceEditor(globalState); 38 | if (referenceEditor !== undefined) { 39 | const referenceText = extractReferenceTextFromEditor(referenceEditor); 40 | if (referenceText !== '') { 41 | prompt += `Keeping in mind these references/context:\n${referenceText}\n`; 42 | } 43 | } 44 | prompt += `Create a valid Dart code block based on the following instructions:\n${instructions}\n\n`; 45 | prompt += `To give you more context, here's `; 46 | if (aboveText.length > 0) { 47 | prompt += `the code above the line where you're asked to insert the code: \n ${aboveText}\n\n`; 48 | } 49 | if (belowText.length > 0) { 50 | if (aboveText.length > 0) { prompt += `And here's `; } 51 | prompt += `the code below the line where you're asked to insert the code: \n ${belowText}\n\n`; 52 | } 53 | prompt += `Should you have any general suggestions, add them as comments before the code block. Inline comments are also welcome`; 54 | 55 | const result = await generationRepository.createCodeFromDescription(aboveText, belowText, instructions, globalState); 56 | 57 | clearInterval(progressInterval); 58 | progress.report({ increment: 100 }); 59 | if (!result) { 60 | vscode.window.showErrorMessage('Failed to create code'); 61 | return; 62 | } 63 | const createdCode = extractDartCode(result); 64 | 65 | editor.edit((editBuilder) => { 66 | const selection = new vscode.Selection(cursorLine, 0, cursorLine, 0); 67 | editBuilder.insert(selection.end, '\n'); 68 | editBuilder.insert(selection.end, createdCode); 69 | 70 | }); 71 | vscode.window.showInformationMessage('Code created successfully!'); 72 | }); 73 | } catch (error: Error | unknown) { 74 | if (error instanceof Error) { 75 | vscode.window.showErrorMessage(`${error.message}`); 76 | } else { 77 | vscode.window.showErrorMessage(`Failed to generate code: ${error}`); 78 | } 79 | } 80 | 81 | function getCodeAroundCursor(editor: vscode.TextEditor) { 82 | const maxWords = 2500; 83 | 84 | const cursorLine = editor.selection.active.line; 85 | let lineAbove = cursorLine - 1; 86 | let lineBelow = cursorLine + 1; 87 | let aboveWordCounter = 0; 88 | let belowWordCounter = 0; 89 | 90 | let iterationCounter = 0; 91 | while (iterationCounter < 1024) { 92 | let outOfAboveLines = lineAbove < 0; 93 | let outOfBelowLines = lineBelow >= editor.document.lineCount; 94 | if (outOfAboveLines && outOfBelowLines) { 95 | break; 96 | } 97 | 98 | if (!outOfAboveLines) { 99 | aboveWordCounter += editor.document.lineAt(lineAbove).text.split(' ').length; 100 | if (aboveWordCounter + belowWordCounter > maxWords) { break; } 101 | } 102 | 103 | if (!outOfBelowLines) { 104 | belowWordCounter += editor.document.lineAt(lineBelow).text.split(' ').length; 105 | if (aboveWordCounter + belowWordCounter > maxWords) { break; } 106 | } 107 | 108 | lineAbove--; 109 | lineBelow++; 110 | iterationCounter++; 111 | } 112 | 113 | if (lineAbove < 0) { lineAbove = 0; } 114 | if (lineBelow >= editor.document.lineCount) { lineBelow = editor.document.lineCount - 1; } 115 | 116 | var aboveText = editor.document.getText(new vscode.Range(lineAbove, 0, cursorLine + 1, 0)); 117 | var belowText = editor.document.getText(new vscode.Range(cursorLine + 1, 0, lineBelow, 0)); 118 | return { aboveText, belowText, cursorLine }; 119 | } 120 | } -------------------------------------------------------------------------------- /vscode/src/tools/inline-hints/inlint-hints-utils.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import { CacheManager } from '../../utilities/cache-manager'; 3 | import { shortcutInlineCodeGeneration } from '../../utilities/shortcut-hint-utils'; 4 | 5 | 6 | export async function activateInlineHints(cacheManager: CacheManager) { 7 | const completionDecoration = vscode.window.createTextEditorDecorationType({ 8 | cursor: 'pointer', 9 | after: { 10 | contentText: `Use ${shortcutInlineCodeGeneration()} to auto complete using CommandDash`, 11 | color: 'gray', 12 | fontStyle: 'italic', 13 | fontWeight: 'bold', 14 | }, 15 | }); 16 | 17 | vscode.workspace.onDidChangeTextDocument(async event => { 18 | const inlineCount = cacheManager.getInlineCompletionCount(); 19 | 20 | if (event.document.languageId === 'dart') { 21 | const activeEditor = vscode.window.activeTextEditor; 22 | 23 | if(!activeEditor){ 24 | return; 25 | } 26 | 27 | // Remove decorations after any change in the document 28 | activeEditor.setDecorations(completionDecoration, []); 29 | 30 | const currentLine = activeEditor.selection.active.line; 31 | const totalLines = activeEditor.document.lineCount; 32 | 33 | if(currentLine+1>=totalLines) {return ;} 34 | // Check if there's text on the first line 35 | const lineText = activeEditor.document.lineAt(currentLine + 1).text.trim(); 36 | // check if the previous line is a comment 37 | const isComment = activeEditor.document.lineAt(currentLine).text.trim().startsWith('//'); 38 | 39 | // If the user has not used inline completion for 5 times, show hint for the same 40 | if (inlineCount < 5) { 41 | if (lineText.length === 0) { 42 | if (isComment || await isFirstLineOfSymbol(activeEditor)) { 43 | // Set decoration on the current line 44 | const range = new vscode.Range(currentLine + 1, activeEditor.document.lineAt(currentLine).range.end.character, currentLine + 1, activeEditor.document.lineAt(currentLine).range.end.character); 45 | activeEditor.setDecorations(completionDecoration, [{ range }]); 46 | } 47 | } 48 | } 49 | } 50 | }); 51 | } 52 | 53 | 54 | export async function isFirstLineOfSymbol(editor: vscode.TextEditor): Promise { 55 | const cursorLine = editor.selection.active.line; 56 | 57 | // Retrieve the document symbols 58 | const symbols = await vscode.commands.executeCommand('vscode.executeDocumentSymbolProvider', editor.document.uri); 59 | const flatSymbols: vscode.DocumentSymbol[] = []; 60 | 61 | // Flatten the symbol tree into an array 62 | function flattenSymbol(symbol: vscode.DocumentSymbol) { 63 | flatSymbols.push(symbol); 64 | if (symbol.children && symbol.children.length > 0) { 65 | symbol.children.forEach(child => flattenSymbol(child)); 66 | } 67 | } 68 | 69 | if (symbols) { 70 | symbols.forEach(symbol => flattenSymbol(symbol)); 71 | } 72 | 73 | // Check if the cursor is at the first line of a method, function, or class 74 | for (const symbol of flatSymbols) { 75 | if (symbol.kind === vscode.SymbolKind.Method || symbol.kind === vscode.SymbolKind.Function || symbol.kind === vscode.SymbolKind.Class) { 76 | if (symbol.range.start.line === cursorLine) { 77 | return true; 78 | } 79 | } 80 | } 81 | 82 | return false; 83 | } -------------------------------------------------------------------------------- /vscode/src/tools/refactor/optimize_code.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import { extractDartCode, filterSurroundingCode, } from '../../utilities/code-processing'; 3 | import { logError, logEvent } from '../../utilities/telemetry-reporter'; 4 | import { ILspAnalyzer } from '../../shared/types/LspAnalyzer'; 5 | import { ContextualCodeProvider } from '../../utilities/contextual-code'; 6 | import { handleDiffViewAndMerge } from '../../utilities/diff-utils'; 7 | import { GenerationRepository } from '../../repository/generation-repository'; 8 | 9 | export async function optimizeCode(generationRepository: GenerationRepository, globalState: vscode.Memento, range: vscode.Range | undefined, analyzer: ILspAnalyzer, elementName: string | undefined, context: vscode.ExtensionContext) { 10 | logEvent('optimize-code', { 'type': 'refractor' }); 11 | const editor = vscode.window.activeTextEditor; 12 | if (!editor) { 13 | vscode.window.showErrorMessage('No active editor'); 14 | return; 15 | } 16 | // Get the entire document's text 17 | const entireDocumentText = editor.document.getText(); 18 | 19 | var selectedCode = editor.document.getText(editor.selection); 20 | var replaceRange: vscode.Range; 21 | replaceRange = editor.selection; 22 | if (!selectedCode) { 23 | if (range === undefined) { 24 | vscode.window.showErrorMessage('No code selected'); 25 | return; 26 | } 27 | // if no code is selected, we use the range 28 | selectedCode = editor.document.getText(range); 29 | replaceRange = range; 30 | } 31 | 32 | // Define the markers for highlighting 33 | const highlightStart = ""; 34 | const highlightEnd = ""; 35 | 36 | // Split the entire document into two parts, at the start of the selection 37 | const docStart = entireDocumentText.substring(0, editor.document.offsetAt(replaceRange.start)); 38 | const docEnd = entireDocumentText.substring(editor.document.offsetAt(replaceRange.end)); 39 | 40 | // Construct the final string with highlighted selected code 41 | const finalString = `${docStart}${highlightStart}${selectedCode}${highlightEnd}${docEnd}`; 42 | 43 | let documentRefactoredText = editor.document.getText(); // Get the entire document text 44 | 45 | try { 46 | await vscode.window.withProgress({ 47 | location: vscode.ProgressLocation.Notification, 48 | title: "Optimizing Code", 49 | cancellable: false 50 | }, async (progress) => { 51 | let progressPercentage = 0; 52 | let prevProgressPercentage = 0; 53 | const progressInterval = setInterval(() => { 54 | prevProgressPercentage = progressPercentage; 55 | progressPercentage = (progressPercentage + 10) % 100; 56 | const increment = progressPercentage - prevProgressPercentage; 57 | progress.report({ increment }); 58 | }, 200); 59 | 60 | let contextualCode = await new ContextualCodeProvider().getContextualCode(editor.document, replaceRange, analyzer, elementName); 61 | 62 | const result = await generationRepository.optimizeCode(finalString, contextualCode, globalState); 63 | if (!result) { 64 | vscode.window.showErrorMessage('Failed to optimize code. Please try again.'); 65 | return; 66 | } 67 | clearInterval(progressInterval); 68 | progress.report({ increment: 100 }); 69 | 70 | let optimizedCode = extractDartCode(result); 71 | if (!optimizedCode) { 72 | vscode.window.showErrorMessage('Failed to optimize code. Please try again.'); 73 | return; 74 | } 75 | optimizedCode = optimizedCode.replace(//g, ''); 76 | optimizedCode = filterSurroundingCode(editor.document.getText(), optimizedCode, replaceRange.start.line, replaceRange.end.line); 77 | console.log("Optimized code:", optimizedCode); 78 | 79 | 80 | // Modify the documentText string instead of the document directly 81 | const startOffset = editor.document.offsetAt(replaceRange.start); 82 | const endOffset = editor.document.offsetAt(replaceRange.end); 83 | documentRefactoredText = documentRefactoredText.substring(0, startOffset) + optimizedCode + documentRefactoredText.substring(endOffset); 84 | }); 85 | vscode.window.showInformationMessage('Code optimization successful!'); 86 | 87 | // Pass the current editor, current document uri and optimized code respectively. 88 | await handleDiffViewAndMerge(editor, editor.document.uri, editor.document.getText(), documentRefactoredText, context); 89 | } catch (error: Error | unknown) { 90 | logError('optimize-code-error', error); 91 | if (error instanceof Error) { 92 | vscode.window.showErrorMessage(`${error.message}`); 93 | } else { 94 | vscode.window.showErrorMessage(`Failed to fix code: ${error}`); 95 | } 96 | return ''; 97 | } 98 | } -------------------------------------------------------------------------------- /vscode/src/tools/reference/add_reference.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import { getReferenceEditor } from '../../utilities/state-objects'; 3 | import * as path from 'path'; 4 | import { logEvent } from '../../utilities/telemetry-reporter'; 5 | import { FlutterGPTViewProvider } from '../../providers/chat_view_provider'; 6 | 7 | export async function addToReference(globalState: vscode.Memento, flutterGPTViewProvider: FlutterGPTViewProvider) { 8 | logEvent('add-to-reference', { 'type': 'reference' }); 9 | 10 | const editor = vscode.window.activeTextEditor; 11 | if (!editor) { 12 | vscode.window.showErrorMessage('Please open a file first.'); 13 | return; 14 | } 15 | 16 | const referenceContent = editor.document.getText(editor.selection); 17 | const startLineNumber = editor.selection.start.line + 1; 18 | const endLineNumber = editor.selection.end.line + 1; 19 | 20 | 21 | const workspaceFolders = vscode.workspace.workspaceFolders; 22 | const fileName = path.basename(editor.document.fileName); 23 | let relativePath = editor.document.fileName; 24 | const filePath = editor.document.uri.fsPath; 25 | if (workspaceFolders && workspaceFolders.length > 0) { 26 | const workspaceRoot = workspaceFolders[0].uri.fsPath; 27 | relativePath = path.relative(workspaceRoot, editor.document.fileName); 28 | } 29 | 30 | flutterGPTViewProvider.postMessageToWebview({ 31 | type: 'addToReference', value: JSON.stringify({ 32 | filePath, 33 | relativePath: relativePath.trim(), 34 | referenceContent: `\`${relativePath.trim()}\`\n\`\`\`${extractFileExtension(fileName)}\n${referenceContent.toString()}\n\`\`\`\n`, 35 | referenceData: { 36 | 'selection': { 37 | 'start': { 38 | 'line': startLineNumber, 39 | 'character': 0 40 | }, 41 | 'end': { 42 | 'line': endLineNumber, 43 | 'character': 0 44 | } 45 | }, 46 | 'editor': editor.document.uri.toString(), 47 | }, startLineNumber, endLineNumber, fileName 48 | }), 49 | 50 | }); 51 | } 52 | 53 | /** 54 | * Extracts the extension from a given filename. 55 | * 56 | * @param filename - The name of the file from which to extract the extension. 57 | * @returns The file extension without the dot, or an empty string if no extension is found. 58 | */ 59 | function extractFileExtension(filename: string): string { 60 | // Split the filename by dots 61 | const parts = filename.split('.'); 62 | 63 | // If there are no dots or the last part is empty, return an empty string 64 | if (parts.length <= 1 || parts[parts.length - 1] === '') { 65 | return ''; 66 | } 67 | 68 | // Return the last part as the extension 69 | return parts[parts.length - 1]; 70 | } -------------------------------------------------------------------------------- /vscode/src/utilities/api-communicator.ts: -------------------------------------------------------------------------------- 1 | import axios, { AxiosResponse } from 'axios'; 2 | import * as vscode from 'vscode'; 3 | import * as path from 'path'; 4 | 5 | export async function getWelltestedKey(): Promise { 6 | if (vscode.workspace.workspaceFolders === undefined) { 7 | vscode.window.showErrorMessage(' No active workspace found'); 8 | throw new Error("No active workspace found"); 9 | } 10 | const envPath = path.join(vscode.workspace.workspaceFolders[0].uri.fsPath, '.env'); 11 | const dotenv = require('dotenv'); 12 | const env = dotenv.config({ path: envPath }); 13 | const WELLTESTED_API = env.parsed?.WELLTESTED_API; 14 | if (!WELLTESTED_API) { 15 | throw new Error("No WELLTESTED_API found in .env file"); 16 | } 17 | return WELLTESTED_API; 18 | } 19 | 20 | export class APICommunicator { 21 | private apiUrl: string; 22 | 23 | constructor() { 24 | this.apiUrl = 'http://api.welltested.ai'; 25 | } 26 | 27 | async post(url: string, data: Record): Promise { 28 | try { 29 | const apiKey = await getWelltestedKey(); 30 | const response: AxiosResponse = await axios.post(`${this.apiUrl}${url}`, data, { 31 | headers: { 32 | 'apikey': `${apiKey}`, 33 | }, 34 | }); 35 | return response.data; 36 | } catch (error) { 37 | console.error('Error in POST request:', error); 38 | return null; 39 | } 40 | } 41 | 42 | async get(url: string): Promise { 43 | try { 44 | const apiKey = getWelltestedKey(); 45 | const response: AxiosResponse = await axios.get(`${this.apiUrl}${url}`, { 46 | headers: { 47 | 'apikey': `Bearer ${apiKey}`, 48 | }, 49 | }); 50 | return response.data; 51 | } catch (error) { 52 | console.error('Error in GET request:', error); 53 | vscode.window.showErrorMessage('Error connecting to Welltested API.'); 54 | return null; 55 | } 56 | } 57 | } 58 | 59 | 60 | export class UnauthorizedException extends Error { 61 | constructor() { 62 | super(); 63 | this.name = 'UnauthorizedException'; 64 | } 65 | } -------------------------------------------------------------------------------- /vscode/src/utilities/auth/auth.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import { CacheManager } from '../cache-manager'; 3 | import { makeHttpRequest } from '../../repository/http-utils'; 4 | 5 | export class Auth { 6 | private constructor() { } 7 | 8 | private static instance: Auth; 9 | 10 | private cacheManager = CacheManager.getInstance(); 11 | 12 | public static getInstance(): Auth { 13 | if (!Auth.instance) { 14 | Auth.instance = new Auth(); 15 | } 16 | 17 | return Auth.instance; 18 | } 19 | 20 | public getApiKey(): string | undefined { 21 | const config = vscode.workspace.getConfiguration('fluttergpt'); 22 | const apiKey = config.get('apiKey'); 23 | if (apiKey?.startsWith('sk-')) { // Don't account the old API Keys 24 | return; 25 | } 26 | return apiKey; 27 | } 28 | 29 | public async setApiKey(apiKey: string): Promise { 30 | return vscode.workspace.getConfiguration().update("fluttergpt.apiKey", apiKey, vscode.ConfigurationTarget.Global); 31 | } 32 | 33 | public getGithubRefreshToken(): string | undefined { 34 | return this.cacheManager.getGlobalValue('refresh_token'); 35 | } 36 | 37 | public getGithubAccessToken(): string | undefined { 38 | return this.cacheManager.getGlobalValue('access_token'); 39 | } 40 | 41 | public async signInWithGithub(context: vscode.ExtensionContext): Promise { 42 | const url = '/account/github/url/' + vscode.env.uriScheme; 43 | const { github_oauth_url } = await makeHttpRequest<{ github_oauth_url: string }>({ url: url }); 44 | vscode.env.openExternal(vscode.Uri.parse(github_oauth_url)); 45 | 46 | 47 | // Create a promise to handle the authentication callback 48 | const authPromise = new Promise<{ accessToken: string; refreshToken: string }>( 49 | (resolve, reject) => { 50 | context.subscriptions.push( 51 | vscode.window.registerUriHandler({ 52 | handleUri(uri: vscode.Uri): vscode.ProviderResult { 53 | if (uri.path === '/login-success') { 54 | const query = uri.query.split('&'); 55 | const accessToken = query[0].split('=')[1]; 56 | const refreshToken = query[1].split('=')[1]; 57 | resolve({ accessToken, refreshToken }); 58 | } else { 59 | reject(new Error('Authentication Failed')); 60 | } 61 | }, 62 | }) 63 | ); 64 | } 65 | ); 66 | 67 | // Wait for the promise to resolve and update the global state with the access and refresh tokens 68 | const { accessToken, refreshToken } = await authPromise; 69 | await context.globalState.update('access_token', accessToken); 70 | await context.globalState.update('refresh_token', refreshToken); 71 | return refreshToken; 72 | } 73 | 74 | public async signOutFromGithub(context: vscode.ExtensionContext): Promise { 75 | // Remove the access and refresh tokens from the global state 76 | await context.globalState.update('access_token', undefined); 77 | await context.globalState.update('refresh_token', undefined); 78 | 79 | // Additional cleanup code if needed 80 | // For example, you might want to unregister the URI handler 81 | // context.subscriptions.forEach((subscription) => { 82 | // subscription.dispose(); 83 | // }); 84 | } 85 | } -------------------------------------------------------------------------------- /vscode/src/utilities/cache-manager.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import { logError } from './telemetry-reporter'; 3 | // import { ContentEmbedding } from '@google/generative-ai'; 4 | import * as path from 'path'; 5 | import { computeCodehash } from '../shared/utils'; 6 | export class CacheManager { 7 | private static instance: CacheManager; 8 | private globalState: vscode.Memento; 9 | private workspaceState: vscode.Memento; 10 | 11 | private constructor(globalState: vscode.Memento, workspaceState: vscode.Memento) { 12 | this.globalState = globalState; 13 | this.workspaceState = workspaceState; 14 | } 15 | 16 | public static getInstance(globalState?: vscode.Memento, workspaceState?: vscode.Memento): CacheManager { 17 | if (!CacheManager.instance) { 18 | if (globalState && workspaceState) { 19 | CacheManager.instance = new CacheManager(globalState, workspaceState); 20 | } else { 21 | throw new Error('CacheManager not initialized. Call getInstance with Mementos first.'); 22 | } 23 | } 24 | return CacheManager.instance; 25 | } 26 | 27 | public getGlobalValue(key: string): T | undefined { 28 | return this.globalState.get(key); 29 | } 30 | 31 | public async setGlobalValue(key: string, value: T): Promise { 32 | await this.globalState.update(key, value); 33 | } 34 | 35 | private getWorkspaceValue(key: string): T | undefined { 36 | return this.workspaceState.get(key); 37 | } 38 | 39 | private async setWorkspaceValue(key: string, value: T): Promise { 40 | await this.workspaceState.update(key, value); 41 | } 42 | 43 | async incrementInlineCompletionCount() { 44 | try { 45 | let currentCount: number = this.getGlobalValue("inline-count") ?? 0; 46 | currentCount++; 47 | await this.setGlobalValue("inline-count", currentCount); 48 | } catch (error) { 49 | logError('incrementInlineCompletionCount', error); 50 | console.log("Failed updating cache for FlutterGpt!!"); 51 | } 52 | } 53 | 54 | public getInlineCompletionCount(): number { 55 | try { 56 | return this.getGlobalValue("inline-count") ?? 0; 57 | } catch (error) { 58 | logError('getInlineCompletionCount', error); 59 | console.log("Failed updating cache for FlutterGpt!!"); 60 | return 0; 61 | } 62 | } 63 | 64 | async setGeminiCache(cacheData: { [filePath: string]: { codehash: string } }): Promise { 65 | const excludePatterns = "**/{android,ios,web,linux,macos,windows,.dart_tool}/**"; 66 | const pubspecs = await vscode.workspace.findFiles("**/pubspec.yaml", excludePatterns); 67 | if (pubspecs.length === 0) { 68 | throw new Error("No pubspec.yaml found in the workspace."); 69 | } 70 | // Get all the flutter projects in the workspace 71 | const flutterProjects = pubspecs.map((uri) => uri.fsPath); 72 | 73 | // ITERATE OVER ALL THE FILES IN THE CACHE 74 | // Find the flutter project for the file 75 | // Add the file to the cache of that flutter project 76 | for (const filePath in cacheData) { 77 | const parentProjectPath = this.findParentFlutterProject(filePath, flutterProjects); 78 | if (parentProjectPath) { 79 | const key = "gemini-cache-" + (parentProjectPath); 80 | var currentCache = this.getGlobalValue(key); 81 | if (currentCache) { 82 | var cache = JSON.parse(currentCache); 83 | } else { 84 | cache = {}; 85 | } 86 | cache[filePath] = cacheData[filePath]; 87 | await this.setGlobalValue(key, JSON.stringify(cache)); 88 | } 89 | } 90 | } 91 | 92 | async getGeminiCache(): Promise { 93 | const excludePatterns = "**/{android,ios,web,linux,macos,windows,.dart_tool}/**"; 94 | const pubspecs = await vscode.workspace.findFiles("**/pubspec.yaml", excludePatterns); 95 | if (pubspecs.length === 0) { 96 | throw new Error("No pubspec.yaml found in the workspace."); 97 | } 98 | 99 | // Get all the flutter projects in the workspace 100 | const flutterProjects = pubspecs.map((uri) => uri.fsPath); 101 | 102 | const activeCache: { [filePath: string]: { codehash: string } } = {}; 103 | // Return cache only for the parent flutter project of the current workspace 104 | for (const projectPath of flutterProjects) { 105 | const projectDir = path.dirname(projectPath); 106 | const key = "gemini-cache-" + (projectDir); 107 | // await this.setGlobalValue(key, "value"); 108 | const cacheString = await this.getGlobalValue(key); 109 | if (!cacheString) { 110 | continue; 111 | } 112 | const cache = JSON.parse(cacheString); 113 | // Add the cache for the project to the activeCache 114 | Object.assign(activeCache, cache); 115 | } 116 | 117 | return JSON.stringify(activeCache); 118 | } 119 | 120 | // Helper function to find parent Flutter project 121 | private findParentFlutterProject(filePath: string, flutterProjects: string[]) { 122 | let parentProjectPath = null; 123 | let maxCommonLength = -1; 124 | 125 | for (const projectPath of flutterProjects) { 126 | const projectDir = path.dirname(projectPath); 127 | 128 | // Check if the current projectDir is a prefix of the filePath 129 | if (filePath.startsWith(projectDir)) { 130 | const commonLength = projectDir.length; 131 | 132 | if (commonLength > maxCommonLength) { 133 | maxCommonLength = commonLength; 134 | parentProjectPath = projectDir; 135 | } 136 | } 137 | } 138 | 139 | return parentProjectPath; 140 | } 141 | } -------------------------------------------------------------------------------- /vscode/src/utilities/code-processing.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | 3 | 4 | class DartCodeNotFoundError extends Error { 5 | constructor(message?: string) { 6 | super(message); // (1) 7 | this.name = this.constructor.name; // (2) 8 | Error.captureStackTrace(this, this.constructor); // (3) 9 | } 10 | } 11 | 12 | export function filterSurroundingCode(orignalContent: string, codeCompletion: string, splitLineNumberStart: number, splitLineNumberEnd: number = splitLineNumberStart): string { 13 | const orginalContentLines = orignalContent.split('\n'); 14 | let codeCompletionLines = codeCompletion.split('\n'); 15 | 16 | const preInsertLines = orginalContentLines.slice(0, splitLineNumberStart); 17 | const afterInsertLines = orginalContentLines.slice(splitLineNumberEnd + 1); 18 | 19 | const codeCompletionStartLine = removeWhitespaces(codeCompletionLines[0]); 20 | for (let i = 0; i < preInsertLines.length; i++) { //5 21 | if (codeCompletionLines.length < preInsertLines.length - i) { 22 | continue; // surrounding line is out of code completion range. 23 | } 24 | //find the first line from the top of the document that matches the starting line of code completion. 25 | const existingLine = removeWhitespaces(preInsertLines[i]); 26 | if (codeCompletionStartLine === existingLine) { 27 | let fullMatch = true; 28 | // all the below lines in the document should also match with the code completion 29 | for (let j = 1; j < preInsertLines.length - i; j++) { 30 | const followingCodeCompletionLine = removeWhitespaces(codeCompletionLines[j]); 31 | const followingExistingLine = removeWhitespaces(preInsertLines[i + j]); 32 | if (followingCodeCompletionLine !== followingExistingLine) { 33 | fullMatch = false; 34 | break; 35 | } 36 | } 37 | if (fullMatch) { 38 | codeCompletionLines = codeCompletionLines.slice(preInsertLines.length - i); 39 | break; 40 | } 41 | } 42 | } 43 | 44 | // Cleanup logic for after lines 45 | if(codeCompletionLines.length>0){ //safe for all code completion lines removed in last step resulting into error in codeCompletionLines[codeCompletionLines.length - 1] 46 | const codeCompletionEndLine = removeWhitespaces(codeCompletionLines[codeCompletionLines.length - 1]); 47 | for (let i = afterInsertLines.length; i > 0; i--) { 48 | if (codeCompletionLines.length < i) { 49 | continue; // surrounding line is out of code completion range. 50 | } 51 | //find the last line of the doc that matches with the last line of code completion 52 | const existingLine = removeWhitespaces(afterInsertLines[i - 1]); 53 | if (codeCompletionEndLine === existingLine) { 54 | let fullMatch = true; 55 | // make sure all the lines from last line in doc to the line after cursor are available in code compleiton 56 | for (let j = 1; j < i; j++) { 57 | const previousCodeCompletionLine = removeWhitespaces(codeCompletionLines[codeCompletionLines.length - 1 - j]); 58 | const previousExistingLine = removeWhitespaces(afterInsertLines[i - 1 - j]); 59 | if (previousCodeCompletionLine !== previousExistingLine) { 60 | fullMatch = false; 61 | break; 62 | } 63 | } 64 | if (fullMatch) { 65 | codeCompletionLines = codeCompletionLines.slice(0, codeCompletionLines.length - i); 66 | break; 67 | } 68 | } 69 | } 70 | } 71 | 72 | // Join the cleaned up code completion lines with the original content lines 73 | const result = codeCompletionLines.join('\n'); 74 | return result; 75 | } 76 | 77 | function removeWhitespaces(line: string): string { 78 | return line.replace(/\s/g, ""); 79 | } 80 | 81 | 82 | export function extractDartCode(widgetCode: string, first: Boolean = true): string { 83 | const codeBlocksRegex = /```(dart)?([\s\S]*?)```/g; 84 | 85 | let dartCodes: string[] = []; 86 | let match: RegExpExecArray | null; 87 | while ((match = codeBlocksRegex.exec(widgetCode)) !== null) { 88 | let dartCode: string = match[2]; 89 | dartCodes.push(dartCode.trim()); // extracting and storing all dart code blocks 90 | } 91 | if (dartCodes.length === 0) { 92 | throw new DartCodeNotFoundError(`No Dart code recognized in response: ${widgetCode}`); 93 | } else if (first) { 94 | // Returns the first Dart code block 95 | return dartCodes[0]; 96 | } else { 97 | // Returns the last Dart code block 98 | return dartCodes[dartCodes.length - 1]; 99 | } 100 | } 101 | 102 | export function previewCode(dartCode: string): string { 103 | const maxLength = 100; 104 | if (dartCode.length <= maxLength) { 105 | return dartCode; 106 | } 107 | 108 | const startLength = 40; 109 | const middleLength = 20; 110 | const endLength = 40; 111 | const start = dartCode.slice(0, startLength); 112 | const middle = dartCode.slice(dartCode.length / 2 - middleLength / 2, dartCode.length / 2 + middleLength / 2); 113 | const end = dartCode.slice(-endLength); 114 | return start + '...' + middle + '...' + end; 115 | } 116 | 117 | export function extractExplanation(widgetCode: string): string { 118 | let explanation: string = widgetCode.split("```")[0] || widgetCode; 119 | return explanation; 120 | } 121 | 122 | export function extractReferenceTextFromEditor(referenceEditor: vscode.TextEditor): string { 123 | const selectedCode = referenceEditor.document.getText(); 124 | return selectedCode; 125 | } 126 | -------------------------------------------------------------------------------- /vscode/src/utilities/command-manager.ts: -------------------------------------------------------------------------------- 1 | /* commandManager.ts 2 | This file is responsible for registering commands for the FlutterGPT extension. 3 | Commands can be registered as VS Code commands, context menu items, or keyboard shortcuts. 4 | Each command is associated with a handler function that gets executed when the command is invoked. 5 | 6 | To register a new command: 7 | 1. Add a new entry to the `commands` array in the `initCommands` function. 8 | 2. Provide the `name` of the command, the `handler` function, and the `options` object. 9 | 3. The `options` object specifies whether the command is a regular command (`isCommand`), 10 | appears in the context menu (`isMenu`), or is triggered by a keyboard shortcut (`isShortcut`). 11 | 4. Use the `registerCommand` function to add the command to the VS Code context. 12 | This function also checks if the API key is valid before executing the handler. 13 | 14 | Example command registration: 15 | { 16 | name: 'fluttergpt.doSomething', 17 | handler: () => doSomethingFunction(), 18 | options: { isCommand: true, isMenu: true, isShortcut: false } 19 | } 20 | 21 | Note: The `handler` function can be an async function if needed. 22 | */ 23 | import * as vscode from 'vscode'; 24 | import { addToReference } from '../tools/reference/add_reference'; 25 | import { logEvent } from './telemetry-reporter'; 26 | import { FlutterGPTViewProvider } from '../providers/chat_view_provider'; // Adjust the import path accordingly 27 | import { Auth } from './auth/auth'; 28 | 29 | 30 | export function registerCommand( 31 | context: vscode.ExtensionContext, 32 | name: string, 33 | handler: (...args: any[]) => any, 34 | options: { isCommand: boolean; isMenu: boolean; isShortcut: boolean } 35 | ) { 36 | const { isCommand, isMenu, isShortcut } = options; 37 | 38 | let baseCommand = vscode.commands.registerCommand(name, async (...args: any[]) => { 39 | logEvent(name, { 'type': 'commands', 'isCommand': isCommand.toString(), 'isShortcut': isShortcut.toString(), 'isMenu': isMenu.toString() }); 40 | handler(...args); 41 | 42 | }); 43 | 44 | context.subscriptions.push(baseCommand); 45 | 46 | if (isMenu) { 47 | let menuCommand = vscode.commands.registerCommand(`${name}.menu`, async (...args: any[]) => { 48 | logEvent(name, { 'type': 'commands', 'isCommand': isCommand.toString(), 'isShortcut': isShortcut.toString(), 'isMenu': isMenu.toString() }); 49 | handler(...args); 50 | }); 51 | context.subscriptions.push(menuCommand); 52 | } 53 | } 54 | 55 | export function initCommands(context: vscode.ExtensionContext, flutterGPTViewProvider: FlutterGPTViewProvider) { 56 | const commands = [ 57 | { name: 'dash.attachToDash', handler: () => addToReference(context.globalState, flutterGPTViewProvider), options: { isCommand: true, isMenu: true, isShortcut: false } }, 58 | { name: 'dash.clearChat', handler: () => flutterGPTViewProvider?.postMessageToWebview({ type: 'clearCommandDeck' }), options: { isCommand: true, isMenu: false, isShortcut: false } }, 59 | { name: 'dash.marketPlace', handler: () => flutterGPTViewProvider.setMarketPlaceWebView(), options: { isCommand: true, isMenu: false, isShortcut: false } }, 60 | { name: 'dash.backButton', handler: () => flutterGPTViewProvider.setChatWebView(), options: { isCommand: true, isMenu: false, isShortcut: false } }, 61 | 62 | // Add more commands as needed. 63 | ]; 64 | 65 | // Register all commands. 66 | commands.forEach(cmd => registerCommand(context, cmd.name, cmd.handler, cmd.options)); 67 | } -------------------------------------------------------------------------------- /vscode/src/utilities/commanddash-integration/task.ts: -------------------------------------------------------------------------------- 1 | import { DartCLIClient } from "./dart-cli-client"; 2 | 3 | export class Task { 4 | private taskId: number; 5 | private dartClient: DartCLIClient; 6 | private handlers: Map void> = new Map(); 7 | 8 | constructor(dartClient: DartCLIClient, taskId: number) { 9 | this.dartClient = dartClient; 10 | this.taskId = taskId; 11 | } 12 | 13 | public onProcessStep(kind: string, handler: (message: any) => Promise) { 14 | const eventName = `step_${kind}_${this.taskId}`; 15 | this.handlers.set(eventName, handler); 16 | this.dartClient.eventEmitter.on(eventName, async (message) => { 17 | try { 18 | await handler(message); 19 | } catch (e) { 20 | // console.error(e); 21 | // Inform CLI that client was unable to provide requested data 22 | this.sendStepResponse(message, { 'message': `Step kind: ${message.params['kind']} failed with error ${e}` }); 23 | } 24 | }); 25 | } 26 | 27 | public sendStepResponse(message: any, response: any, error: boolean = false): any { 28 | this.dartClient.sendStepResponse(message.id, message.params['kind'], response, error); 29 | } 30 | 31 | public async run(params: any = {}): Promise { 32 | try { 33 | const result = await this.dartClient.processTask(this.taskId, params); 34 | // Task completed successfully 35 | this.dispose(); 36 | return result; 37 | } catch (error) { 38 | // Task encountered an error 39 | this.dispose(); 40 | throw error; 41 | } 42 | } 43 | 44 | private dispose() { 45 | // Remove all event listeners associated with this task 46 | this.handlers.forEach((handler, eventName) => { 47 | this.dartClient.eventEmitter.removeListener(eventName, handler); 48 | }); 49 | } 50 | 51 | public getTaskId(): number { 52 | return this.taskId; 53 | } 54 | } -------------------------------------------------------------------------------- /vscode/src/utilities/diff-utils.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import { tempScheme, virtualDocumentProvider } from './virtual-document-provider'; 3 | 4 | export async function handleDiffViewAndMerge( 5 | editor: vscode.TextEditor, 6 | originalCodeUri: vscode.Uri, 7 | orignalCode: string, 8 | optimizedCode: string, 9 | context: vscode.ExtensionContext, 10 | showMergeConfimation: boolean = true 11 | ): Promise { 12 | 13 | const posAtTime = editor.selection.active; 14 | 15 | // Create a temporary file with a .dart extension to show the diff 16 | const currentFileName = `${tempScheme}:current.dart`; 17 | const updateFileName = `${tempScheme}:updated.dart`; 18 | 19 | virtualDocumentProvider.addDocument(vscode.Uri.parse(currentFileName), orignalCode); 20 | virtualDocumentProvider.addDocument(vscode.Uri.parse(updateFileName), optimizedCode); 21 | 22 | let lhsUri = vscode.Uri.parse(currentFileName); 23 | let rhsUri = vscode.Uri.parse(updateFileName); 24 | 25 | // Open the diff view 26 | await vscode.commands.executeCommand( 27 | "vscode.diff", 28 | lhsUri, 29 | rhsUri, 30 | "Current Code ↔ Updated Code", 31 | ); 32 | if (showMergeConfimation) { 33 | // Ask user if they want to merge changes 34 | let userChoice = await vscode.window.showInformationMessage( 35 | 'Do you want to merge these changes?', 36 | 'Yes', 'No' 37 | ); 38 | 39 | if (!userChoice) { 40 | return; 41 | } 42 | 43 | let reopenEditor = async () => { 44 | let document = await vscode.workspace.openTextDocument(originalCodeUri); 45 | await vscode.window.showTextDocument(document, { 46 | viewColumn: editor.viewColumn, 47 | preserveFocus: false, 48 | selection: new vscode.Range(posAtTime, posAtTime) 49 | }); 50 | }; 51 | 52 | 53 | if (userChoice === 'Yes') { 54 | vscode.commands.executeCommand('workbench.action.closeActiveEditor'); // assuming apply edit time will be enough for the diff to close so user doesn't see a jank. 55 | // Apply the optimized code 56 | const workspaceEdit = new vscode.WorkspaceEdit(); 57 | const entireDocumentRange = new vscode.Range( 58 | editor.document.positionAt(0), 59 | editor.document.positionAt(editor.document.getText().length) 60 | ); 61 | workspaceEdit.replace(originalCodeUri, entireDocumentRange, optimizedCode); 62 | if (await vscode.workspace.applyEdit(workspaceEdit)) { 63 | await reopenEditor(); 64 | } 65 | } else { 66 | await vscode.commands.executeCommand('workbench.action.closeActiveEditor'); 67 | await reopenEditor(); 68 | } 69 | } 70 | 71 | // remove the temporary documents 72 | virtualDocumentProvider.removeDocument(vscode.Uri.parse(`${tempScheme}:current.dart`)); 73 | virtualDocumentProvider.removeDocument(vscode.Uri.parse(`${tempScheme}:updated.dart`)); 74 | } -------------------------------------------------------------------------------- /vscode/src/utilities/prompt_helpers.ts: -------------------------------------------------------------------------------- 1 | import { extractReferenceTextFromEditor } from "./code-processing"; 2 | import * as vscode from 'vscode'; 3 | 4 | export function appendReferences(referenceEditor: vscode.TextEditor | undefined, prompt: string): string { 5 | if (referenceEditor !== undefined) { 6 | const referenceText = extractReferenceTextFromEditor(referenceEditor); 7 | if (referenceText !== '') { 8 | prompt += `Here are user shared context/references: \n${referenceText}\n\n. Anaylze these well and use them to refactor the code.\n\n`; 9 | } 10 | } 11 | return prompt; 12 | } -------------------------------------------------------------------------------- /vscode/src/utilities/setup-manager/setup-manager.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import { DartCLIClient, deleteExecutable } from "../commanddash-integration/dart-cli-client"; 3 | import { Auth } from "../auth/auth"; 4 | import { refreshAccessToken } from '../../repository/http-utils'; 5 | 6 | export enum SetupStep { github, executable } 7 | 8 | export class SetupManager { 9 | public pendingSetupSteps: SetupStep[] = []; 10 | private auth = Auth.getInstance(); 11 | private dartClient: DartCLIClient | undefined; 12 | private context: vscode.ExtensionContext | undefined; 13 | private _onDidChangeSetup = new vscode.EventEmitter(); 14 | public onDidChangeSetup = this._onDidChangeSetup.event; 15 | private constructor() { } 16 | 17 | private static instance: SetupManager; 18 | 19 | public static getInstance(): SetupManager { 20 | if (!SetupManager.instance) { 21 | SetupManager.instance = new SetupManager(); 22 | } 23 | 24 | return SetupManager.instance; 25 | } 26 | 27 | public async init(context: vscode.ExtensionContext): Promise { 28 | this.context = context; 29 | if (!this.auth.getGithubAccessToken()) { 30 | this.pendingSetupSteps.push(SetupStep.github); 31 | } 32 | this.dartClient = DartCLIClient.init(this.context); 33 | this.dartClient.onGlobalError((error) => { 34 | 35 | vscode.window.showInformationMessage('Error processing an open task. Please consider closing existing tasks or restart IDE if there is trouble using CommandDash', { 36 | detail: error 37 | }); 38 | console.log(error); 39 | }); 40 | this.dartClient.onProcessOperation('refresh_access_token', async (message) => { 41 | let refreshToken = this.auth.getGithubRefreshToken(); 42 | if (refreshToken) { 43 | let accessToken = await refreshAccessToken(refreshToken, context); 44 | this.dartClient?.sendOperationResponse(message, { 45 | 'access_token': accessToken 46 | }); 47 | } else { 48 | throw Error('No refresh token available.'); 49 | } 50 | }); 51 | 52 | if (!this.dartClient.executableExists()) { 53 | this.pendingSetupSteps.push(SetupStep.executable); 54 | } else { 55 | this.dartClient.connect(); 56 | try { 57 | this.dartClient.backgroundUpdateExecutable(); 58 | } catch (error) { 59 | console.log(`Error: ${error}`); 60 | } 61 | } 62 | } 63 | 64 | public async updatePendingSteps() { 65 | 66 | if (!this.auth.getGithubAccessToken()) { 67 | this.pendingSetupSteps.push(SetupStep.github); 68 | } 69 | if (this.dartClient && !this.dartClient.executableExists()) { 70 | this.pendingSetupSteps.push(SetupStep.executable); 71 | } 72 | if (this.auth.getGithubAccessToken() && (this.dartClient && this.dartClient.executableExists())) { 73 | this.pendingSetupSteps.length = 0; 74 | } 75 | } 76 | 77 | public async setupGithub() { 78 | await this.auth.signInWithGithub(this.context!); 79 | this._onDidChangeSetup.fire(SetupStep.github); 80 | } 81 | 82 | public async setupExecutable(onProgress: (progress: number) => void) { 83 | await this.dartClient!.installExecutable(onProgress); 84 | this._onDidChangeSetup.fire(SetupStep.executable); 85 | this.dartClient!.connect(); 86 | } 87 | 88 | public async deleteExecutable() { 89 | return this.dartClient?.deleteExecutable(); 90 | } 91 | 92 | public async deleteGithub() { 93 | return this.auth.signOutFromGithub(this.context!); 94 | } 95 | } -------------------------------------------------------------------------------- /vscode/src/utilities/shortcut-hint-utils.ts: -------------------------------------------------------------------------------- 1 | import * as os from 'os'; 2 | 3 | export function shortcutInlineCodeGeneration(minified: boolean = false): string{ 4 | const platform = os.platform(); 5 | let stringRepresentation; 6 | 7 | if (platform === 'win32' || platform === 'linux') { 8 | stringRepresentation = minified? 'ctrl+shift+→' : '(ctrl) + (shift) + (→)'; 9 | } else { 10 | stringRepresentation = minified? '⌘+shift+→' : '(⌘) + (shift) + (→)'; 11 | } 12 | return stringRepresentation; 13 | } 14 | 15 | export function shortcutInlineCodeRefactor(minified: boolean = false): string{ 16 | const platform = os.platform(); 17 | let stringRepresentation; 18 | 19 | if (platform === 'win32' || platform === 'linux') { 20 | stringRepresentation = minified? 'ctrl+r' : '(ctrl) + (R)'; 21 | } else { 22 | stringRepresentation = minified? '⌘+r' : '(⌘) + (R)'; 23 | } 24 | return stringRepresentation; 25 | } 26 | -------------------------------------------------------------------------------- /vscode/src/utilities/state-objects.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | 3 | // Retrieve the reference editor from the global state 4 | export function getReferenceEditor(globalState: vscode.Memento): vscode.TextEditor | undefined { 5 | let referenceEditor: vscode.TextEditor | undefined; 6 | const referenceEditorId = globalState.get('referenceEditorId'); 7 | if (referenceEditorId) { 8 | referenceEditor = vscode.window.visibleTextEditors.find( 9 | (editor) => editor.document.uri.toString() === referenceEditorId 10 | ); 11 | } 12 | return referenceEditor; 13 | } -------------------------------------------------------------------------------- /vscode/src/utilities/storage-manager.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | 3 | export class StorageManager { 4 | private static _instance: StorageManager; 5 | private _context: vscode.ExtensionContext | undefined; 6 | agentsSecretStoreKey: string = "commanddash.agents"; 7 | 8 | public static get instance(): StorageManager { 9 | if (!this._instance) { 10 | this._instance = new StorageManager(); 11 | } 12 | return this._instance; 13 | } 14 | 15 | public loadContext(context: vscode.ExtensionContext) { 16 | this._context = context; 17 | } 18 | 19 | public async setInstallAgents(agents: any): Promise { 20 | if (!this._context) { 21 | throw new Error("Context is undefined"); 22 | } 23 | 24 | try { 25 | await this._context.secrets.store(this.agentsSecretStoreKey, JSON.stringify(agents)); 26 | return true; 27 | 28 | } catch (error) { 29 | console.log('Error while storing install agents:', error); 30 | return false; 31 | } 32 | } 33 | 34 | public async getInstallAgents(): Promise { 35 | if(!this._context){ 36 | throw new Error("Context is undefined"); 37 | 38 | } 39 | const installAgents = await this._context.secrets.get(this.agentsSecretStoreKey); 40 | 41 | return installAgents || undefined; 42 | } 43 | 44 | public async deleteAgents(): Promise { 45 | if(!this._context){ 46 | throw new Error("Context is undefined"); 47 | } 48 | return await this._context.secrets.delete(this.agentsSecretStoreKey); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /vscode/src/utilities/telemetry-reporter.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import TelemetryReporter from '@vscode/extension-telemetry'; 3 | import { log } from 'console'; 4 | 5 | // the application insights key (also known as instrumentation key) 6 | const key = 'ceae95d5-839b-4691-8b42-ad54f8095b6d'; 7 | 8 | // telemetry reporter 9 | let reporter: TelemetryReporter; 10 | 11 | export function activateTelemetry(context: vscode.ExtensionContext) { 12 | 13 | if (key===undefined) {return null;} 14 | // create telemetry reporter on extension activation 15 | reporter = new TelemetryReporter(key); 16 | // ensure it gets properly disposed. Upon disposal the events will be flushed 17 | context.subscriptions.push(reporter); 18 | } 19 | 20 | export function logEvent(eventName: string, properties?: { [key: string]: string; }, measures?: { [key: string]: number; }){ 21 | reporter.sendTelemetryEvent(eventName, properties, measures); 22 | } 23 | 24 | export function logError(eventName: string, error: Error | unknown){ 25 | if (error instanceof Error) { 26 | reporter.sendTelemetryErrorEvent(eventName, { 27 | 'name': error.name, 28 | 'message': error.message, 29 | 'stack': `${error.stack}` 30 | }); 31 | } else { 32 | reporter.sendTelemetryErrorEvent(eventName, { 33 | 'error': `${error}` 34 | }); 35 | } 36 | } -------------------------------------------------------------------------------- /vscode/src/utilities/update-check.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/naming-convention */ 2 | import { extensions } from "vscode"; 3 | import * as path from "path"; 4 | import * as vscode from "vscode"; 5 | import * as fs from "fs"; 6 | import { promises as fsPromises } from 'fs'; 7 | import { logEvent } from "./telemetry-reporter"; 8 | 9 | export class ExtensionVersionManager { 10 | 11 | readonly context: vscode.ExtensionContext; 12 | user_config_file_path: vscode.Uri; 13 | constructor(context: vscode.ExtensionContext) { 14 | this.context = context; 15 | this.user_config_file_path = vscode.Uri.file( 16 | path.join(this.context.extensionPath, "user_config.json") 17 | ); 18 | } 19 | 20 | public static getExtensionVersion(): string { 21 | const extension = extensions.getExtension("WelltestedAI.fluttergpt"); 22 | return extension?.packageJSON.version ?? "0.4.0"; // TODO: Try to always keep this updated as a fallback 23 | } 24 | 25 | public getVersionFromUserConfigFile(): string { 26 | // read from user_config.json file if exists and return version 27 | 28 | // if file does not exist, return 0.0.0 29 | if (!fs.existsSync(this.user_config_file_path.fsPath)) { 30 | return "0.0.0"; 31 | } 32 | try { 33 | // read file and return version 34 | const user_config_file = fs.readFileSync( 35 | this.user_config_file_path.fsPath, 36 | "utf8" 37 | ); 38 | const user_config = JSON.parse(user_config_file); 39 | return user_config.version; 40 | } catch (error) { 41 | console.error(error); 42 | return "0.0.0"; 43 | } 44 | } 45 | 46 | 47 | public async isExtensionUpdated() { 48 | const currentVersion = ExtensionVersionManager.getExtensionVersion(); 49 | const previousVersion = this.getVersionFromUserConfigFile(); 50 | if (currentVersion !== previousVersion) { 51 | // first update packageJSON 52 | const newConfig = { 53 | version: currentVersion, 54 | }; 55 | // then write to file 56 | const path = this.user_config_file_path.fsPath; 57 | // create if not exists 58 | if (!fs.existsSync(path)) { 59 | await fsPromises.writeFile(path, '',); 60 | } 61 | 62 | 63 | fs.writeFile(path, JSON.stringify(newConfig), (err) => { 64 | if (err) { 65 | console.error(err); 66 | return; 67 | } 68 | }); 69 | logEvent('extension-updated', { previousVersion: previousVersion, currentVersion: currentVersion }); 70 | // show message 71 | vscode.window.showInformationMessage( 72 | `FlutterGPT updated checkout the new features` 73 | ); 74 | 75 | } 76 | } 77 | } 78 | 79 | -------------------------------------------------------------------------------- /vscode/src/utilities/update-manager.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import urlMetadata = require('url-metadata'); 3 | 4 | 5 | export class UpdateManager { 6 | readonly context: vscode.ExtensionContext; 7 | 8 | constructor(context: vscode.ExtensionContext) { 9 | this.context = context; 10 | } 11 | 12 | // function to check for update 13 | public async checkForUpdate(): Promise { 14 | 15 | const lastestVersion = await this.getLatestVersion(); 16 | 17 | // in case of failure to obtain latest version, stop further execution 18 | if (!lastestVersion) { 19 | return; 20 | } 21 | 22 | const currentVersion = this.context.extension.packageJSON.version as string; 23 | 24 | // [Warning]this logic is broken. lexical versions can't be compared like this 25 | if (this.convertVersionStringToInt(lastestVersion) > this.convertVersionStringToInt(currentVersion)) { 26 | const selection = await vscode.window.showInformationMessage( 27 | `A new version (${lastestVersion}) of FlutterGPT is available. Update now for the latest features and improvements.`, 28 | 'Update' 29 | ); 30 | 31 | if (selection === 'Update') { 32 | vscode.commands.executeCommand('extension.open', this.context.extension.id); 33 | } 34 | } 35 | 36 | } 37 | 38 | // obtaining latest version of release by web scrapping 39 | private async getLatestVersion(): Promise { 40 | let version: string | undefined; 41 | try { 42 | const metadata = await urlMetadata( 43 | 'https://marketplace.visualstudio.com/items?itemName=WelltestedAI.fluttergpt', 44 | { 45 | mode: 'same-origin', 46 | } 47 | ); 48 | 49 | // obtaining the version from meta-data of vscode market place url from the hosted image endpoint 50 | let extractedVersion: string = metadata['og:image'].toString().split('fluttergpt/')[1].split('/')[0]; 51 | 52 | // console.log(extractedVersion); 53 | 54 | // validate the version pattern 55 | // accepted format -> X.X.X 56 | if (extractedVersion.match(/\d{1,}\.\d{1,}\.\d{1,}/)) { 57 | version = extractedVersion; 58 | } 59 | } catch (err) { 60 | console.log('version fetch error:', err); 61 | } 62 | // version will be undefined either in case of network failure or version pattern match failure 63 | return version; 64 | } 65 | 66 | //converts version string to number 67 | private convertVersionStringToInt(version: string): number { 68 | return Number.parseInt(version.replace(/\./g, ''), 10); 69 | } 70 | } -------------------------------------------------------------------------------- /vscode/src/utilities/virtual-document-provider.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | 3 | export const tempScheme = 'temp-files'; 4 | 5 | // insipred from https://github.com/ryu1kn/vscode-partial-diff/issues/2 6 | // Full Documentation: https://code.visualstudio.com/api/extension-guides/virtual-documents 7 | export const virtualDocumentProvider = new class VirtalDocumentProvider implements vscode.TextDocumentContentProvider{ 8 | private _onDidChange = new vscode.EventEmitter(); 9 | onDidChange = this._onDidChange.event; 10 | private _documents = new Map(); 11 | 12 | addDocument(uri: vscode.Uri, doc: string) { 13 | this._documents.set(uri.toString(), doc); 14 | this._onDidChange.fire(uri); // Notify VS Code that the document has changed (when streaming responses) 15 | } 16 | 17 | removeDocument(uri: vscode.Uri) { 18 | this._documents.delete(uri.toString()); 19 | } 20 | 21 | provideTextDocumentContent(uri: vscode.Uri, token: vscode.CancellationToken): vscode.ProviderResult { 22 | 23 | const document = this._documents.get(uri.toString()); 24 | if (document) { 25 | return document; 26 | } 27 | throw new Error('No Document Found Error'); 28 | } 29 | }; 30 | 31 | -------------------------------------------------------------------------------- /vscode/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: ["./media/**/*.{html,js}"], 4 | theme: { 5 | extend: {}, 6 | }, 7 | plugins: [], 8 | } -------------------------------------------------------------------------------- /vscode/target/npmlist.json: -------------------------------------------------------------------------------- 1 | {"version":"0.0.7","name":"fluttergpt","dependencies":{"axios":{"version":"1.4.0"},"dotenv":{"version":"16.0.3"}}} -------------------------------------------------------------------------------- /vscode/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "ES2020", 5 | "outDir": "out", 6 | "lib": [ 7 | "ES2020" 8 | ], 9 | "sourceMap": true, 10 | "rootDir": "src", 11 | "strict": true /* enable all strict type-checking options */ 12 | /* Additional Checks */ 13 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 14 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 15 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /vscode/vsc-extension-quickstart.md: -------------------------------------------------------------------------------- 1 | # Welcome to your VS Code Extension 2 | 3 | ## What's in the folder 4 | 5 | * This folder contains all of the files necessary for your extension. 6 | * `package.json` - this is the manifest file in which you declare your extension and command. 7 | * The sample plugin registers a command and defines its title and command name. With this information VS Code can show the command in the command palette. It doesn’t yet need to load the plugin. 8 | * `src/extension.ts` - this is the main file where you will provide the implementation of your command. 9 | * The file exports one function, `activate`, which is called the very first time your extension is activated (in this case by executing the command). Inside the `activate` function we call `registerCommand`. 10 | * We pass the function containing the implementation of the command as the second parameter to `registerCommand`. 11 | 12 | ## Get up and running straight away 13 | 14 | * Press `F5` to open a new window with your extension loaded. 15 | * Run your command from the command palette by pressing (`Ctrl+Shift+P` or `Cmd+Shift+P` on Mac) and typing `Hello World`. 16 | * Set breakpoints in your code inside `src/extension.ts` to debug your extension. 17 | * Find output from your extension in the debug console. 18 | 19 | ## Make changes 20 | 21 | * You can relaunch the extension from the debug toolbar after changing code in `src/extension.ts`. 22 | * You can also reload (`Ctrl+R` or `Cmd+R` on Mac) the VS Code window with your extension to load your changes. 23 | 24 | ## Explore the API 25 | 26 | * You can open the full set of our API when you open the file `node_modules/@types/vscode/index.d.ts`. 27 | 28 | ## Run tests 29 | 30 | * Open the debug viewlet (`Ctrl+Shift+D` or `Cmd+Shift+D` on Mac) and from the launch configuration dropdown pick `Extension Tests`. 31 | * Press `F5` to run the tests in a new window with your extension loaded. 32 | * See the output of the test result in the debug console. 33 | * Make changes to `src/test/suite/extension.test.ts` or create new test files inside the `test/suite` folder. 34 | * The provided test runner will only consider files matching the name pattern `**.test.ts`. 35 | * You can create folders inside the `test` folder to structure your tests any way you want. 36 | 37 | ## Go further 38 | 39 | * [Follow UX guidelines](https://code.visualstudio.com/api/ux-guidelines/overview) to create extensions that seamlessly integrate with VS Code's native interface and patterns. 40 | * Reduce the extension size and improve the startup time by [bundling your extension](https://code.visualstudio.com/api/working-with-extensions/bundling-extension). 41 | * [Publish your extension](https://code.visualstudio.com/api/working-with-extensions/publishing-extension) on the VS Code extension marketplace. 42 | * Automate builds by setting up [Continuous Integration](https://code.visualstudio.com/api/working-with-extensions/continuous-integration). 43 | -------------------------------------------------------------------------------- /web/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | # Output 4 | .output 5 | .vercel 6 | /.svelte-kit 7 | /build 8 | 9 | # OS 10 | .DS_Store 11 | Thumbs.db 12 | 13 | # Env 14 | .env 15 | .env.* 16 | !.env.example 17 | !.env.test 18 | 19 | # Vite 20 | vite.config.js.timestamp-* 21 | vite.config.ts.timestamp-* 22 | 23 | package-lock.json -------------------------------------------------------------------------------- /web/.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true 2 | -------------------------------------------------------------------------------- /web/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [{ 7 | "type": "chrome", 8 | "request": "launch", 9 | "name": "Launch Chrome against localhost", 10 | "url": "http://localhost:5173", 11 | "webRoot": "${workspaceFolder}/src", 12 | "breakOnLoad": true, 13 | "sourceMaps": true, 14 | "sourceMapPathOverrides": { 15 | "webpack:///src/*": "${webRoot}/*" 16 | } 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /web/README.md: -------------------------------------------------------------------------------- 1 | # create-svelte 2 | 3 | Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/main/packages/create-svelte). 4 | 5 | ## Creating a project 6 | 7 | If you're seeing this, you've probably already done this step. Congrats! 8 | 9 | ```bash 10 | # create a new project in the current directory 11 | npm create svelte@latest 12 | 13 | # create a new project in my-app 14 | npm create svelte@latest my-app 15 | ``` 16 | 17 | ## Developing 18 | 19 | Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server: 20 | 21 | ```bash 22 | npm run dev 23 | 24 | # or start the server and open the app in a new browser tab 25 | npm run dev -- --open 26 | ``` 27 | 28 | ## Building 29 | 30 | To create a production version of your app: 31 | 32 | ```bash 33 | npm run build 34 | ``` 35 | 36 | You can preview the production build with `npm run preview`. 37 | 38 | > To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment. 39 | -------------------------------------------------------------------------------- /web/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "commanddash-web-app", 3 | "version": "0.0.1", 4 | "private": true, 5 | "engines": { 6 | "node": ">=18.13.0" 7 | }, 8 | "scripts": { 9 | "dev": "vite dev", 10 | "build": "vite build", 11 | "preview": "vite preview", 12 | "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", 13 | "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", 14 | "start": "node build/index.js" 15 | }, 16 | "devDependencies": { 17 | "@iconify-json/carbon": "^1.1.36", 18 | "@iconify/svelte": "^4.0.2", 19 | "@sveltejs/adapter-auto": "^3.0.0", 20 | "@sveltejs/adapter-node": "^5.2.0", 21 | "@sveltejs/kit": "^2.0.0", 22 | "@sveltejs/vite-plugin-svelte": "^3.0.0", 23 | "@types/showdown": "^2.0.6", 24 | "autoprefixer": "^10.4.19", 25 | "postcss": "^8.4.39", 26 | "svelte": "^4.2.7", 27 | "svelte-adapter-azure-swa": "^0.20.0", 28 | "svelte-check": "^3.6.0", 29 | "tailwindcss": "^3.4.4", 30 | "tslib": "^2.4.1", 31 | "typescript": "^5.0.0", 32 | "unplugin-icons": "^0.19.0", 33 | "vite": "^5.0.3" 34 | }, 35 | "type": "module", 36 | "dependencies": { 37 | "@lottiefiles/svelte-lottie-player": "^0.3.1", 38 | "@microsoft/applicationinsights-web": "^3.3.1", 39 | "@tailwindcss/typography": "^0.5.13", 40 | "cheerio": "^1.0.0", 41 | "dotenv": "^16.4.5", 42 | "highlight.js": "^11.10.0", 43 | "isomorphic-dompurify": "^2.14.0", 44 | "showdown": "^2.1.0", 45 | "tailwind-scrollbar": "^3.1.0" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /web/postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /web/src/app.d.ts: -------------------------------------------------------------------------------- 1 | // See https://kit.svelte.dev/docs/types#app 2 | // for information about these interfaces 3 | declare global { 4 | namespace App { 5 | interface Error { 6 | message: string; 7 | errorId?: ReturnType; 8 | } 9 | // interface Locals {} 10 | // interface PageData {} 11 | // interface PageState {} 12 | // interface Platform {} 13 | } 14 | } 15 | 16 | export {}; 17 | -------------------------------------------------------------------------------- /web/src/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | %sveltekit.head% 8 | 9 | 10 |
%sveltekit.body%
11 | 12 | 13 | -------------------------------------------------------------------------------- /web/src/lib/actions/clickOutside.ts: -------------------------------------------------------------------------------- 1 | export function clickOutside(element: HTMLElement, callbackFunction: () => void) { 2 | function onClick(event: MouseEvent) { 3 | if (!element.contains(event.target as Node)) { 4 | callbackFunction(); 5 | } 6 | } 7 | 8 | document.body.addEventListener("click", onClick); 9 | 10 | return { 11 | update(newCallbackFunction: () => void) { 12 | callbackFunction = newCallbackFunction; 13 | }, 14 | destroy() { 15 | document.body.removeEventListener("click", onClick); 16 | }, 17 | }; 18 | } 19 | -------------------------------------------------------------------------------- /web/src/lib/components/ExpandNavigation.svelte: -------------------------------------------------------------------------------- 1 | 8 | 9 | 19 | -------------------------------------------------------------------------------- /web/src/lib/components/LoadingPage.svelte: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | 9 | 112 | -------------------------------------------------------------------------------- /web/src/lib/components/MobileNav.svelte: -------------------------------------------------------------------------------- 1 | 32 | 33 | 47 | 63 | 64 | -------------------------------------------------------------------------------- /web/src/lib/components/NavConversationItem.svelte: -------------------------------------------------------------------------------- 1 | Task -------------------------------------------------------------------------------- /web/src/lib/components/NavMenu.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | 18 | 19 |
22 | 28 |
29 | 67 | -------------------------------------------------------------------------------- /web/src/lib/components/Toast.svelte: -------------------------------------------------------------------------------- 1 | 15 | 16 |
20 |
23 | {#if ToastType.SUCCESS === toastType} 24 | 25 | {:else if ToastType.INFO === toastType} 26 | 27 | {:else if ToastType.ERROR === toastType} 28 | 29 | {/if} 30 |

{message}

31 |
32 |
33 | -------------------------------------------------------------------------------- /web/src/lib/components/chat/ChatInput.svelte: -------------------------------------------------------------------------------- 1 | 35 | 36 |
37 | 41 | 42 |