├── .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 | [](https://marketplace.visualstudio.com/items?itemName=WelltestedAI.fluttergpt&ssr=false#overview) [](/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 |
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 | [](https://marketplace.visualstudio.com/items?itemName=WelltestedAI.fluttergpt&ssr=false#overview) [](https://marketplace.visualstudio.com/items?itemName=WelltestedAI.fluttergpt&ssr=false#overview) [](/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 |
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 |
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 |
13 |
15 |
16 |
17 |
18 |
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 |
13 | {#if isCollapsed}
14 |
15 | {:else}
16 |
17 | {/if}
18 |
19 |
--------------------------------------------------------------------------------
/web/src/lib/components/LoadingPage.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
112 |
--------------------------------------------------------------------------------
/web/src/lib/components/MobileNav.svelte:
--------------------------------------------------------------------------------
1 |
32 |
33 |
36 | dispatch("toggle", true)}
40 | aria-label="Open menu"
41 | bind:this={openEl}>
43 | {title}
44 |
46 |
47 |
52 |
53 | dispatch("toggle", false)}
57 | aria-label="Close menu"
58 | bind:this={closeEl}>
60 |
61 |
62 |
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 |
{(value || " ") + "\n"}
41 |
42 |
55 |
56 |
57 |
65 |
--------------------------------------------------------------------------------
/web/src/lib/components/icons/IconDazzled.svelte:
--------------------------------------------------------------------------------
1 |
4 |
5 |
13 |
17 |
23 |
24 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/web/src/lib/components/icons/IconInternet.svelte:
--------------------------------------------------------------------------------
1 |
4 |
5 |
17 |
29 |
--------------------------------------------------------------------------------
/web/src/lib/components/icons/IconNew.svelte:
--------------------------------------------------------------------------------
1 |
4 |
5 |
19 |
--------------------------------------------------------------------------------
/web/src/lib/index.ts:
--------------------------------------------------------------------------------
1 | // place files you want to import through the `$lib` alias in this folder.
2 |
--------------------------------------------------------------------------------
/web/src/lib/stores/QuestionnaireStores.ts:
--------------------------------------------------------------------------------
1 | import type { Questionnaire } from "$lib/types/Questionnaires";
2 | import { writable } from "svelte/store";
3 |
4 | export const questionnaireStore = writable();
--------------------------------------------------------------------------------
/web/src/lib/stores/ToastStores.ts:
--------------------------------------------------------------------------------
1 | import type { ToastType } from "$lib/types/Toast";
2 | import { writable } from "svelte/store";
3 |
4 | interface Toast {
5 | message: string;
6 | type: ToastType
7 | }
8 |
9 | export const toastStore = writable(null);
10 |
--------------------------------------------------------------------------------
/web/src/lib/types/Agent.ts:
--------------------------------------------------------------------------------
1 | export type Agent = {
2 | author: {
3 | github_id: string,
4 | id: string,
5 | name: string,
6 | source_url: string | null
7 | },
8 | chat_mode: {
9 | data_sources: string[],
10 | system_prompt: string,
11 | version: string
12 | },
13 | data_sources_indexed: boolean,
14 | description: string,
15 | metadata: {
16 | avatar_id: string,
17 | description: string,
18 | display_name: string,
19 | tags: string [],
20 | version: string,
21 | },
22 | data_sources: {
23 | id: string,
24 | uri: {
25 | type: string,
26 | uri: string
27 | }[]
28 | }[],
29 | min_cli_version: string,
30 | name: string,
31 | publisher_id: string,
32 | supported_commands: any,
33 | testing: boolean,
34 | version: string,
35 | enterprise: boolean
36 | }
--------------------------------------------------------------------------------
/web/src/lib/types/MarketPlace.ts:
--------------------------------------------------------------------------------
1 | export enum SortKey {
2 | POPULAR = "popular",
3 | TRENDING = "trending",
4 | NEW = "new"
5 | }
--------------------------------------------------------------------------------
/web/src/lib/types/Message.ts:
--------------------------------------------------------------------------------
1 | export type Message = {
2 | role: "user" | "model";
3 | text: string,
4 | references?: Array<{reference_id: string, type: string, url: string}>,
5 | }
--------------------------------------------------------------------------------
/web/src/lib/types/Questionnaires.ts:
--------------------------------------------------------------------------------
1 | export type Questionnaire = {
2 | id: string,
3 | message: string,
4 | }
--------------------------------------------------------------------------------
/web/src/lib/types/Toast.ts:
--------------------------------------------------------------------------------
1 | export enum ToastType {
2 | ERROR = "error",
3 | INFO = "info",
4 | SUCCESS = "success"
5 | }
--------------------------------------------------------------------------------
/web/src/lib/utils/appInsights.ts:
--------------------------------------------------------------------------------
1 | import { ApplicationInsights } from '@microsoft/applicationinsights-web';
2 |
3 | // const instrumentationKey = import.meta.env.VITE_INSTRUMENTATION_KEY;
4 | const instrumentationKey = '';
5 |
6 |
7 | if (!instrumentationKey) {
8 | console.log('instrumentation key not found');
9 | }
10 |
11 | const appInsights = new ApplicationInsights({
12 | config: {
13 | instrumentationKey: instrumentationKey
14 | }
15 | });
16 |
17 | appInsights.loadAppInsights();
18 | appInsights.trackPageView(); // Manually call trackPageView to establish the current user/session/pageview
19 |
20 | export default appInsights;
--------------------------------------------------------------------------------
/web/src/lib/utils/authenticate.ts:
--------------------------------------------------------------------------------
1 | type RequestOptions = Omit & {
2 | headers?: Record;
3 | };
4 |
5 | export async function apiRequest(url: string, options: RequestOptions = {}) {
6 | try {
7 | let accessToken = localStorage.getItem("accessToken");
8 | const headers: Record = {
9 | ...options.headers,
10 | "Content-Type": "application/json",
11 | };
12 |
13 | if (accessToken) {
14 | headers.Authorization = `Bearer ${accessToken}`;
15 | }
16 |
17 | const response = await fetch(url, {
18 | ...options,
19 | headers,
20 | });
21 |
22 | // Check if access token has expired (401 Unauthorized)
23 | if (response.status === 401) {
24 | const refreshed = await refreshAccessToken();
25 | if (refreshed) {
26 | // Retry the request with the new access token
27 | accessToken = localStorage.getItem("accessToken");
28 | headers.Authorization = `Bearer ${accessToken}`;
29 | return await fetch(url, {
30 | ...options,
31 | headers,
32 | });
33 | }
34 | }
35 |
36 | return response;
37 | } catch (error) {
38 | throw new Error(`API request failed: ${error}`);
39 | }
40 | }
41 |
42 | export async function refreshAccessToken(): Promise {
43 | try {
44 | const refreshToken = localStorage.getItem("refreshToken");
45 | if (!refreshToken) {
46 | console.error("No refresh token available");
47 | return false;
48 | }
49 |
50 | const response = await fetch("https://api.commanddash.dev/account/github/refresh", {
51 | method: "POST",
52 | headers: {
53 | Authorization: `Bearer ${refreshToken}`,
54 | },
55 | });
56 |
57 | const data = await response.json();
58 |
59 | if (response.ok) {
60 | const newAccessToken = data.access_token;
61 | if (newAccessToken) {
62 | localStorage.setItem("accessToken", newAccessToken);
63 | return true;
64 | }
65 | } else {
66 | console.error("Failed to refresh token", data);
67 | }
68 |
69 | return false;
70 | } catch (error) {
71 | console.error("Error refreshing access token:", error);
72 | return false;
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/web/src/lib/utils/copyToClipboard.ts:
--------------------------------------------------------------------------------
1 | // src/lib/utils/copyToClipboard.ts
2 | export function copyToClipboard(text: string) {
3 | const textarea = document.createElement("textarea");
4 | textarea.value = text;
5 | document.body.appendChild(textarea);
6 | textarea.select();
7 | document.execCommand("copy");
8 | document.body.removeChild(textarea);
9 | }
--------------------------------------------------------------------------------
/web/src/lib/utils/debounce.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * A debounce function that works in both browser and Nodejs.
3 | * For pure Nodejs work, prefer the `Debouncer` class.
4 | */
5 | export function debounce(
6 | callback: (...rest: T) => unknown,
7 | limit: number
8 | ): (...rest: T) => void {
9 | let timer: ReturnType;
10 |
11 | return function (...rest) {
12 | clearTimeout(timer);
13 | timer = setTimeout(() => {
14 | callback(...rest);
15 | }, limit);
16 | };
17 | }
18 |
--------------------------------------------------------------------------------
/web/src/lib/utils/isDesktop.ts:
--------------------------------------------------------------------------------
1 | // Approximate width from which we disable autofocus
2 | const TABLET_VIEWPORT_WIDTH = 768;
3 |
4 | export function isDesktop(window: Window) {
5 | const { innerWidth } = window;
6 | return innerWidth > TABLET_VIEWPORT_WIDTH;
7 | }
8 |
--------------------------------------------------------------------------------
/web/src/lib/utils/validateURL.ts:
--------------------------------------------------------------------------------
1 | // src/lib/utils/validateURL.ts
2 |
3 | export const validateURL = (url: string, platform: string): { isValid: boolean, packageName: string } => {
4 | const patterns = {
5 | github: /^(https:\/\/github\.com\/[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+\/?)$/,
6 | npm: /^(https:\/\/www\.npmjs\.com\/package\/(@?[A-Za-z0-9_.-]+\/?[A-Za-z0-9_.-]+))\/?.*$/,
7 | pypi: /^(https:\/\/pypi\.org\/project\/([A-Za-z0-9_.-]+))\/?.*$/,
8 | pub: /^(https:\/\/pub\.dev\/packages\/([A-Za-z0-9_.-]+))\/?.*$/,
9 | };
10 |
11 | const match = url.match(patterns[platform]);
12 | if (match) {
13 | return { isValid: true, packageName: match[2] };
14 | } else {
15 | return { isValid: false, packageName: "" };
16 | }
17 | };
--------------------------------------------------------------------------------
/web/src/routes/+error.svelte:
--------------------------------------------------------------------------------
1 |
4 |
5 |
8 |
11 |
{$page.status}
12 |
13 |
{$page.error?.message}
14 | {#if $page.error?.errorId}
15 |
16 |
18 | {$page.error.errorId}
19 |
20 | {/if}
21 |
22 |
23 |
--------------------------------------------------------------------------------
/web/src/routes/+layout.svelte:
--------------------------------------------------------------------------------
1 |
42 |
43 |
44 |
51 |
52 |
57 |
64 |
65 |
70 | {#if toastMessage}
71 |
72 | {/if}
73 |
74 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/web/src/routes/agent/[id]/+page.svelte:
--------------------------------------------------------------------------------
1 |
95 |
96 | {#if currentAgentDetails}
97 |
110 | {/if}
111 |
112 | {#if loading}
113 |
114 | {:else if !loading && !currentAgentDetails}
115 |
116 |
{errorStatus}
117 | {errorMessage}
118 |
119 | {/if}
120 |
--------------------------------------------------------------------------------
/web/src/styles/highlight-js.css:
--------------------------------------------------------------------------------
1 | @import "highlight.js/styles/atom-one-dark";
--------------------------------------------------------------------------------
/web/src/styles/main.css:
--------------------------------------------------------------------------------
1 | @import "./highlight-js.css";
2 |
3 | @tailwind base;
4 | @tailwind components;
5 | @tailwind utilities;
--------------------------------------------------------------------------------
/web/static/code-snippet.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/web/static/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CommandDash/commanddash/8d5d61379a47641c85d93fcbcda4f9175d44f5fc/web/static/favicon.png
--------------------------------------------------------------------------------
/web/static/github.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CommandDash/commanddash/8d5d61379a47641c85d93fcbcda4f9175d44f5fc/web/static/github.png
--------------------------------------------------------------------------------
/web/static/go.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CommandDash/commanddash/8d5d61379a47641c85d93fcbcda4f9175d44f5fc/web/static/go.png
--------------------------------------------------------------------------------
/web/static/icons8-dart-96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CommandDash/commanddash/8d5d61379a47641c85d93fcbcda4f9175d44f5fc/web/static/icons8-dart-96.png
--------------------------------------------------------------------------------
/web/static/icons8-github-80.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CommandDash/commanddash/8d5d61379a47641c85d93fcbcda4f9175d44f5fc/web/static/icons8-github-80.png
--------------------------------------------------------------------------------
/web/static/lottie/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":[]}
--------------------------------------------------------------------------------
/web/static/market-place.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/web/static/mellowtel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CommandDash/commanddash/8d5d61379a47641c85d93fcbcda4f9175d44f5fc/web/static/mellowtel.png
--------------------------------------------------------------------------------
/web/static/npm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CommandDash/commanddash/8d5d61379a47641c85d93fcbcda4f9175d44f5fc/web/static/npm.png
--------------------------------------------------------------------------------
/web/static/python.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CommandDash/commanddash/8d5d61379a47641c85d93fcbcda4f9175d44f5fc/web/static/python.png
--------------------------------------------------------------------------------
/web/static/question-mark.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/web/static/whoosh.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CommandDash/commanddash/8d5d61379a47641c85d93fcbcda4f9175d44f5fc/web/static/whoosh.mp3
--------------------------------------------------------------------------------
/web/svelte.config.js:
--------------------------------------------------------------------------------
1 | import adapter from "@sveltejs/adapter-node";
2 | import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
3 |
4 | /** @type {import('@sveltejs/kit').Config} */
5 | const config = {
6 | // Consult https://kit.svelte.dev/docs/integrations#preprocessors
7 | // for more information about preprocessors
8 | preprocess: vitePreprocess(),
9 |
10 | kit: {
11 | adapter: adapter(),
12 | csrf: {
13 | // handled in hooks.server.ts, because we can have multiple valid origins
14 | checkOrigin: false,
15 | },
16 | }
17 | };
18 |
19 | export default config;
--------------------------------------------------------------------------------
/web/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | export default {
3 | darkMode: 'class',
4 | content: ['./src/**/*.{html,js,svelte,ts}'],
5 | theme: {
6 | extend: {
7 | colors: {
8 | primary: "#497BEF"
9 | },
10 | fontSize: {
11 | xxs: "0.625rem",
12 | smd: "0.94rem"
13 | }
14 | }
15 | },
16 | plugins: [
17 | require("tailwind-scrollbar")({ nocompatible: true }),
18 | require("@tailwindcss/typography")
19 | ]
20 | };
--------------------------------------------------------------------------------
/web/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./.svelte-kit/tsconfig.json",
3 | "compilerOptions": {
4 | "allowJs": true,
5 | "checkJs": true,
6 | "esModuleInterop": true,
7 | "forceConsistentCasingInFileNames": true,
8 | "resolveJsonModule": true,
9 | "skipLibCheck": true,
10 | "sourceMap": true,
11 | "strict": true,
12 | "moduleResolution": "bundler"
13 | }
14 | // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
15 | // except $lib which is handled by https://kit.svelte.dev/docs/configuration#files
16 | //
17 | // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
18 | // from the referenced tsconfig.json - TypeScript does not merge them in
19 | }
20 |
--------------------------------------------------------------------------------
/web/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { sveltekit } from '@sveltejs/kit/vite';
2 | import { defineConfig } from 'vite';
3 | import Icons from "unplugin-icons/vite";
4 | import dotenv from 'dotenv';
5 |
6 | // Load environment variables from .env file only in development
7 | // Github actions work without dotenv
8 | if (process.env.NODE_ENV !== 'production') {
9 | dotenv.config();
10 | }
11 |
12 | export default defineConfig({
13 | define: {
14 | 'import.meta.env.VITE_INSTRUMENTATION_KEY': JSON.stringify(process.env.VITE_INSTRUMENTATION_KEY)
15 | },
16 | plugins: [sveltekit(), Icons({ compiler: "svelte" })]
17 | });
18 |
--------------------------------------------------------------------------------