diff --git a/.github/actions/pr/action.yml b/.github/actions/pr/action.yml index fbe3a08175b..79c9663a6e1 100644 --- a/.github/actions/pr/action.yml +++ b/.github/actions/pr/action.yml @@ -128,17 +128,17 @@ runs: run: | baseBranch="" if [ "${{ inputs.ballerina }}" == 'true' ]; then - baseBranch="release-ballerina" + baseBranch="stable/ballerina" elif [ "${{ inputs.bi }}" == 'true' ]; then - baseBranch="release-bi" + baseBranch="stable/bi" elif [ "${{ inputs.wso2-platform }}" == 'true' ]; then - baseBranch="release-platform" + baseBranch="stable/platform" elif [ "${{ inputs.choreo }}" == 'true' ]; then - baseBranch="release-choreo" + baseBranch="stable/choreo" elif [ "${{ inputs.apk }}" == 'true' ]; then - baseBranch="release-apk" + baseBranch="stable/apk" elif [ "${{ inputs.mi }}" == 'true' ]; then - baseBranch="release-mi" + baseBranch="stable/mi" fi pr=$(gh pr create -B "$baseBranch" -H "${{ inputs.version }}" --title "Merge \"${{ inputs.version }}\" into \"$baseBranch\"" --body '$subject') echo "prURL=$pr" >> $GITHUB_OUTPUT diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8522f3cb7c2..ce5c20ca896 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -233,7 +233,7 @@ jobs: name: Run Ballerina extension tests needs: Build_Stage if: false - # if: ${{ inputs.runTests || (inputs.isReleaseBuild && (inputs.ballerina || inputs.bi)) || needs.Build_Stage.outputs.runBalExtTests == 'true' || github.base_ref == 'release-ballerina' }} + # if: ${{ inputs.runTests || (inputs.isReleaseBuild && (inputs.ballerina || inputs.bi)) || needs.Build_Stage.outputs.runBalExtTests == 'true' || github.base_ref == 'stable/ballerina' }} timeout-minutes: 45 runs-on: ${{ inputs.runOnAWS && inputs.awsRunnerId || 'ubuntu-latest' }} steps: @@ -281,7 +281,7 @@ jobs: ExtTest_MI: name: Run MI diagram tests needs: Build_Stage - if: ${{ inputs.runTests || (inputs.isReleaseBuild && inputs.mi) || needs.Build_Stage.outputs.runMIExtTests == 'true' || github.base_ref == 'release-mi' }} + if: ${{ inputs.runTests || (inputs.isReleaseBuild && inputs.mi) || needs.Build_Stage.outputs.runMIExtTests == 'true' || github.base_ref == 'stable/mi' }} timeout-minutes: 30 runs-on: ${{ inputs.runOnAWS && inputs.awsRunnerId || 'ubuntu-latest' }} steps: diff --git a/.github/workflows/sync-main-with-releases.yml b/.github/workflows/sync-main-with-releases.yml index 8255d27bdc0..48bebbf58fb 100644 --- a/.github/workflows/sync-main-with-releases.yml +++ b/.github/workflows/sync-main-with-releases.yml @@ -4,7 +4,7 @@ on: types: - closed branches: - - 'release-**' + - 'stable/**' jobs: sync-main: diff --git a/.github/workflows/test-pr.yml b/.github/workflows/test-pr.yml index 6dcc056684d..b7513480cfb 100644 --- a/.github/workflows/test-pr.yml +++ b/.github/workflows/test-pr.yml @@ -17,5 +17,5 @@ jobs: with: runOnAWS: ${{ contains(github.event.pull_request.labels.*.name, 'Runner/AWS') }} enableE2ETests: ${{ contains(github.event.pull_request.labels.*.name, 'Checks/Enable UI Tests') }} - runBIE2ETests: ${{ contains(github.event.pull_request.labels.*.name, 'Checks/Run BI UI Tests') || github.base_ref == 'release-bi' || github.base_ref == 'release-ballerina' }} - runMIE2ETests: ${{ contains(github.event.pull_request.labels.*.name, 'Checks/Run MI UI Tests') || github.base_ref == 'release-mi' }} + runBIE2ETests: ${{ contains(github.event.pull_request.labels.*.name, 'Checks/Run BI UI Tests') || github.base_ref == 'stable/bi' || github.base_ref == 'stable/ballerina' }} + runMIE2ETests: ${{ contains(github.event.pull_request.labels.*.name, 'Checks/Run MI UI Tests') || github.base_ref == 'stable/mi' }} diff --git a/common/config/rush/.pnpmfile.cjs b/common/config/rush/.pnpmfile.cjs index 9afac4b374a..907f3abecb7 100644 --- a/common/config/rush/.pnpmfile.cjs +++ b/common/config/rush/.pnpmfile.cjs @@ -46,6 +46,24 @@ module.exports = { if (pkg.dependencies['lodash']) { pkg.dependencies['lodash'] = '4.17.23'; } + if (pkg.dependencies['qs']) { + pkg.dependencies['qs'] = '6.14.2'; + } + if (pkg.dependencies['diff']) { + pkg.dependencies['diff'] = '^8.0.3'; + } + if (pkg.dependencies['eslint']) { + pkg.dependencies['eslint'] = '^9.27.0'; + } + if (pkg.dependencies['fast-xml-parser']) { + pkg.dependencies['fast-xml-parser'] = '5.3.4'; + } + if (pkg.dependencies['hono']) { + pkg.dependencies['hono'] = '^4.11.7'; + } + if (pkg.dependencies['lodash']) { + pkg.dependencies['lodash'] = '4.17.23'; + } } if (pkg.devDependencies) { @@ -79,6 +97,24 @@ module.exports = { if (pkg.devDependencies['lodash']) { pkg.devDependencies['lodash'] = '4.17.23'; } + if (pkg.devDependencies['qs']) { + pkg.devDependencies['qs'] = '6.14.2'; + } + if (pkg.devDependencies['diff']) { + pkg.devDependencies['diff'] = '^8.0.3'; + } + if (pkg.devDependencies['eslint']) { + pkg.devDependencies['eslint'] = '^9.27.0'; + } + if (pkg.devDependencies['fast-xml-parser']) { + pkg.devDependencies['fast-xml-parser'] = '5.3.4'; + } + if (pkg.devDependencies['hono']) { + pkg.devDependencies['hono'] = '^4.11.7'; + } + if (pkg.devDependencies['lodash']) { + pkg.devDependencies['lodash'] = '4.17.23'; + } } return pkg; diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index 762539d31d2..4eac4d3c631 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -68,8 +68,8 @@ importers: specifier: 0.5.14 version: 0.5.14 axios: - specifier: 1.12.0 - version: 1.12.0 + specifier: 1.13.5 + version: 1.13.5 copyfiles: specifier: 2.4.1 version: 2.4.1 @@ -93,7 +93,7 @@ importers: version: 2.6.7(encoding@0.1.13) node-loader: specifier: 2.0.0 - version: 2.0.0(webpack@5.99.9) + version: 2.0.0(webpack@5.104.1) portfinder: specifier: 1.0.32 version: 1.0.32 @@ -136,16 +136,16 @@ importers: version: 5.0.5 ts-loader: specifier: 9.4.4 - version: 9.4.4(typescript@5.8.3)(webpack@5.99.9) + version: 9.4.4(typescript@5.8.3)(webpack@5.104.1) typescript: specifier: 5.8.3 version: 5.8.3 webpack: - specifier: 5.99.9 - version: 5.99.9(webpack-cli@5.1.4) + specifier: 5.104.1 + version: 5.104.1(webpack-cli@5.1.4) webpack-cli: specifier: 5.1.4 - version: 5.1.4(webpack@5.99.9) + version: 5.1.4(webpack@5.104.1) ../../workspaces/api-designer/api-designer-rpc-client: dependencies: @@ -273,7 +273,7 @@ importers: version: 7.4.0(encoding@0.1.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3) '@storybook/react-webpack5': specifier: 7.4.0 - version: 7.4.0(@babel/core@7.29.0)(@swc/helpers@0.5.18)(@types/webpack@5.28.5(webpack-cli@5.1.4))(encoding@0.1.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(type-fest@4.41.0)(typescript@5.8.3)(webpack-cli@5.1.4)(webpack-dev-server@5.2.1)(webpack-hot-middleware@2.26.1) + version: 7.4.0(@babel/core@7.29.0)(@swc/helpers@0.5.18)(@types/webpack@5.28.5(webpack-cli@5.1.4))(encoding@0.1.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(type-fest@4.41.0)(typescript@5.8.3)(webpack-cli@5.1.4)(webpack-dev-server@5.2.3)(webpack-hot-middleware@2.26.1) '@types/js-yaml': specifier: 4.0.9 version: 4.0.9 @@ -300,31 +300,31 @@ importers: version: 2.4.1 css-loader: specifier: 5.2.7 - version: 5.2.7(webpack@5.99.9) + version: 5.2.7(webpack@5.104.1) sass-loader: specifier: 13.2.0 - version: 13.2.0(sass@1.89.0)(webpack@5.99.9) + version: 13.2.0(sass@1.89.0)(webpack@5.104.1) source-map-loader: specifier: 4.0.1 - version: 4.0.1(webpack@5.99.9) + version: 4.0.1(webpack@5.104.1) style-loader: specifier: 1.3.0 - version: 1.3.0(webpack@5.99.9) + version: 1.3.0(webpack@5.104.1) ts-loader: specifier: 9.5.0 - version: 9.5.0(typescript@5.8.3)(webpack@5.99.9) + version: 9.5.0(typescript@5.8.3)(webpack@5.104.1) typescript: specifier: 5.8.3 version: 5.8.3 webpack: - specifier: 5.99.9 - version: 5.99.9(webpack-cli@5.1.4) + specifier: 5.104.1 + version: 5.104.1(webpack-cli@5.1.4) webpack-cli: specifier: 5.1.4 - version: 5.1.4(webpack-dev-server@5.2.1)(webpack@5.99.9) + version: 5.1.4(webpack-dev-server@5.2.3)(webpack@5.104.1) webpack-dev-server: - specifier: 5.2.1 - version: 5.2.1(webpack-cli@5.1.4)(webpack@5.99.9) + specifier: 5.2.3 + version: 5.2.3(webpack-cli@5.1.4)(webpack@5.104.1) ../../workspaces/apk/apk-extension: devDependencies: @@ -426,8 +426,8 @@ importers: specifier: 18.2.0 version: 18.2.0 '@types/vscode': - specifier: 1.83.1 - version: 1.83.1 + specifier: 1.100.0 + version: 1.100.0 '@typescript-eslint/eslint-plugin': specifier: 8.32.1 version: 8.32.1(@typescript-eslint/parser@8.32.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.8.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.8.3) @@ -589,8 +589,8 @@ importers: specifier: 1.0.3 version: 1.0.3 '@types/vscode': - specifier: 1.83.1 - version: 1.83.1 + specifier: 1.100.0 + version: 1.100.0 '@types/vscode-notebook-renderer': specifier: 1.72.2 version: 1.72.2 @@ -598,8 +598,8 @@ importers: specifier: 0.5.16 version: 0.5.16 axios: - specifier: 1.12.0 - version: 1.12.0 + specifier: 1.13.5 + version: 1.13.5 chai: specifier: 4.3.10 version: 4.3.10 @@ -647,7 +647,7 @@ importers: version: 1.0.2 ts-loader: specifier: 9.5.0 - version: 9.5.0(typescript@5.8.3)(webpack@5.99.9) + version: 9.5.0(typescript@5.8.3)(webpack@5.104.1) tslint: specifier: 6.1.3 version: 6.1.3(typescript@5.8.3) @@ -661,11 +661,11 @@ importers: specifier: 5.10.0 version: 5.10.0(mocha@10.2.0)(typescript@5.8.3) webpack: - specifier: 5.99.9 - version: 5.99.9(webpack-cli@6.0.1) + specifier: 5.104.1 + version: 5.104.1(webpack-cli@6.0.1) webpack-cli: specifier: 6.0.1 - version: 6.0.1(webpack@5.99.9) + version: 6.0.1(webpack@5.104.1) yarn: specifier: 1.22.19 version: 1.22.19 @@ -768,7 +768,7 @@ importers: version: 6.5.16(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@storybook/addon-essentials': specifier: 6.5.16 - version: 6.5.16(@babel/core@7.27.1)(@storybook/builder-webpack5@6.5.16(@swc/core@1.15.11(@swc/helpers@0.5.18))(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@6.0.1))(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@6.0.1)(webpack@5.99.9) + version: 6.5.16(@babel/core@7.27.1)(@storybook/builder-webpack5@6.5.16(@swc/core@1.15.11(@swc/helpers@0.5.18))(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@6.0.1))(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@6.0.1)(webpack@5.104.1) '@storybook/addon-links': specifier: 6.5.16 version: 6.5.16(react-dom@18.2.0(react@18.2.0))(react@18.2.0) @@ -780,7 +780,7 @@ importers: version: 6.5.9(@swc/core@1.15.11(@swc/helpers@0.5.18))(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@6.0.1) '@storybook/react': specifier: 6.5.16 - version: 6.5.16(@babel/core@7.27.1)(@storybook/builder-webpack5@6.5.16(@swc/core@1.15.11(@swc/helpers@0.5.18))(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@6.0.1))(@storybook/manager-webpack5@6.5.9(@swc/core@1.15.11(@swc/helpers@0.5.18))(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@6.0.1))(@swc/core@1.15.11(@swc/helpers@0.5.18))(@types/webpack@5.28.5(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1))(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(require-from-string@2.0.2)(type-fest@4.41.0)(typescript@5.8.3)(webpack-cli@6.0.1)(webpack-dev-server@5.2.1)(webpack-hot-middleware@2.26.1) + version: 6.5.16(@babel/core@7.27.1)(@storybook/builder-webpack5@6.5.16(@swc/core@1.15.11(@swc/helpers@0.5.18))(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@6.0.1))(@storybook/manager-webpack5@6.5.9(@swc/core@1.15.11(@swc/helpers@0.5.18))(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@6.0.1))(@swc/core@1.15.11(@swc/helpers@0.5.18))(@types/webpack@5.28.5(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1))(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(require-from-string@2.0.2)(type-fest@4.41.0)(typescript@5.8.3)(webpack-cli@6.0.1)(webpack-dev-server@5.2.3)(webpack-hot-middleware@2.26.1) '@types/classnames': specifier: 2.2.9 version: 2.2.9 @@ -813,25 +813,25 @@ importers: version: 5.28.5(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) babel-loader: specifier: 10.0.0 - version: 10.0.0(@babel/core@7.27.1)(webpack@5.99.9) + version: 10.0.0(@babel/core@7.27.1)(webpack@5.104.1) copy-webpack-plugin: specifier: 13.0.0 - version: 13.0.0(webpack@5.99.9) + version: 13.0.0(webpack@5.104.1) copyfiles: specifier: 2.4.1 version: 2.4.1 css-loader: specifier: 7.1.2 - version: 7.1.2(webpack@5.99.9) + version: 7.1.2(webpack@5.104.1) express: specifier: 4.22.1 version: 4.22.1 file-loader: specifier: 6.2.0 - version: 6.2.0(webpack@5.99.9) + version: 6.2.0(webpack@5.104.1) fork-ts-checker-webpack-plugin: specifier: 9.1.0 - version: 9.1.0(typescript@5.8.3)(webpack@5.99.9) + version: 9.1.0(typescript@5.8.3)(webpack@5.104.1) glob: specifier: 11.1.0 version: 11.1.0 @@ -870,13 +870,13 @@ importers: version: 1.89.0 sass-loader: specifier: 16.0.5 - version: 16.0.5(sass@1.89.0)(webpack@5.99.9) + version: 16.0.5(sass@1.89.0)(webpack@5.104.1) storybook: specifier: 8.6.14 version: 8.6.14(prettier@3.5.3) style-loader: specifier: 4.0.0 - version: 4.0.0(webpack@5.99.9) + version: 4.0.0(webpack@5.104.1) stylelint: specifier: 16.19.1 version: 16.19.1(typescript@5.8.3) @@ -885,10 +885,10 @@ importers: version: 38.0.0(stylelint@16.19.1(typescript@5.8.3)) svg-url-loader: specifier: 8.0.0 - version: 8.0.0(webpack@5.99.9) + version: 8.0.0(webpack@5.104.1) ts-loader: specifier: 9.5.2 - version: 9.5.2(typescript@5.8.3)(webpack@5.99.9) + version: 9.5.2(typescript@5.8.3)(webpack@5.104.1) tslib: specifier: 2.8.1 version: 2.8.1 @@ -905,14 +905,14 @@ importers: specifier: 5.8.3 version: 5.8.3 webpack: - specifier: 5.99.9 - version: 5.99.9(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) + specifier: 5.104.1 + version: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) webpack-cli: specifier: 6.0.1 - version: 6.0.1(webpack-dev-server@5.2.1)(webpack@5.99.9) + version: 6.0.1(webpack-dev-server@5.2.3)(webpack@5.104.1) webpack-dev-server: - specifier: 5.2.1 - version: 5.2.1(webpack-cli@6.0.1)(webpack@5.99.9) + specifier: 5.2.3 + version: 5.2.3(webpack-cli@6.0.1)(webpack@5.104.1) ../../workspaces/ballerina/ballerina-rpc-client: dependencies: @@ -1023,8 +1023,8 @@ importers: specifier: 4.17.23 version: 4.17.23 markdown-it: - specifier: 14.1.0 - version: 14.1.0 + specifier: 14.1.1 + version: 14.1.1 prosemirror-commands: specifier: 1.7.1 version: 1.7.1 @@ -1079,7 +1079,7 @@ importers: devDependencies: '@storybook/react': specifier: 6.5.16 - version: 6.5.16(@babel/core@7.29.0)(@types/webpack@5.28.5)(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(require-from-string@2.0.2)(type-fest@4.41.0)(typescript@5.8.3)(webpack-dev-server@5.2.1(webpack@5.103.0))(webpack-hot-middleware@2.26.1) + version: 6.5.16(@babel/core@7.29.0)(@types/webpack@5.28.5)(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(require-from-string@2.0.2)(type-fest@4.41.0)(typescript@5.8.3)(webpack-dev-server@5.2.3(webpack@5.104.1))(webpack-hot-middleware@2.26.1) '@types/lodash': specifier: 4.17.16 version: 4.17.16 @@ -1098,6 +1098,15 @@ importers: ../../workspaces/ballerina/ballerina-visualizer: dependencies: + '@dnd-kit/core': + specifier: 6.1.0 + version: 6.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@dnd-kit/sortable': + specifier: 8.0.0 + version: 8.0.0(@dnd-kit/core@6.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react@18.2.0) + '@dnd-kit/utilities': + specifier: 3.2.2 + version: 3.2.2(react@18.2.0) '@emotion/css': specifier: 11.13.5 version: 11.13.5 @@ -1179,9 +1188,15 @@ importers: '@wso2/wso2-platform-core': specifier: workspace:* version: link:../../wso2-platform/wso2-platform-core + framer-motion: + specifier: ^11.0.0 + version: 11.18.2(@emotion/is-prop-valid@1.4.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) highlight.js: specifier: 11.11.1 version: 11.11.1 + katex: + specifier: ^0.16.27 + version: 0.16.28 lodash: specifier: 4.17.23 version: 4.17.23 @@ -1209,12 +1224,21 @@ importers: react-syntax-highlighter: specifier: 15.6.1 version: 15.6.1(react@18.2.0) + rehype-katex: + specifier: ^7.0.1 + version: 7.0.1 rehype-raw: - specifier: 7.0.0 + specifier: ^7.0.0 version: 7.0.0 remark-breaks: - specifier: 4.0.0 + specifier: ~4.0.0 version: 4.0.0 + remark-gfm: + specifier: ^4.0.1 + version: 4.0.1 + remark-math: + specifier: ^6.0.0 + version: 6.0.0 vscode-uri: specifier: 3.1.0 version: 3.1.0 @@ -1260,7 +1284,7 @@ importers: version: 2.4.1 css-loader: specifier: 7.1.2 - version: 7.1.2(webpack@5.99.9) + version: 7.1.2(webpack@5.104.1) eslint: specifier: ^9.27.0 version: 9.39.2(jiti@2.6.1) @@ -1272,37 +1296,37 @@ importers: version: 0.4.20(eslint@9.39.2(jiti@2.6.1)) sass-loader: specifier: 16.0.5 - version: 16.0.5(sass@1.89.0)(webpack@5.99.9) + version: 16.0.5(sass@1.89.0)(webpack@5.104.1) source-map-loader: specifier: 5.0.0 - version: 5.0.0(webpack@5.99.9) + version: 5.0.0(webpack@5.104.1) style-loader: specifier: 4.0.0 - version: 4.0.0(webpack@5.99.9) + version: 4.0.0(webpack@5.104.1) ts-loader: specifier: 9.5.2 - version: 9.5.2(typescript@5.8.3)(webpack@5.99.9) + version: 9.5.2(typescript@5.8.3)(webpack@5.104.1) typescript: specifier: 5.8.3 version: 5.8.3 webpack: - specifier: 5.99.9 - version: 5.99.9(webpack-cli@5.1.4) + specifier: 5.104.1 + version: 5.104.1(webpack-cli@5.1.4) webpack-cli: specifier: 5.1.4 - version: 5.1.4(webpack-dev-server@5.2.1)(webpack@5.99.9) + version: 5.1.4(webpack-dev-server@5.2.3)(webpack@5.104.1) webpack-dev-server: - specifier: 5.2.1 - version: 5.2.1(webpack-cli@5.1.4)(webpack@5.99.9) + specifier: 5.2.3 + version: 5.2.3(webpack-cli@5.1.4)(webpack@5.104.1) ../../workspaces/ballerina/bi-diagram: dependencies: '@emotion/react': - specifier: 11.9.3 - version: 11.9.3(@babel/core@7.27.1)(@types/react@18.2.0)(react@18.2.0) + specifier: 11.14.0 + version: 11.14.0(@types/react@18.2.0)(react@18.2.0) '@emotion/styled': - specifier: 11.10.5 - version: 11.10.5(@babel/core@7.27.1)(@emotion/react@11.9.3(@babel/core@7.27.1)(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0)(react@18.2.0) + specifier: 11.14.0 + version: 11.14.0(@emotion/react@11.14.0(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0)(react@18.2.0) '@projectstorm/geometry': specifier: 6.7.4 version: 6.7.4 @@ -1311,16 +1335,16 @@ importers: version: 6.7.4(lodash@4.17.23)(react@18.2.0) '@projectstorm/react-diagrams': specifier: 7.0.4 - version: 7.0.4(@emotion/react@11.9.3(@babel/core@7.27.1)(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0) + version: 7.0.4(@emotion/react@11.14.0(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0) '@projectstorm/react-diagrams-core': specifier: 7.0.3 - version: 7.0.3(@emotion/react@11.9.3(@babel/core@7.27.1)(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0) + version: 7.0.3(@emotion/react@11.14.0(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0) '@projectstorm/react-diagrams-defaults': specifier: 7.1.3 version: 7.1.3(@types/react@18.2.0) '@projectstorm/react-diagrams-routing': specifier: 7.1.3 - version: 7.1.3(@emotion/react@11.9.3(@babel/core@7.27.1)(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0) + version: 7.1.3(@emotion/react@11.14.0(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0) '@wso2/ballerina-core': specifier: workspace:* version: link:../ballerina-core @@ -1481,7 +1505,7 @@ importers: version: 7.27.1(@babel/core@7.27.1) '@storybook/react': specifier: 6.5.16 - version: 6.5.16(@babel/core@7.27.1)(@swc/core@1.15.11(@swc/helpers@0.5.18))(@types/webpack@5.28.5(@swc/core@1.15.11(@swc/helpers@0.5.18)))(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(require-from-string@2.0.2)(type-fest@4.41.0)(typescript@5.8.3)(webpack-dev-server@5.2.1(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))))(webpack-hot-middleware@2.26.1) + version: 6.5.16(@babel/core@7.27.1)(@swc/core@1.15.11(@swc/helpers@0.5.18))(@types/webpack@5.28.5(@swc/core@1.15.11(@swc/helpers@0.5.18)))(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(require-from-string@2.0.2)(type-fest@4.41.0)(typescript@5.8.3)(webpack-dev-server@5.2.3(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))))(webpack-hot-middleware@2.26.1) '@testing-library/dom': specifier: 10.4.0 version: 10.4.0 @@ -1644,7 +1668,7 @@ importers: version: 2.4.1 css-loader: specifier: 7.1.2 - version: 7.1.2(webpack@5.103.0) + version: 7.1.2(webpack@5.104.1) eslint: specifier: ^9.27.0 version: 9.39.2(jiti@2.6.1) @@ -1656,10 +1680,10 @@ importers: version: 0.4.4(eslint@9.39.2(jiti@2.6.1)) file-loader: specifier: 6.2.0 - version: 6.2.0(webpack@5.103.0) + version: 6.2.0(webpack@5.104.1) ts-loader: specifier: 9.5.2 - version: 9.5.2(typescript@5.8.3)(webpack@5.103.0) + version: 9.5.2(typescript@5.8.3)(webpack@5.104.1) tslib: specifier: 2.8.1 version: 2.8.1 @@ -1702,7 +1726,7 @@ importers: version: 6.5.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@storybook/addon-essentials': specifier: 6.5.9 - version: 6.5.9(@babel/core@7.27.1)(@storybook/builder-webpack5@6.5.9(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@4.10.0))(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@4.10.0)(webpack@5.99.9) + version: 6.5.9(@babel/core@7.27.1)(@storybook/builder-webpack5@6.5.9(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@4.10.0))(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@4.10.0)(webpack@5.104.1) '@storybook/addon-links': specifier: 6.5.9 version: 6.5.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0) @@ -1714,7 +1738,7 @@ importers: version: 6.5.9(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@4.10.0) '@storybook/react': specifier: 6.5.9 - version: 6.5.9(@babel/core@7.27.1)(@storybook/builder-webpack5@6.5.9(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@4.10.0))(@storybook/manager-webpack5@6.5.9(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@4.10.0))(@types/webpack@5.28.5(webpack-cli@4.10.0))(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(require-from-string@2.0.2)(type-fest@4.41.0)(typescript@5.8.3)(webpack-cli@4.10.0)(webpack-dev-server@5.2.1)(webpack-hot-middleware@2.26.1) + version: 6.5.9(@babel/core@7.27.1)(@storybook/builder-webpack5@6.5.9(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@4.10.0))(@storybook/manager-webpack5@6.5.9(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@4.10.0))(@types/webpack@5.28.5(webpack-cli@4.10.0))(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(require-from-string@2.0.2)(type-fest@4.41.0)(typescript@5.8.3)(webpack-cli@4.10.0)(webpack-dev-server@5.2.3)(webpack-hot-middleware@2.26.1) '@types/react': specifier: 18.2.0 version: 18.2.0 @@ -1723,34 +1747,34 @@ importers: version: 18.2.0 babel-loader: specifier: 10.0.0 - version: 10.0.0(@babel/core@7.27.1)(webpack@5.99.9) + version: 10.0.0(@babel/core@7.27.1)(webpack@5.104.1) css-loader: specifier: 7.1.2 - version: 7.1.2(webpack@5.99.9) + version: 7.1.2(webpack@5.104.1) graphql: specifier: 16.11.0 version: 16.11.0 mini-css-extract-plugin: specifier: 2.9.2 - version: 2.9.2(webpack@5.99.9) + version: 2.9.2(webpack@5.104.1) source-map-loader: specifier: 5.0.0 - version: 5.0.0(webpack@5.99.9) + version: 5.0.0(webpack@5.104.1) style-loader: specifier: 4.0.0 - version: 4.0.0(webpack@5.99.9) + version: 4.0.0(webpack@5.104.1) ts-loader: specifier: 9.5.2 - version: 9.5.2(typescript@5.8.3)(webpack@5.99.9) + version: 9.5.2(typescript@5.8.3)(webpack@5.104.1) typescript: specifier: 5.8.3 version: 5.8.3 webpack: - specifier: 5.99.9 - version: 5.99.9(webpack-cli@4.10.0) + specifier: 5.104.1 + version: 5.104.1(webpack-cli@4.10.0) webpack-cli: specifier: 4.10.0 - version: 4.10.0(webpack-dev-server@5.2.1)(webpack@5.99.9) + version: 4.10.0(webpack-dev-server@5.2.3)(webpack@5.104.1) ../../workspaces/ballerina/graphql-design-diagram: dependencies: @@ -1788,8 +1812,8 @@ importers: specifier: 2.4.1 version: 2.4.1 html-to-image: - specifier: 1.10.8 - version: 1.10.8 + specifier: 1.11.11 + version: 1.11.11 lodash: specifier: 4.17.23 version: 4.17.23 @@ -1810,16 +1834,16 @@ importers: version: 6.0.1 tslint: specifier: 6.1.3 - version: 6.1.3(typescript@4.1.3) + version: 6.1.3(typescript@4.2.4) tslint-react: specifier: 5.0.0 - version: 5.0.0(tslint@6.1.3(typescript@4.1.3))(typescript@4.1.3) + version: 5.0.0(tslint@6.1.3(typescript@4.2.4))(typescript@4.2.4) tslint-react-hooks: specifier: 2.2.2 - version: 2.2.2(tslint@6.1.3(typescript@4.1.3))(typescript@4.1.3) + version: 2.2.2(tslint@6.1.3(typescript@4.2.4))(typescript@4.2.4) typescript: - specifier: 4.1.3 - version: 4.1.3 + specifier: 4.2.4 + version: 4.2.4 vscode-uri: specifier: 3.1.0 version: 3.1.0 @@ -1834,11 +1858,11 @@ importers: ../../workspaces/ballerina/overview-view: dependencies: '@emotion/react': - specifier: 11.9.3 - version: 11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@18.2.0) + specifier: 11.14.0 + version: 11.14.0(@types/react@18.2.0)(react@18.2.0) '@emotion/styled': - specifier: 11.10.5 - version: 11.10.5(@babel/core@7.29.0)(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0)(react@18.2.0) + specifier: 11.14.0 + version: 11.14.0(@emotion/react@11.14.0(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0)(react@18.2.0) '@vscode/webview-ui-toolkit': specifier: 1.2.0 version: 1.2.0(react@18.2.0) @@ -1892,11 +1916,11 @@ importers: specifier: 11.13.5 version: 11.13.5 '@emotion/react': - specifier: 11.9.3 - version: 11.9.3(@babel/core@7.27.1)(@types/react@18.2.0)(react@18.2.0) + specifier: 11.14.0 + version: 11.14.0(@types/react@18.2.0)(react@18.2.0) '@emotion/styled': - specifier: 11.10.5 - version: 11.10.5(@babel/core@7.27.1)(@emotion/react@11.9.3(@babel/core@7.27.1)(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0)(react@18.2.0) + specifier: 11.14.0 + version: 11.14.0(@emotion/react@11.14.0(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0)(react@18.2.0) '@projectstorm/geometry': specifier: 7.0.3 version: 7.0.3 @@ -1905,16 +1929,16 @@ importers: version: 7.0.3(@types/react@18.2.0) '@projectstorm/react-diagrams': specifier: 7.0.4 - version: 7.0.4(@emotion/react@11.9.3(@babel/core@7.27.1)(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0) + version: 7.0.4(@emotion/react@11.14.0(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0) '@projectstorm/react-diagrams-core': specifier: 7.0.3 - version: 7.0.3(@emotion/react@11.9.3(@babel/core@7.27.1)(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0) + version: 7.0.3(@emotion/react@11.14.0(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0) '@projectstorm/react-diagrams-defaults': specifier: 7.1.3 version: 7.1.3(@types/react@18.2.0) '@projectstorm/react-diagrams-routing': specifier: 7.1.3 - version: 7.1.3(@emotion/react@11.9.3(@babel/core@7.27.1)(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0) + version: 7.1.3(@emotion/react@11.14.0(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0) '@types/lodash': specifier: 4.14.189 version: 4.14.189 @@ -1929,10 +1953,10 @@ importers: version: 0.8.5 file-loader: specifier: 6.2.0 - version: 6.2.0(webpack@5.99.9) + version: 6.2.0(webpack@5.104.1) html-to-image: - specifier: 1.10.8 - version: 1.10.8 + specifier: 1.11.11 + version: 1.11.11 lodash: specifier: 4.17.23 version: 4.17.23 @@ -1972,31 +1996,31 @@ importers: version: link:../../common-libs/ui-toolkit babel-loader: specifier: 10.0.0 - version: 10.0.0(@babel/core@7.27.1)(webpack@5.99.9) + version: 10.0.0(@babel/core@7.27.1)(webpack@5.104.1) copyfiles: specifier: 2.4.1 version: 2.4.1 css-loader: specifier: 7.1.2 - version: 7.1.2(webpack@5.99.9) + version: 7.1.2(webpack@5.104.1) source-map-loader: specifier: 5.0.0 - version: 5.0.0(webpack@5.99.9) + version: 5.0.0(webpack@5.104.1) style-loader: specifier: 4.0.0 - version: 4.0.0(webpack@5.99.9) + version: 4.0.0(webpack@5.104.1) ts-loader: specifier: 9.4.1 - version: 9.4.1(typescript@5.8.3)(webpack@5.99.9) + version: 9.4.1(typescript@5.8.3)(webpack@5.104.1) webpack: - specifier: 5.99.9 - version: 5.99.9(webpack-cli@6.0.1) + specifier: 5.104.1 + version: 5.104.1(webpack-cli@6.0.1) webpack-cli: specifier: 6.0.1 - version: 6.0.1(webpack-dev-server@5.2.1)(webpack@5.99.9) + version: 6.0.1(webpack-dev-server@5.2.3)(webpack@5.104.1) webpack-dev-server: - specifier: 5.2.1 - version: 5.2.1(webpack-cli@6.0.1)(webpack@5.99.9) + specifier: 5.2.3 + version: 5.2.3(webpack-cli@6.0.1)(webpack@5.104.1) ../../workspaces/ballerina/record-creator: dependencies: @@ -2086,11 +2110,11 @@ importers: ../../workspaces/ballerina/sequence-diagram: dependencies: '@emotion/react': - specifier: 11.9.3 - version: 11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@18.2.0) + specifier: 11.14.0 + version: 11.14.0(@types/react@18.2.0)(react@18.2.0) '@emotion/styled': - specifier: 11.10.5 - version: 11.10.5(@babel/core@7.29.0)(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0)(react@18.2.0) + specifier: 11.14.0 + version: 11.14.0(@emotion/react@11.14.0(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0)(react@18.2.0) '@projectstorm/geometry': specifier: 7.0.3 version: 7.0.3 @@ -2099,16 +2123,16 @@ importers: version: 7.0.3(@types/react@18.2.0) '@projectstorm/react-diagrams': specifier: 7.0.4 - version: 7.0.4(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0) + version: 7.0.4(@emotion/react@11.14.0(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0) '@projectstorm/react-diagrams-core': specifier: 7.0.3 - version: 7.0.3(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0) + version: 7.0.3(@emotion/react@11.14.0(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0) '@projectstorm/react-diagrams-defaults': specifier: 7.1.3 version: 7.1.3(@types/react@18.2.0) '@projectstorm/react-diagrams-routing': specifier: 7.1.3 - version: 7.1.3(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0) + version: 7.1.3(@emotion/react@11.14.0(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0) '@wso2/ballerina-core': specifier: workspace:* version: link:../ballerina-core @@ -2174,11 +2198,11 @@ importers: specifier: 11.13.5 version: 11.13.5 '@emotion/react': - specifier: 11.9.3 - version: 11.9.3(@babel/core@7.29.0)(@types/react@17.0.37)(react@19.1.0) + specifier: 11.14.0 + version: 11.14.0(@types/react@17.0.37)(react@19.1.0) '@emotion/styled': - specifier: 11.10.5 - version: 11.10.5(@babel/core@7.29.0)(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@17.0.37)(react@19.1.0))(@types/react@17.0.37)(react@19.1.0) + specifier: 11.14.0 + version: 11.14.0(@emotion/react@11.14.0(@types/react@17.0.37)(react@19.1.0))(@types/react@17.0.37)(react@19.1.0) '@tanstack/query-core': specifier: 5.77.1 version: 5.77.1 @@ -2233,7 +2257,7 @@ importers: devDependencies: '@storybook/react': specifier: 6.5.9 - version: 6.5.9(@babel/core@7.29.0)(@types/webpack@5.28.5)(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(require-from-string@2.0.2)(type-fest@4.41.0)(typescript@4.9.4)(webpack-dev-server@5.2.1(webpack@5.103.0))(webpack-hot-middleware@2.26.1) + version: 6.5.9(@babel/core@7.29.0)(@types/webpack@5.28.5)(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(require-from-string@2.0.2)(type-fest@4.41.0)(typescript@4.9.4)(webpack-dev-server@5.2.3(webpack@5.104.1))(webpack-hot-middleware@2.26.1) '@types/classnames': specifier: 2.2.9 version: 2.2.9 @@ -2312,12 +2336,27 @@ importers: '@wso2/ui-toolkit': specifier: workspace:* version: link:../../common-libs/ui-toolkit + katex: + specifier: ^0.16.27 + version: 0.16.28 react: specifier: 18.2.0 version: 18.2.0 react-dom: specifier: 18.2.0 version: 18.2.0(react@18.2.0) + react-markdown: + specifier: ^10.1.0 + version: 10.1.0(@types/react@18.2.0)(react@18.2.0) + rehype-katex: + specifier: ^7.0.1 + version: 7.0.1 + remark-gfm: + specifier: ^4.0.1 + version: 4.0.1 + remark-math: + specifier: ^6.0.0 + version: 6.0.0 devDependencies: '@types/react': specifier: 18.2.0 @@ -2336,31 +2375,31 @@ importers: version: 2.4.1 css-loader: specifier: 7.1.2 - version: 7.1.2(webpack@5.99.9) + version: 7.1.2(webpack@5.104.1) sass-loader: specifier: 16.0.5 - version: 16.0.5(sass@1.89.0)(webpack@5.99.9) + version: 16.0.5(sass@1.89.0)(webpack@5.104.1) source-map-loader: specifier: 5.0.0 - version: 5.0.0(webpack@5.99.9) + version: 5.0.0(webpack@5.104.1) style-loader: specifier: 4.0.0 - version: 4.0.0(webpack@5.99.9) + version: 4.0.0(webpack@5.104.1) ts-loader: specifier: 9.5.2 - version: 9.5.2(typescript@5.8.3)(webpack@5.99.9) + version: 9.5.2(typescript@5.8.3)(webpack@5.104.1) typescript: specifier: 5.8.3 version: 5.8.3 webpack: - specifier: 5.99.9 - version: 5.99.9(webpack-cli@5.1.4) + specifier: 5.104.1 + version: 5.104.1(webpack-cli@5.1.4) webpack-cli: specifier: 5.1.4 - version: 5.1.4(webpack-dev-server@5.2.1)(webpack@5.99.9) + version: 5.1.4(webpack-dev-server@5.2.3)(webpack@5.104.1) webpack-dev-server: - specifier: 5.2.1 - version: 5.2.1(webpack-cli@5.1.4)(webpack@5.99.9) + specifier: 5.2.3 + version: 5.2.3(webpack-cli@5.1.4)(webpack@5.104.1) ../../workspaces/ballerina/type-diagram: dependencies: @@ -2368,11 +2407,11 @@ importers: specifier: 11.13.5 version: 11.13.5 '@emotion/react': - specifier: 11.9.3 - version: 11.9.3(@babel/core@7.27.1)(@types/react@18.2.0)(react@18.2.0) + specifier: 11.14.0 + version: 11.14.0(@types/react@18.2.0)(react@18.2.0) '@emotion/styled': specifier: 11.14.0 - version: 11.14.0(@emotion/react@11.9.3(@babel/core@7.27.1)(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0)(react@18.2.0) + version: 11.14.0(@emotion/react@11.14.0(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0)(react@18.2.0) '@projectstorm/geometry': specifier: 7.0.3 version: 7.0.3 @@ -2381,16 +2420,16 @@ importers: version: 7.0.3(@types/react@18.2.0) '@projectstorm/react-diagrams': specifier: 7.0.4 - version: 7.0.4(@emotion/react@11.9.3(@babel/core@7.27.1)(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0) + version: 7.0.4(@emotion/react@11.14.0(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0) '@projectstorm/react-diagrams-core': specifier: 7.0.3 - version: 7.0.3(@emotion/react@11.9.3(@babel/core@7.27.1)(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0) + version: 7.0.3(@emotion/react@11.14.0(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0) '@projectstorm/react-diagrams-defaults': specifier: 7.1.3 version: 7.1.3(@types/react@18.2.0) '@projectstorm/react-diagrams-routing': specifier: 7.1.3 - version: 7.1.3(@emotion/react@11.9.3(@babel/core@7.27.1)(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0) + version: 7.1.3(@emotion/react@11.14.0(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0) '@types/lodash': specifier: 4.17.16 version: 4.17.16 @@ -2405,7 +2444,7 @@ importers: version: 0.8.5 file-loader: specifier: 6.2.0 - version: 6.2.0(webpack@5.99.9) + version: 6.2.0(webpack@5.104.1) html-to-image: specifier: 1.11.11 version: 1.11.11 @@ -2454,31 +2493,31 @@ importers: version: link:../../common-libs/ui-toolkit babel-loader: specifier: 10.0.0 - version: 10.0.0(@babel/core@7.27.1)(webpack@5.99.9) + version: 10.0.0(@babel/core@7.27.1)(webpack@5.104.1) copyfiles: specifier: 2.4.1 version: 2.4.1 css-loader: specifier: 7.1.2 - version: 7.1.2(webpack@5.99.9) + version: 7.1.2(webpack@5.104.1) source-map-loader: specifier: 5.0.0 - version: 5.0.0(webpack@5.99.9) + version: 5.0.0(webpack@5.104.1) style-loader: specifier: 4.0.0 - version: 4.0.0(webpack@5.99.9) + version: 4.0.0(webpack@5.104.1) ts-loader: specifier: 9.4.1 - version: 9.4.1(typescript@5.8.3)(webpack@5.99.9) + version: 9.4.1(typescript@5.8.3)(webpack@5.104.1) webpack: - specifier: 5.99.9 - version: 5.99.9(webpack-cli@6.0.1) + specifier: 5.104.1 + version: 5.104.1(webpack-cli@6.0.1) webpack-cli: specifier: 6.0.1 - version: 6.0.1(webpack-dev-server@5.2.1)(webpack@5.99.9) + version: 6.0.1(webpack-dev-server@5.2.3)(webpack@5.104.1) webpack-dev-server: - specifier: 5.2.1 - version: 5.2.1(webpack-cli@6.0.1)(webpack@5.99.9) + specifier: 5.2.3 + version: 5.2.3(webpack-cli@6.0.1)(webpack@5.104.1) ../../workspaces/ballerina/type-editor: dependencies: @@ -2612,7 +2651,7 @@ importers: version: link:../../common-libs/playwright-vscode-tester copy-webpack-plugin: specifier: 13.0.0 - version: 13.0.0(webpack@5.99.9) + version: 13.0.0(webpack@5.104.1) copyfiles: specifier: 2.4.1 version: 2.4.1 @@ -2630,16 +2669,16 @@ importers: version: 0.5.21 ts-loader: specifier: 9.5.2 - version: 9.5.2(typescript@5.8.3)(webpack@5.99.9) + version: 9.5.2(typescript@5.8.3)(webpack@5.104.1) typescript: specifier: 5.8.3 version: 5.8.3 webpack: - specifier: 5.99.9 - version: 5.99.9(webpack-cli@6.0.1) + specifier: 5.104.1 + version: 5.104.1(webpack-cli@6.0.1) webpack-cli: specifier: 6.0.1 - version: 6.0.1(webpack@5.99.9) + version: 6.0.1(webpack@5.104.1) webpack-permissions-plugin: specifier: 1.0.9 version: 1.0.9 @@ -2751,11 +2790,11 @@ importers: specifier: workspace:* version: link:../../common-libs/playwright-vscode-tester axios: - specifier: 1.12.0 - version: 1.12.0 + specifier: 1.13.5 + version: 1.13.5 copy-webpack-plugin: specifier: 13.0.0 - version: 13.0.0(webpack@5.99.9) + version: 13.0.0(webpack@5.104.1) copyfiles: specifier: 2.4.1 version: 2.4.1 @@ -2767,10 +2806,10 @@ importers: version: 11.5.0 terser-webpack-plugin: specifier: 5.3.10 - version: 5.3.10(webpack@5.99.9) + version: 5.3.10(webpack@5.104.1) ts-loader: specifier: 9.5.2 - version: 9.5.2(typescript@5.8.3)(webpack@5.99.9) + version: 9.5.2(typescript@5.8.3)(webpack@5.104.1) typescript: specifier: 5.8.3 version: 5.8.3 @@ -2778,11 +2817,11 @@ importers: specifier: 8.14.1 version: 8.14.1(mocha@11.5.0)(typescript@5.8.3) webpack: - specifier: 5.99.9 - version: 5.99.9(webpack-cli@6.0.1) + specifier: 5.104.1 + version: 5.104.1(webpack-cli@6.0.1) webpack-cli: specifier: 6.0.1 - version: 6.0.1(webpack@5.99.9) + version: 6.0.1(webpack@5.104.1) webpack-permissions-plugin: specifier: 1.0.9 version: 1.0.9 @@ -2873,10 +2912,10 @@ importers: version: 2.4.1 css-loader: specifier: 7.1.2 - version: 7.1.2(webpack@5.99.9) + version: 7.1.2(webpack@5.104.1) file-loader: specifier: 6.2.0 - version: 6.2.0(webpack@5.99.9) + version: 6.2.0(webpack@5.104.1) path: specifier: 0.12.7 version: 0.12.7 @@ -2885,34 +2924,34 @@ importers: version: 8.5.4 postcss-loader: specifier: 8.1.1 - version: 8.1.1(postcss@8.5.4)(typescript@5.8.3)(webpack@5.99.9) + version: 8.1.1(postcss@8.5.4)(typescript@5.8.3)(webpack@5.104.1) sass-loader: specifier: 16.0.5 - version: 16.0.5(sass@1.89.0)(webpack@5.99.9) + version: 16.0.5(sass@1.89.0)(webpack@5.104.1) source-map-loader: specifier: 5.0.0 - version: 5.0.0(webpack@5.99.9) + version: 5.0.0(webpack@5.104.1) style-loader: specifier: 4.0.0 - version: 4.0.0(webpack@5.99.9) + version: 4.0.0(webpack@5.104.1) tailwindcss: specifier: 3.4.3 version: 3.4.3(ts-node@10.9.2(@swc/core@1.15.11(@swc/helpers@0.5.18))(@types/node@22.15.24)(typescript@5.8.3)) ts-loader: specifier: 9.5.2 - version: 9.5.2(typescript@5.8.3)(webpack@5.99.9) + version: 9.5.2(typescript@5.8.3)(webpack@5.104.1) typescript: specifier: 5.8.3 version: 5.8.3 webpack: - specifier: 5.99.9 - version: 5.99.9(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) + specifier: 5.104.1 + version: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) webpack-cli: specifier: 6.0.1 - version: 6.0.1(webpack-dev-server@5.2.1)(webpack@5.99.9) + version: 6.0.1(webpack-dev-server@5.2.3)(webpack@5.104.1) webpack-dev-server: - specifier: 5.2.1 - version: 5.2.1(webpack-cli@6.0.1)(webpack@5.99.9) + specifier: 5.2.3 + version: 5.2.3(webpack-cli@6.0.1)(webpack@5.104.1) ../../workspaces/common-libs/font-wso2-vscode: devDependencies: @@ -3060,11 +3099,11 @@ importers: specifier: 11.10.5 version: 11.10.5(@babel/core@7.29.0) '@emotion/react': - specifier: 11.9.3 - version: 11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@19.1.0) + specifier: 11.14.0 + version: 11.14.0(@types/react@18.2.0)(react@19.1.0) '@emotion/styled': - specifier: 11.10.5 - version: 11.10.5(@babel/core@7.29.0)(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@19.1.0))(@types/react@18.2.0)(react@19.1.0) + specifier: 11.14.0 + version: 11.14.0(@emotion/react@11.14.0(@types/react@18.2.0)(react@19.1.0))(@types/react@18.2.0)(react@19.1.0) '@headlessui/react': specifier: 1.7.18 version: 1.7.18(react-dom@19.1.0(react@19.1.0))(react@19.1.0) @@ -3079,10 +3118,10 @@ importers: version: 6.7.4(lodash@4.17.23)(react@19.1.0) '@projectstorm/react-diagrams': specifier: 6.7.4 - version: 6.7.4(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@19.1.0))(@emotion/styled@11.10.5(@babel/core@7.29.0)(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@19.1.0))(@types/react@18.2.0)(react@19.1.0))(dagre@0.8.5)(lodash@4.17.23)(pathfinding@0.4.18)(paths-js@0.4.11)(react@19.1.0)(resize-observer-polyfill@1.5.1) + version: 6.7.4(@emotion/react@11.14.0(@types/react@18.2.0)(react@19.1.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@18.2.0)(react@19.1.0))(@types/react@18.2.0)(react@19.1.0))(dagre@0.8.5)(lodash@4.17.23)(pathfinding@0.4.18)(paths-js@0.4.11)(react@19.1.0)(resize-observer-polyfill@1.5.1) '@projectstorm/react-diagrams-core': specifier: 7.0.3 - version: 7.0.3(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@19.1.0))(@types/react@18.2.0) + version: 7.0.3(@emotion/react@11.14.0(@types/react@18.2.0)(react@19.1.0))(@types/react@18.2.0) '@vscode/codicons': specifier: 0.0.44 version: 0.0.44 @@ -3207,7 +3246,7 @@ importers: version: 3.7.0 copy-webpack-plugin: specifier: 13.0.0 - version: 13.0.0(webpack@5.99.9) + version: 13.0.0(webpack@5.104.1) copyfiles: specifier: 2.4.1 version: 2.4.1 @@ -3225,16 +3264,16 @@ importers: version: 6.1.6 ts-loader: specifier: 9.5.2 - version: 9.5.2(typescript@5.8.3)(webpack@5.99.9) + version: 9.5.2(typescript@5.8.3)(webpack@5.104.1) typescript: specifier: 5.8.3 version: 5.8.3 webpack: - specifier: 5.99.9 - version: 5.99.9(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@5.1.4) + specifier: 5.104.1 + version: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@5.1.4) webpack-cli: specifier: 5.1.4 - version: 5.1.4(webpack@5.99.9) + version: 5.1.4(webpack@5.104.1) ../../workspaces/mi/mi-component-diagram: dependencies: @@ -3441,7 +3480,7 @@ importers: version: 2.4.1 css-loader: specifier: 7.1.2 - version: 7.1.2(webpack@5.103.0) + version: 7.1.2(webpack@5.104.1) eslint: specifier: ^9.27.0 version: 9.39.2(jiti@2.6.1) @@ -3453,13 +3492,13 @@ importers: version: 0.4.20(eslint@9.39.2(jiti@2.6.1)) file-loader: specifier: 6.2.0 - version: 6.2.0(webpack@5.103.0) + version: 6.2.0(webpack@5.104.1) react-hook-form: specifier: 7.56.4 version: 7.56.4(react@18.2.0) ts-loader: specifier: 9.5.2 - version: 9.5.2(typescript@5.8.3)(webpack@5.103.0) + version: 9.5.2(typescript@5.8.3)(webpack@5.104.1) ts-morph: specifier: 22.0.0 version: 22.0.0 @@ -3767,8 +3806,8 @@ importers: specifier: 5.0.76 version: 5.0.76(zod@4.1.11) axios: - specifier: 1.12.0 - version: 1.12.0 + specifier: 1.13.5 + version: 1.13.5 copyfiles: specifier: 2.4.1 version: 2.4.1 @@ -3813,7 +3852,7 @@ importers: version: 3.3.2 node-loader: specifier: 2.1.0 - version: 2.1.0(webpack@5.99.9) + version: 2.1.0(webpack@5.104.1) portfinder: specifier: 1.0.37 version: 1.0.37 @@ -3919,7 +3958,7 @@ importers: version: 6.0.1 ts-loader: specifier: 9.5.2 - version: 9.5.2(typescript@5.8.3)(webpack@5.99.9) + version: 9.5.2(typescript@5.8.3)(webpack@5.104.1) ts-morph: specifier: 26.0.0 version: 26.0.0 @@ -3927,11 +3966,11 @@ importers: specifier: 5.8.3 version: 5.8.3 webpack: - specifier: 5.99.9 - version: 5.99.9(webpack-cli@4.10.0) + specifier: 5.104.1 + version: 5.104.1(webpack-cli@4.10.0) webpack-cli: specifier: 4.10.0 - version: 4.10.0(webpack@5.99.9) + version: 4.10.0(webpack@5.104.1) yaml: specifier: 2.8.0 version: 2.8.0 @@ -4010,7 +4049,7 @@ importers: version: 1.55.1 '@pmmmwh/react-refresh-webpack-plugin': specifier: 0.6.0 - version: 0.6.0(@types/webpack@5.28.5(webpack-cli@5.1.4))(react-refresh@0.11.0)(type-fest@4.41.0)(webpack-dev-server@5.2.1)(webpack-hot-middleware@2.26.1)(webpack@5.99.9) + version: 0.6.0(@types/webpack@5.28.5(webpack-cli@5.1.4))(react-refresh@0.11.0)(type-fest@4.41.0)(webpack-dev-server@5.2.3)(webpack-hot-middleware@2.26.1)(webpack@5.104.1) '@tanstack/query-core': specifier: 5.76.0 version: 5.76.0 @@ -4170,19 +4209,19 @@ importers: version: 2.4.1 css-loader: specifier: 7.1.2 - version: 7.1.2(webpack@5.99.9) + version: 7.1.2(webpack@5.104.1) sass-loader: specifier: 16.0.5 - version: 16.0.5(sass@1.89.0)(webpack@5.99.9) + version: 16.0.5(sass@1.89.0)(webpack@5.104.1) source-map-loader: specifier: 5.0.0 - version: 5.0.0(webpack@5.99.9) + version: 5.0.0(webpack@5.104.1) style-loader: specifier: 4.0.0 - version: 4.0.0(webpack@5.99.9) + version: 4.0.0(webpack@5.104.1) ts-loader: specifier: 9.5.2 - version: 9.5.2(typescript@5.8.3)(webpack@5.99.9) + version: 9.5.2(typescript@5.8.3)(webpack@5.104.1) typescript: specifier: 5.8.3 version: 5.8.3 @@ -4190,14 +4229,14 @@ importers: specifier: 3.17.5 version: 3.17.5 webpack: - specifier: 5.99.9 - version: 5.99.9(webpack-cli@5.1.4) + specifier: 5.104.1 + version: 5.104.1(webpack-cli@5.1.4) webpack-cli: specifier: 5.1.4 - version: 5.1.4(webpack-dev-server@5.2.1)(webpack@5.99.9) + version: 5.1.4(webpack-dev-server@5.2.3)(webpack@5.104.1) webpack-dev-server: - specifier: 5.2.1 - version: 5.2.1(webpack-cli@5.1.4)(webpack@5.99.9) + specifier: 5.2.3 + version: 5.2.3(webpack-cli@5.1.4)(webpack@5.104.1) yaml: specifier: 2.8.0 version: 2.8.0 @@ -4367,11 +4406,11 @@ importers: specifier: workspace:* version: link:../../common-libs/playwright-vscode-tester axios: - specifier: 1.9.0 - version: 1.9.0 + specifier: 1.13.5 + version: 1.13.5 copy-webpack-plugin: specifier: 13.0.0 - version: 13.0.0(webpack@5.103.0) + version: 13.0.0(webpack@5.104.1) copyfiles: specifier: 2.4.1 version: 2.4.1 @@ -4383,10 +4422,10 @@ importers: version: 11.5.0 terser-webpack-plugin: specifier: 5.3.14 - version: 5.3.14(webpack@5.103.0) + version: 5.3.14(webpack@5.104.1) ts-loader: specifier: 9.5.4 - version: 9.5.4(typescript@5.8.3)(webpack@5.103.0) + version: 9.5.4(typescript@5.8.3)(webpack@5.104.1) typescript: specifier: 5.8.3 version: 5.8.3 @@ -4394,11 +4433,11 @@ importers: specifier: 8.14.1 version: 8.14.1(mocha@11.5.0)(typescript@5.8.3) webpack: - specifier: 5.103.0 - version: 5.103.0(webpack-cli@6.0.1) + specifier: 5.104.1 + version: 5.104.1(webpack-cli@6.0.1) webpack-cli: specifier: 6.0.1 - version: 6.0.1(webpack@5.103.0) + version: 6.0.1(webpack@5.104.1) webpack-permissions-plugin: specifier: 1.0.10 version: 1.0.10 @@ -4510,10 +4549,10 @@ importers: version: 2.4.1 css-loader: specifier: 7.1.2 - version: 7.1.2(webpack@5.99.9) + version: 7.1.2(webpack@5.104.1) file-loader: specifier: 6.2.0 - version: 6.2.0(webpack@5.99.9) + version: 6.2.0(webpack@5.104.1) path: specifier: 0.12.7 version: 0.12.7 @@ -4522,34 +4561,34 @@ importers: version: 8.5.3 postcss-loader: specifier: 8.1.1 - version: 8.1.1(postcss@8.5.3)(typescript@5.8.3)(webpack@5.99.9) + version: 8.1.1(postcss@8.5.3)(typescript@5.8.3)(webpack@5.104.1) sass-loader: specifier: 16.0.5 - version: 16.0.5(sass@1.89.0)(webpack@5.99.9) + version: 16.0.5(sass@1.89.0)(webpack@5.104.1) source-map-loader: specifier: 5.0.0 - version: 5.0.0(webpack@5.99.9) + version: 5.0.0(webpack@5.104.1) style-loader: specifier: 4.0.0 - version: 4.0.0(webpack@5.99.9) + version: 4.0.0(webpack@5.104.1) tailwindcss: specifier: 4.1.7 version: 4.1.7 ts-loader: specifier: 9.5.2 - version: 9.5.2(typescript@5.8.3)(webpack@5.99.9) + version: 9.5.2(typescript@5.8.3)(webpack@5.104.1) typescript: specifier: 5.8.3 version: 5.8.3 webpack: - specifier: 5.99.9 - version: 5.99.9(webpack-cli@6.0.1) + specifier: 5.104.1 + version: 5.104.1(webpack-cli@6.0.1) webpack-cli: specifier: 6.0.1 - version: 6.0.1(webpack-dev-server@5.2.1)(webpack@5.99.9) + version: 6.0.1(webpack-dev-server@5.2.3)(webpack@5.104.1) webpack-dev-server: - specifier: 5.2.1 - version: 5.2.1(webpack-cli@6.0.1)(webpack@5.99.9) + specifier: 5.2.3 + version: 5.2.3(webpack-cli@6.0.1)(webpack@5.104.1) packages: @@ -4819,16 +4858,16 @@ packages: resolution: {integrity: sha512-fCqPIfOcLE+CGqGPd66c8bZpwAji98tZ4JI9i/mlTNTlsIWslCfpg48s/ypyLxZTump5sypjrKn2/kY7q8oAbA==} engines: {node: '>=20.0.0'} - '@azure/msal-browser@4.28.1': - resolution: {integrity: sha512-al2u2fTchbClq3L4C1NlqLm+vwKfhYCPtZN2LR/9xJVaQ4Mnrwf5vANvuyPSJHcGvw50UBmhuVmYUAhTEetTpA==} + '@azure/msal-browser@4.28.2': + resolution: {integrity: sha512-6vYUMvs6kJxJgxaCmHn/F8VxjLHNh7i9wzfwPGf8kyBJ8Gg2yvBXx175Uev8LdrD1F5C4o7qHa2CC4IrhGE1XQ==} engines: {node: '>=0.8.0'} - '@azure/msal-common@15.14.1': - resolution: {integrity: sha512-IkzF7Pywt6QKTS0kwdCv/XV8x8JXknZDvSjj/IccooxnP373T5jaadO3FnOrbWo3S0UqkfIDyZNTaQ/oAgRdXw==} + '@azure/msal-common@15.14.2': + resolution: {integrity: sha512-n8RBJEUmd5QotoqbZfd+eGBkzuFI1KX6jw2b3WcpSyGjwmzoeI/Jb99opIBPHpb8y312NB+B6+FGi2ZVSR8yfA==} engines: {node: '>=0.8.0'} - '@azure/msal-node@3.8.6': - resolution: {integrity: sha512-XTmhdItcBckcVVTy65Xp+42xG4LX5GK+9AqAsXPXk4IqUNv+LyQo5TMwNjuFYBfAB2GTG9iSQGk+QLc03vhf3w==} + '@azure/msal-node@3.8.7': + resolution: {integrity: sha512-a+Xnrae+uwLnlw68bplS1X4kuJ9F/7K6afuMFyRkNIskhjgDezl5Fhrx+1pmAlDmC0VaaAxjRQMp1OmcqVwkIg==} engines: {node: '>=16'} '@babel/code-frame@7.10.4': @@ -5717,8 +5756,8 @@ packages: '@cacheable/memory@2.0.7': resolution: {integrity: sha512-RbxnxAMf89Tp1dLhXMS7ceft/PGsDl1Ip7T20z5nZ+pwIAsQ1p2izPjVG69oCLv/jfQ7HDPHTWK0c9rcAWXN3A==} - '@cacheable/utils@2.3.3': - resolution: {integrity: sha512-JsXDL70gQ+1Vc2W/KUFfkAJzgb4puKwwKehNLuB+HrNKWf91O736kGfxn4KujXCCSuh6mRRL4XEB0PkAFjWS0A==} + '@cacheable/utils@2.3.4': + resolution: {integrity: sha512-knwKUJEYgIfwShABS1BX6JyJJTglAFcEU7EXqzTdiGCXur4voqkiJkdgZIQtWNFhynzDWERcTYv/sETMu3uJWA==} '@cnakazawa/watch@1.0.4': resolution: {integrity: sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ==} @@ -5893,6 +5932,28 @@ packages: resolution: {integrity: sha512-4B4OijXeVNOPZlYA2oEwWOTkzyltLao+xbotHQeqN++Rv27Y6s818+n2Qkp8q+Fxhn0t/5lA5X1Mxktud8eayQ==} engines: {node: '>=14.17.0'} + '@dnd-kit/accessibility@3.1.1': + resolution: {integrity: sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==} + peerDependencies: + react: '>=16.8.0' + + '@dnd-kit/core@6.1.0': + resolution: {integrity: sha512-J3cQBClB4TVxwGo3KEjssGEXNJqGVWx17aRTZ1ob0FliR5IjYgTxl5YJbKTzA6IzrtelotH19v6y7uoIRUZPSg==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@dnd-kit/sortable@8.0.0': + resolution: {integrity: sha512-U3jk5ebVXe1Lr7c2wU7SBZjcWdQP+j7peHJfCspnA81enlu88Mgd7CC8Q+pub9ubP7eKVETzJW+IBAhsqbSu/g==} + peerDependencies: + '@dnd-kit/core': ^6.1.0 + react: '>=16.8.0' + + '@dnd-kit/utilities@3.2.2': + resolution: {integrity: sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg==} + peerDependencies: + react: '>=16.8.0' + '@dual-bundle/import-meta-resolve@4.2.1': resolution: {integrity: sha512-id+7YRUgoUX6CgV0DtuhirQWodeeA7Lf4i2x71JS/vtA5pRb/hIGWlw+G6MeXvsM+MXrz0VAydTGElX1rAfgPg==} @@ -6679,14 +6740,6 @@ packages: '@iarna/toml@2.2.5': resolution: {integrity: sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==} - '@isaacs/balanced-match@4.0.1': - resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} - engines: {node: 20 || >=22} - - '@isaacs/brace-expansion@5.0.1': - resolution: {integrity: sha512-WMz71T1JS624nWj2n2fnYAuPovhv7EUhk69R6i9dsVyzxt5eM3bjwvgk9L+APE1TRscGysAVMANkB0jh0LQZrQ==} - engines: {node: 20 || >=22} - '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} @@ -6967,8 +7020,8 @@ packages: peerDependencies: tslib: '2' - '@jsonjoy.com/base64@17.65.0': - resolution: {integrity: sha512-Xrh7Fm/M0QAYpekSgmskdZYnFdSGnsxJ/tHaolA4bNwWdG9i65S8m83Meh7FOxyJyQAdo4d4J97NOomBLEfkDQ==} + '@jsonjoy.com/base64@17.67.0': + resolution: {integrity: sha512-5SEsJGsm15aP8TQGkDfJvz9axgPwAEm98S5DxOuYe8e1EbfajcDmgeXXzccEjh+mLnjqEKrkBdjHWS5vFNwDdw==} engines: {node: '>=10.0'} peerDependencies: tslib: '2' @@ -6979,8 +7032,8 @@ packages: peerDependencies: tslib: '2' - '@jsonjoy.com/buffers@17.65.0': - resolution: {integrity: sha512-eBrIXd0/Ld3p9lpDDlMaMn6IEfWqtHMD+z61u0JrIiPzsV1r7m6xDZFRxJyvIFTEO+SWdYF9EiQbXZGd8BzPfA==} + '@jsonjoy.com/buffers@17.67.0': + resolution: {integrity: sha512-tfExRpYxBvi32vPs9ZHaTjSP4fHAfzSmcahOfNxtvGHcyJel+aibkPlGeBB+7AoC6hL7lXIE++8okecBxx7lcw==} engines: {node: '>=10.0'} peerDependencies: tslib: '2' @@ -6991,8 +7044,8 @@ packages: peerDependencies: tslib: '2' - '@jsonjoy.com/codegen@17.65.0': - resolution: {integrity: sha512-7MXcRYe7n3BG+fo3jicvjB0+6ypl2Y/bQp79Sp7KeSiiCgLqw4Oled6chVv07/xLVTdo3qa1CD0VCCnPaw+RGA==} + '@jsonjoy.com/codegen@17.67.0': + resolution: {integrity: sha512-idnkUplROpdBOV0HMcwhsCUS5TRUi9poagdGs70A6S4ux9+/aPuKbh8+UYRTLYQHtXvAdNfQWXDqZEx5k4Dj2Q==} engines: {node: '>=10.0'} peerDependencies: tslib: '2' @@ -7051,8 +7104,8 @@ packages: peerDependencies: tslib: '2' - '@jsonjoy.com/json-pack@17.65.0': - resolution: {integrity: sha512-e0SG/6qUCnVhHa0rjDJHgnXnbsacooHVqQHxspjvlYQSkHm+66wkHw6Gql+3u/WxI/b1VsOdUi0M+fOtkgKGdQ==} + '@jsonjoy.com/json-pack@17.67.0': + resolution: {integrity: sha512-t0ejURcGaZsn1ClbJ/3kFqSOjlryd92eQY465IYrezsXmPcfHPE/av4twRSxf6WE+TkZgLY+71vCZbiIiFKA/w==} engines: {node: '>=10.0'} peerDependencies: tslib: '2' @@ -7063,8 +7116,8 @@ packages: peerDependencies: tslib: '2' - '@jsonjoy.com/json-pointer@17.65.0': - resolution: {integrity: sha512-uhTe+XhlIZpWOxgPcnO+iSCDgKKBpwkDVTyYiXX9VayGV8HSFVJM67M6pUE71zdnXF1W0Da21AvnhlmdwYPpow==} + '@jsonjoy.com/json-pointer@17.67.0': + resolution: {integrity: sha512-+iqOFInH+QZGmSuaybBUNdh7yvNrXvqR+h3wjXm0N/3JK1EyyFAeGJvqnmQL61d1ARLlk/wJdFKSL+LHJ1eaUA==} engines: {node: '>=10.0'} peerDependencies: tslib: '2' @@ -7075,8 +7128,8 @@ packages: peerDependencies: tslib: '2' - '@jsonjoy.com/util@17.65.0': - resolution: {integrity: sha512-cWiEHZccQORf96q2y6zU3wDeIVPeidmGqd9cNKJRYoVHTV0S1eHPy5JTbHpMnGfDvtvujQwQozOqgO9ABu6h0w==} + '@jsonjoy.com/util@17.67.0': + resolution: {integrity: sha512-6+8xBaz1rLSohlGh68D1pdw3AwDi9xydm8QNlAFkvnavCJYSze+pxoW2VKP8p308jtlMRLs5NTHfPlZLd4w7ew==} engines: {node: '>=10.0'} peerDependencies: tslib: '2' @@ -7382,6 +7435,10 @@ packages: '@nevware21/ts-utils@0.12.6': resolution: {integrity: sha512-UsS1hbgr/V/x8dT7hVHvr/PwHzASi8/Itis1+L8ykLiqsUXdfzrB1maL0vMmKbDEJpmGARsoC/7RIswi+n248Q==} + '@noble/hashes@1.4.0': + resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==} + engines: {node: '>= 16'} + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -7520,6 +7577,40 @@ packages: resolution: {integrity: sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==} engines: {node: '>= 10.0.0'} + '@peculiar/asn1-cms@2.6.1': + resolution: {integrity: sha512-vdG4fBF6Lkirkcl53q6eOdn3XYKt+kJTG59edgRZORlg/3atWWEReRCx5rYE1ZzTTX6vLK5zDMjHh7vbrcXGtw==} + + '@peculiar/asn1-csr@2.6.1': + resolution: {integrity: sha512-WRWnKfIocHyzFYQTka8O/tXCiBquAPSrRjXbOkHbO4qdmS6loffCEGs+rby6WxxGdJCuunnhS2duHURhjyio6w==} + + '@peculiar/asn1-ecc@2.6.1': + resolution: {integrity: sha512-+Vqw8WFxrtDIN5ehUdvlN2m73exS2JVG0UAyfVB31gIfor3zWEAQPD+K9ydCxaj3MLen9k0JhKpu9LqviuCE1g==} + + '@peculiar/asn1-pfx@2.6.1': + resolution: {integrity: sha512-nB5jVQy3MAAWvq0KY0R2JUZG8bO/bTLpnwyOzXyEh/e54ynGTatAR+csOnXkkVD9AFZ2uL8Z7EV918+qB1qDvw==} + + '@peculiar/asn1-pkcs8@2.6.1': + resolution: {integrity: sha512-JB5iQ9Izn5yGMw3ZG4Nw3Xn/hb/G38GYF3lf7WmJb8JZUydhVGEjK/ZlFSWhnlB7K/4oqEs8HnfFIKklhR58Tw==} + + '@peculiar/asn1-pkcs9@2.6.1': + resolution: {integrity: sha512-5EV8nZoMSxeWmcxWmmcolg22ojZRgJg+Y9MX2fnE2bGRo5KQLqV5IL9kdSQDZxlHz95tHvIq9F//bvL1OeNILw==} + + '@peculiar/asn1-rsa@2.6.1': + resolution: {integrity: sha512-1nVMEh46SElUt5CB3RUTV4EG/z7iYc7EoaDY5ECwganibQPkZ/Y2eMsTKB/LeyrUJ+W/tKoD9WUqIy8vB+CEdA==} + + '@peculiar/asn1-schema@2.6.0': + resolution: {integrity: sha512-xNLYLBFTBKkCzEZIw842BxytQQATQv+lDTCEMZ8C196iJcJJMBUZxrhSTxLaohMyKK8QlzRNTRkUmanucnDSqg==} + + '@peculiar/asn1-x509-attr@2.6.1': + resolution: {integrity: sha512-tlW6cxoHwgcQghnJwv3YS+9OO1737zgPogZ+CgWRUK4roEwIPzRH4JEiG770xe5HX2ATfCpmX60gurfWIF9dcQ==} + + '@peculiar/asn1-x509@2.6.1': + resolution: {integrity: sha512-O9jT5F1A2+t3r7C4VT7LYGXqkGLK7Kj1xFpz7U0isPrubwU5PbDoyYtx6MiGst29yq7pXN5vZbQFKRCP+lLZlA==} + + '@peculiar/x509@1.14.3': + resolution: {integrity: sha512-C2Xj8FZ0uHWeCXXqX5B4/gVFQmtSkiuOolzAgutjTfseNOHT3pUjljDZsTSxXFGgio54bCzVFqmEOUrIVk8RDA==} + engines: {node: '>=20.0.0'} + '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} @@ -8836,8 +8927,8 @@ packages: resolution: {integrity: sha512-qJpzYC64kaj3S0fueiu3kXm8xPrR3PcXDPEgnaNMRn0EjNSZFoFjvbUp0YUDsRhN1CB90EnHJtbxWKevnH99UQ==} engines: {node: '>=18.0.0'} - '@smithy/core@3.22.1': - resolution: {integrity: sha512-x3ie6Crr58MWrm4viHqqy2Du2rHYZjwu8BekasrQx4ca+Y24dzVAwq3yErdqIbc2G3I0kLQA13PQ+/rde+u65g==} + '@smithy/core@3.23.0': + resolution: {integrity: sha512-Yq4UPVoQICM9zHnByLmG8632t2M0+yap4T7ANVw482J0W7HW0pOuxwVmeOwzJqX2Q89fkXz0Vybz55Wj2Xzrsg==} engines: {node: '>=18.0.0'} '@smithy/credential-provider-imds@4.2.8': @@ -8900,12 +8991,12 @@ packages: resolution: {integrity: sha512-RO0jeoaYAB1qBRhfVyq0pMgBoUK34YEJxVxyjOWYZiOKOq2yMZ4MnVXMZCUDenpozHue207+9P5ilTV1zeda0A==} engines: {node: '>=18.0.0'} - '@smithy/middleware-endpoint@4.4.13': - resolution: {integrity: sha512-x6vn0PjYmGdNuKh/juUJJewZh7MoQ46jYaJ2mvekF4EesMuFfrl4LaW/k97Zjf8PTCPQmPgMvwewg7eNoH9n5w==} + '@smithy/middleware-endpoint@4.4.14': + resolution: {integrity: sha512-FUFNE5KVeaY6U/GL0nzAAHkaCHzXLZcY1EhtQnsAqhD8Du13oPKtMB9/0WK4/LK6a/T5OZ24wPoSShff5iI6Ag==} engines: {node: '>=18.0.0'} - '@smithy/middleware-retry@4.4.30': - resolution: {integrity: sha512-CBGyFvN0f8hlnqKH/jckRDz78Snrp345+PVk8Ux7pnkUCW97Iinse59lY78hBt04h1GZ6hjBN94BRwZy1xC8Bg==} + '@smithy/middleware-retry@4.4.31': + resolution: {integrity: sha512-RXBzLpMkIrxBPe4C8OmEOHvS8aH9RUuCOH++Acb5jZDEblxDjyg6un72X9IcbrGTJoiUwmI7hLypNfuDACypbg==} engines: {node: '>=18.0.0'} '@smithy/middleware-serde@4.2.9': @@ -8920,8 +9011,8 @@ packages: resolution: {integrity: sha512-aFP1ai4lrbVlWjfpAfRSL8KFcnJQYfTl5QxLJXY32vghJrDuFyPZ6LtUL+JEGYiFRG1PfPLHLoxj107ulncLIg==} engines: {node: '>=18.0.0'} - '@smithy/node-http-handler@4.4.9': - resolution: {integrity: sha512-KX5Wml5mF+luxm1szW4QDz32e3NObgJ4Fyw+irhph4I/2geXwUy4jkIMUs5ZPGflRBeR6BUkC2wqIab4Llgm3w==} + '@smithy/node-http-handler@4.4.10': + resolution: {integrity: sha512-u4YeUwOWRZaHbWaebvrs3UhwQwj+2VNmcVCwXcYTvPIuVyM7Ex1ftAj+fdbG/P4AkBwLq/+SKn+ydOI4ZJE9PA==} engines: {node: '>=18.0.0'} '@smithy/property-provider@4.2.8': @@ -8952,8 +9043,8 @@ packages: resolution: {integrity: sha512-6A4vdGj7qKNRF16UIcO8HhHjKW27thsxYci+5r/uVRkdcBEkOEiY8OMPuydLX4QHSrJqGHPJzPRwwVTqbLZJhg==} engines: {node: '>=18.0.0'} - '@smithy/smithy-client@4.11.2': - resolution: {integrity: sha512-SCkGmFak/xC1n7hKRsUr6wOnBTJ3L22Qd4e8H1fQIuKTAjntwgU8lrdMe7uHdiT2mJAOWA/60qaW9tiMu69n1A==} + '@smithy/smithy-client@4.11.3': + resolution: {integrity: sha512-Q7kY5sDau8OoE6Y9zJoRGgje8P4/UY0WzH8R2ok0PDh+iJ+ZnEKowhjEqYafVcubkbYxQVaqwm3iufktzhprGg==} engines: {node: '>=18.0.0'} '@smithy/types@4.12.0': @@ -8988,12 +9079,12 @@ packages: resolution: {integrity: sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q==} engines: {node: '>=18.0.0'} - '@smithy/util-defaults-mode-browser@4.3.29': - resolution: {integrity: sha512-nIGy3DNRmOjaYaaKcQDzmWsro9uxlaqUOhZDHQed9MW/GmkBZPtnU70Pu1+GT9IBmUXwRdDuiyaeiy9Xtpn3+Q==} + '@smithy/util-defaults-mode-browser@4.3.30': + resolution: {integrity: sha512-cMni0uVU27zxOiU8TuC8pQLC1pYeZ/xEMxvchSK/ILwleRd1ugobOcIRr5vXtcRqKd4aBLWlpeBoDPJJ91LQng==} engines: {node: '>=18.0.0'} - '@smithy/util-defaults-mode-node@4.2.32': - resolution: {integrity: sha512-7dtFff6pu5fsjqrVve0YMhrnzJtccCWDacNKOkiZjJ++fmjGExmmSu341x+WU6Oc1IccL7lDuaUj7SfrHpWc5Q==} + '@smithy/util-defaults-mode-node@4.2.33': + resolution: {integrity: sha512-LEb2aq5F4oZUSzWBG7S53d4UytZSkOEJPXcBq/xbG2/TmK9EW5naUZ8lKu1BEyWMzdHIzEVN16M3k8oxDq+DJA==} engines: {node: '>=18.0.0'} '@smithy/util-endpoints@3.2.8': @@ -9012,8 +9103,8 @@ packages: resolution: {integrity: sha512-CfJqwvoRY0kTGe5AkQokpURNCT1u/MkRzMTASWMPPo2hNSnKtF1D45dQl3DE2LKLr4m+PW9mCeBMJr5mCAVThg==} engines: {node: '>=18.0.0'} - '@smithy/util-stream@4.5.11': - resolution: {integrity: sha512-lKmZ0S/3Qj2OF5H1+VzvDLb6kRxGzZHq6f3rAsoSu5cTLGsn3v3VQBA8czkNNXlLjoFEtVu3OQT2jEeOtOE2CA==} + '@smithy/util-stream@4.5.12': + resolution: {integrity: sha512-D8tgkrmhAX/UNeCZbqbEO3uqyghUnEmmoO9YEvRuwxjlkKKUE7FOgCJnqpTlQPe9MApdWPky58mNQQHbnCzoNg==} engines: {node: '>=18.0.0'} '@smithy/util-uri-escape@4.2.0': @@ -11044,6 +11135,9 @@ packages: '@types/jsonfile@6.1.4': resolution: {integrity: sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==} + '@types/katex@0.16.8': + resolution: {integrity: sha512-trgaNyfU+Xh2Tc+ABIb44a5AYUpicB3uwirOioeOkNPPbmgRNtcWyDeeFRzjPZENO9Vq8gvVqfhaaXWLlevVwg==} + '@types/linkify-it@5.0.0': resolution: {integrity: sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==} @@ -11140,9 +11234,6 @@ packages: '@types/node-fetch@2.6.13': resolution: {integrity: sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==} - '@types/node-forge@1.3.14': - resolution: {integrity: sha512-mhVF2BnD4BO+jtOp7z1CdzaK4mbuK0LLQYAvdOLqHTavxFNq4zA1EmYkpnFjP8HOUzedfQkRnp0E2ulSAYSzAw==} - '@types/node@14.18.63': resolution: {integrity: sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==} @@ -11194,8 +11285,8 @@ packages: '@types/pretty-hrtime@1.0.3': resolution: {integrity: sha512-nj39q0wAIdhwn7DGUyT9irmsKK1tV0bd5WFEhgpqNTMFZ8cE+jieuTphCW0tfdm47S2zVT5mr09B28b1chmQMA==} - '@types/prismjs@1.26.5': - resolution: {integrity: sha512-AUZTa7hQ2KY5L7AmtSiqxlhWxb4ina0yd8hNbl4TWuqnv/pFP0nDMb3YrfSBf4hJVGLh2YEIBfKaBW/9UEl6IQ==} + '@types/prismjs@1.26.6': + resolution: {integrity: sha512-vqlvI7qlMvcCBbVe0AKAb4f97//Hy0EBTaiW8AalRnG/xAN5zOiWWyrNqNXeq8+KAuvRewjCVY1+IPxk4RdNYw==} '@types/prop-types@15.7.15': resolution: {integrity: sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==} @@ -11372,9 +11463,6 @@ packages: '@types/vscode@1.81.0': resolution: {integrity: sha512-YIaCwpT+O2E7WOMq0eCgBEABE++SX3Yl/O02GoMIF2DO3qAtvw7m6BXFYsxnc6XyzwZgh6/s/UG78LSSombl2w==} - '@types/vscode@1.83.1': - resolution: {integrity: sha512-BHu51NaNKOtDf3BOonY3sKFFmZKEpRkzqkZVpSYxowLbs5JqjOQemYFob7Gs5rpxE5tiGhfpnMpcdF/oKrLg4w==} - '@types/vscode@1.84.0': resolution: {integrity: sha512-lCGOSrhT3cL+foUEqc8G1PVZxoDbiMmxgnUZZTEnHF4mC47eKAUtBGAuMLY6o6Ua8PAuNCoKXbqPmJd1JYnQfg==} @@ -12500,6 +12588,10 @@ packages: asn1@0.2.6: resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==} + asn1js@3.0.7: + resolution: {integrity: sha512-uLvq6KJu04qoQM6gvBfKFjlh6Gl0vOKQuR5cJMDHQkmwfMOQeN3F3SHCv9SNYSL+CRoHvOGFfllDlVz03GQjvQ==} + engines: {node: '>=12.0.0'} + assert-plus@1.0.0: resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==} engines: {node: '>=0.8'} @@ -12626,14 +12718,8 @@ packages: resolution: {integrity: sha512-BASOg+YwO2C+346x3LZOeoovTIoTrRqEsqMa6fmfAV0P+U9mFr9NsyOEpiYvFjbc64NMrSswhV50WdXzdb/Z5A==} engines: {node: '>=4'} - axios@1.12.0: - resolution: {integrity: sha512-oXTDccv8PcfjZmPGlWsPSwtOJCZ/b6W5jAMCNcfwJbCzDckwG0jrYJFaWH1yvivfCXjVzV/SPDEhMB3Q+DSurg==} - - axios@1.13.4: - resolution: {integrity: sha512-1wVkUaAO6WyaYtCkcYCOx12ZgpGf9Zif+qXa4n+oYzK558YryKqiL6UWwd5DqiH3VRW0GYhTZQ/vlgJrCoNQlg==} - - axios@1.9.0: - resolution: {integrity: sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==} + axios@1.13.5: + resolution: {integrity: sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==} axobject-query@4.1.0: resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} @@ -13070,6 +13156,10 @@ packages: balanced-match@2.0.0: resolution: {integrity: sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==} + balanced-match@4.0.2: + resolution: {integrity: sha512-x0K50QvKQ97fdEz2kPehIerj+YTeptKF9hyYkKf6egnwmMWAkADiO0QCzSp0R5xN8FTZgYaBfSaue46Ej62nMg==} + engines: {node: 20 || >=22} + base16@1.0.0: resolution: {integrity: sha512-pNdYkNPiJUnEhnfXV56+sQy8+AaPcG3POZAUnwr4EeqCUZFz4u2PePbo3e5Gj4ziYPCWGUZT9RHisvJKnwFuBQ==} @@ -13174,8 +13264,8 @@ packages: boundary@2.0.0: resolution: {integrity: sha512-rJKn5ooC9u8q13IMCrW0RSp31pxBCHE3y9V/tp3TdWSLf8Em3p6Di4NBpfzbJge9YjjFEsD0RtFEjtvHL5VyEA==} - bowser@2.13.1: - resolution: {integrity: sha512-OHawaAbjwx6rqICCKgSG0SAnT05bzd7ppyKLVUITZpANBaaMFBAsaNkto3LoQ31tyFP5kNujE8Cdx85G9VzOkw==} + bowser@2.14.1: + resolution: {integrity: sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==} boxen@1.3.0: resolution: {integrity: sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==} @@ -13202,6 +13292,10 @@ packages: brace-expansion@2.0.2: resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + brace-expansion@5.0.2: + resolution: {integrity: sha512-Pdk8c9poy+YhOgVWw1JNN22/HcivgKWwpxKq04M/jTmHyCZn12WPJebZxdjSa5TmBqISrUSgNYU3eRORljfCCw==} + engines: {node: 20 || >=22} + braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} @@ -13354,6 +13448,10 @@ packages: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} + bytestreamjs@2.0.1: + resolution: {integrity: sha512-U1Z/ob71V/bXfVABvNr/Kumf5VyeQRBEm6Txb0PQ6S7V5GpBM3w4Cbqz/xPDicR5tN0uvDifng8C+5qECeGwyQ==} + engines: {node: '>=6.0.0'} + c8@10.1.3: resolution: {integrity: sha512-LvcyrOAaOnrrlMpW22n690PUvxiq4Uf9WMhQwNJ9vgagkL/ph1+D4uvjvDA5XCbykrc0sx+ay6pVi9YZ1GnhyA==} engines: {node: '>=18'} @@ -13472,11 +13570,11 @@ packages: caniuse-api@3.0.0: resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==} - caniuse-db@1.0.30001768: - resolution: {integrity: sha512-hbETk3toYOs+9qGqR0x4Bz4lKFRs6UD9zc4iUtRNwWJ3tRGkFcBxGM/UocIhPFMwA15s1zmtQMgyjo6auN+OTw==} + caniuse-db@1.0.30001769: + resolution: {integrity: sha512-YUJlOqWziYAdXSnL60FU2Won9HqW/IY77M8xgDFMRj5+StEnycCnlKvORrMPAevdyfYd8W6pjQ2XaEiMyDocWA==} - caniuse-lite@1.0.30001768: - resolution: {integrity: sha512-qY3aDRZC5nWPgHUgIB84WL+nySuo19wk0VJpp/XI9T34lrvkyhRvNVOFJOp2kxClQhiFBu+TaUSudf6oa3vkSA==} + caniuse-lite@1.0.30001769: + resolution: {integrity: sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg==} canvas@3.2.1: resolution: {integrity: sha512-ej1sPFR5+0YWtaVp6S1N1FVz69TQCqmrkGeRvQxZeAB1nAIcjNTHVwrZtYtWFFBmQsF40/uDLehsW5KuYC99mg==} @@ -13734,8 +13832,8 @@ packages: resolution: {integrity: sha512-5mOlNS0mhX0707P2I0aZ2V/cmHUEO/fL7VFLqszkhUsxt7RwnmrInf/eEQKlf5GzvYeHIjT+Ov1HRfNmymlG0w==} engines: {node: '>=18'} - clipboardy@5.2.1: - resolution: {integrity: sha512-RWp4E/ivQAzgF4QSWA9sjeW+Bjo+U2SvebkDhNIfO7y65eGdXPUxMTdIKYsn+bxM3ItPHGm3e68Bv3fgQ3mARw==} + clipboardy@5.3.0: + resolution: {integrity: sha512-EOei1RJTbqXbXhUBMGN8C/Pf+QIPrnDWx9ztlmcW5Hljqj/oVlPrlrDw2O4xh5ViHcvHX3+A0zBrCdcptKTaJA==} engines: {node: '>=20'} cliui@2.1.0: @@ -13820,8 +13918,8 @@ packages: codemirror: ^5.65.3 graphql: ^15.5.0 || ^16.0.0 || ^17.0.0 - codemirror@5.65.20: - resolution: {integrity: sha512-i5dLDDxwkFCbhjvL2pNjShsojoL3XHyDwsGv1jqETUoW+lzpBKKqNTUWgQwVAOa0tUm4BwekT455ujafi8payA==} + codemirror@5.65.21: + resolution: {integrity: sha512-6teYk0bA0nR3QP0ihGMoxuKzpl5W80FpnHpBJpgy66NK3cZv5b/d/HY8PnRvfSsCG1MTfr92u2WUl+wT0E40mQ==} codemirror@6.0.2: resolution: {integrity: sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw==} @@ -14243,9 +14341,9 @@ packages: peerDependencies: postcss: ^8.0.9 - css-functions-list@3.2.3: - resolution: {integrity: sha512-IQOkD3hbR5KrN93MtcYuad6YPuTSUhntLHDuLEbFWE+ff2/XSZNdZG+LcbbIW5AXKg/WFIfYItIzVoHngHXZzA==} - engines: {node: '>=12 || >=16'} + css-functions-list@3.3.3: + resolution: {integrity: sha512-8HFEBPKhOpJPEPu70wJJetjKta86Gw9+CCyCnB3sui2qQfOvRyqBy4IKLKKAwdMpWb2lHXWk9Wb4Z6AmaUT1Pg==} + engines: {node: '>=12'} css-loader@0.28.7: resolution: {integrity: sha512-GxMpax8a/VgcfRrVy0gXD6yLd5ePYbXX/5zGgTVYp4wXtJklS8Z2VaUArJgc//f6/Dzil7BaJObdSv8eKKCPgg==} @@ -14275,8 +14373,8 @@ packages: webpack: optional: true - css-loader@7.1.2: - resolution: {integrity: sha512-6WvYYn7l/XEGN8Xu2vWFt9nVzrCn39vKyTEFf/ExEyoksJjjSZV/0/35XPlMbpnr6VGhZIUg5yJrL8tGfes/FA==} + css-loader@7.1.3: + resolution: {integrity: sha512-frbERmjT0UC5lMheWpJmMilnt9GEhbZJN/heUb7/zaJYeIzj5St9HvDcfshzzOqbsS+rYpMk++2SD3vGETDSyA==} engines: {node: '>= 18.12.0'} peerDependencies: '@rspack/core': 0.x || 1.x @@ -15052,6 +15150,9 @@ packages: es-module-lexer@1.7.0: resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + es-module-lexer@2.0.0: + resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==} + es-object-atoms@1.1.1: resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} engines: {node: '>= 0.4'} @@ -15655,10 +15756,6 @@ packages: resolution: {integrity: sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==} engines: {node: '>=4'} - figures@3.2.0: - resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} - engines: {node: '>=8'} - figures@6.1.0: resolution: {integrity: sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==} engines: {node: '>=18'} @@ -15815,8 +15912,8 @@ packages: resolution: {integrity: sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg==} deprecated: flatten is deprecated in favor of utility frameworks such as lodash. - flow-parser@0.299.0: - resolution: {integrity: sha512-phGMRoNt6SNglPHGRbCyWm9/pxfe6t/t4++EIYPaBGWT6e0lphLBgUMrvpL62NbRo9R549o3oqrbKHq82kANCw==} + flow-parser@0.301.0: + resolution: {integrity: sha512-yKRjJzN+W9dwk1tU9u6gowANdgFZyYknokcLePyLe30AV6WzAquKJzx+smN9wovWMBE2hvCDUvKbXUpcT1+8OA==} engines: {node: '>=0.4.0'} flush-write-stream@1.1.1: @@ -15923,6 +16020,20 @@ packages: fraction.js@4.3.7: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} + framer-motion@11.18.2: + resolution: {integrity: sha512-5F5Och7wrvtLVElIpclDT0CBzMVg3dL22B64aZwHtsIY8RB4mXICLrkajK4G9R+ieSAGcgrLeae2SeUTg2pr6w==} + peerDependencies: + '@emotion/is-prop-valid': '*' + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@emotion/is-prop-valid': + optional: true + react: + optional: true + react-dom: + optional: true + framer-motion@6.5.1: resolution: {integrity: sha512-o1BGqqposwi7cgDrtg0dNONhkmPsUFDaLcKXigzuTFC5x58mE8iyTazxSudFzmT6MEyJKfjjU8ItoMe3W+3fiw==} peerDependencies: @@ -16471,6 +16582,15 @@ packages: hast-to-hyperscript@9.0.1: resolution: {integrity: sha512-zQgLKqF+O2F72S1aa4y2ivxzSlko3MAvxkwG8ehGmNiqd98BIN3JM1rAJPmplEyLmGLO2QZYJtIneOSZ2YbJuA==} + hast-util-from-dom@5.0.1: + resolution: {integrity: sha512-N+LqofjR2zuzTjCPzyDUdSshy4Ma6li7p/c3pA78uTwzFgENbgbUrm2ugwsOdcjI1muO+o6Dgzp9p8WHtn/39Q==} + + hast-util-from-html-isomorphic@2.0.0: + resolution: {integrity: sha512-zJfpXq44yff2hmE0XmwEOzdWin5xwH+QIhMLOScpX91e/NSGPsAzNCvLQDIEPyO2TXi+lBmU6hjLIhV8MwP2kw==} + + hast-util-from-html@2.0.3: + resolution: {integrity: sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==} + hast-util-from-parse5@6.0.1: resolution: {integrity: sha512-jeJUWiN5pSxW12Rh01smtVkZgZr33wBokLzKLwinYOUfSzm1Nl/c3GUGebDyOKjdsRgMvoVbV0VpAcpjF4NrJA==} @@ -16480,6 +16600,9 @@ packages: hast-util-from-parse5@8.0.3: resolution: {integrity: sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==} + hast-util-is-element@3.0.0: + resolution: {integrity: sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==} + hast-util-parse-selector@2.2.5: resolution: {integrity: sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==} @@ -16510,6 +16633,9 @@ packages: hast-util-to-parse5@8.0.1: resolution: {integrity: sha512-MlWT6Pjt4CG9lFCjiz4BH7l9wmrMkfkJYCxFwKQic8+RTZgWPuWxwAfjJElsXkex7DJjfSJsQIt931ilUgmwdA==} + hast-util-to-text@4.0.2: + resolution: {integrity: sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==} + hast-util-whitespace@3.0.0: resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} @@ -16556,8 +16682,8 @@ packages: resolution: {integrity: sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==} engines: {node: '>=0.10.0'} - hono@4.11.7: - resolution: {integrity: sha512-l7qMiNee7t82bH3SeyUCt9UF15EVmaBvsppY2zQtrbIhl/yzBTny+YUxsVjSjQ6gaqaeVtZmGocom8TzBlA4Yw==} + hono@4.11.9: + resolution: {integrity: sha512-Eaw2YTGM6WOxA6CXbckaEvslr2Ne4NFsKrvc0v97JD5awbmeBLO5w9Ho9L9kmKonrwF9RJlW6BxT1PVv/agBHQ==} engines: {node: '>=16.9.0'} hookified@1.15.1: @@ -16619,9 +16745,6 @@ packages: resolution: {integrity: sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==} engines: {node: '>=8'} - html-to-image@1.10.8: - resolution: {integrity: sha512-t+JyFJwKDCp4ZwBp4iC/wqw0meQDDc77Qs8OFl5P7RGlIP3LQMvwpD7VXxqQfC7/TfC+GKYlFP6WDYfXTmXHfw==} - html-to-image@1.11.11: resolution: {integrity: sha512-9gux8QhvjRO/erSnDPv28noDZcPZmYE7e1vFsBLKLlRlKDSqNJYebj6Qz1TGd5lsRV+X+xYyjCKjuZdABinWjA==} @@ -17428,9 +17551,9 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - isexe@3.1.2: - resolution: {integrity: sha512-mIcis6w+JiQf3P7t7mg/35GKB4T1FQsBOtMIvuKw4YErj5RjtbhcTd5/I30fmkmGMwvI0WlzSNN+27K0QCMkAw==} - engines: {node: '>=20'} + isexe@3.1.5: + resolution: {integrity: sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==} + engines: {node: '>=18'} isobject@3.0.1: resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} @@ -17529,8 +17652,8 @@ packages: jackspeak@3.4.3: resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} - jackspeak@4.2.1: - resolution: {integrity: sha512-GPBXyfcZSGujjddPeA+V34bW70ZJT7jzCEbloVasSH4yjiqWqXHX8iZQtZdVbOhc5esSeAIuiSmMutRZQB/olg==} + jackspeak@4.2.3: + resolution: {integrity: sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg==} engines: {node: 20 || >=22} jake@10.9.4: @@ -18277,6 +18400,10 @@ packages: resolution: {integrity: sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==} engines: {node: '>=18'} + katex@0.16.28: + resolution: {integrity: sha512-YHzO7721WbmAL6Ov1uzN/l5mY5WWWhJBSW+jq4tkfZfsxmo1hu6frS0EOswvjBUnWE6NtjEs48SFn5CQESRLZg==} + hasBin: true + keytar@7.9.0: resolution: {integrity: sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==} @@ -18632,8 +18759,8 @@ packages: lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - lru-cache@11.2.5: - resolution: {integrity: sha512-vFrFJkWtJvJnD5hg+hJvVE8Lh/TcMzKnTgCWmtBipwI5yLX/iX+5UB2tfuyODF5E7k9xEzMdYgGqaSb1c0c5Yw==} + lru-cache@11.2.6: + resolution: {integrity: sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==} engines: {node: 20 || >=22} lru-cache@4.1.5: @@ -18731,8 +18858,8 @@ packages: resolution: {integrity: sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==} hasBin: true - markdown-it@14.1.0: - resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==} + markdown-it@14.1.1: + resolution: {integrity: sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA==} hasBin: true markdown-table@3.0.4: @@ -18805,6 +18932,9 @@ packages: mdast-util-gfm@3.1.0: resolution: {integrity: sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==} + mdast-util-math@3.0.0: + resolution: {integrity: sha512-Tl9GBNeG/AhJnQM221bJR2HPvLOSnLE/T9cJI9tlc6zwQk2nPk/4f0cHkOdEixQPC/j8UtKDdITswvLAy1OZ1w==} + mdast-util-mdx-expression@2.0.1: resolution: {integrity: sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==} @@ -18969,6 +19099,9 @@ packages: micromark-extension-gfm@3.0.0: resolution: {integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==} + micromark-extension-math@3.1.0: + resolution: {integrity: sha512-lvEqd+fHjATVs+2v/8kg9i5Q0AP2k85H0WUOwpIVvUML8BapsMvh1XAogmQjOCsLpoKRCVQqEkQBB3NhVBcsOg==} + micromark-extension-mdx-expression@3.0.1: resolution: {integrity: sha512-dD/ADLJ1AeMvSAKBwO22zG22N4ybhe7kFIZ3LsDI0GlsNr2A3KYxb0LdC1u5rj4Nw+CHKY0RVdnHX8vj8ejm4Q==} @@ -19143,8 +19276,8 @@ packages: minimalistic-crypto-utils@1.0.1: resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==} - minimatch@10.1.2: - resolution: {integrity: sha512-fu656aJ0n2kcXwsnwnv9g24tkU5uSmOlTjd6WyyaKm2Z+h1qmY6bAjrcaIxF/BslFqbZ8UBtbJi7KgQOZD2PTw==} + minimatch@10.2.0: + resolution: {integrity: sha512-ugkC31VaVg9cF0DFVoADH12k6061zNZkZON+aX8AWsR9GhPcErkcMBceb6znR8wLERM2AkkOxy2nWRLpT9Jq5w==} engines: {node: 20 || >=22} minimatch@3.0.3: @@ -19289,6 +19422,12 @@ packages: selenium-webdriver: '>=4.6.1' typescript: '>=4.6.2' + motion-dom@11.18.1: + resolution: {integrity: sha512-g76KvA001z+atjfxczdRtw/RXOM3OMSdd1f4DL77qCTF/+avrRJiawSG4yDibEQ215sr9kpinSlX2pCTJ9zbhw==} + + motion-utils@11.18.1: + resolution: {integrity: sha512-49Kt+HKjtbJKLtgO/LKj9Ld+6vw9BjH5d9sc40R/kVyH8GLAXgT42M2NnuPcJNuA3s9ZfZBUcwIgpmZWGEE+hA==} + mousetrap@1.6.5: resolution: {integrity: sha512-QNo4kEepaIBwiT8CDhP98umTetp+JNfQYBWvC1pc6/OAibuXtRcxZ58Qz8skvEHYvURne/7R8T5VoOI7rDsEUA==} @@ -19468,10 +19607,6 @@ packages: resolution: {integrity: sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==} engines: {node: '>= 6.0.0'} - node-forge@1.3.3: - resolution: {integrity: sha512-rLvcdSyRCyouf6jcOIPe/BgwG/d7hKjzMKOas33/pHEr6gbq18IK9zV7DiPvzsz0oBJPme6qr6H6kGZuI9/DZg==} - engines: {node: '>= 6.13.0'} - node-gyp-build@4.8.4: resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} hasBin: true @@ -20229,6 +20364,10 @@ packages: resolution: {integrity: sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==} engines: {node: '>=8'} + pkijs@3.3.3: + resolution: {integrity: sha512-+KD8hJtqQMYoTuL1bbGOqxb4z+nZkTAwVdNtWwe8Tc2xNbEmdJYIYoc6Qt0uF55e6YW6KuTHw1DjQ18gMhzepw==} + engines: {node: '>=16.0.0'} + playwright-core@1.55.1: resolution: {integrity: sha512-Z6Mh9mkwX+zxSlHqdr5AOcJnfp+xUWLCt9uKV18fhzA8eyxUd8NUWzAjxUh55RZKSYwDGX0cfaySdhZJGMoJ+w==} engines: {node: '>=18'} @@ -20895,8 +21034,8 @@ packages: prosemirror-keymap@1.2.2: resolution: {integrity: sha512-EAlXoksqC6Vbocqc0GtzCruZEzYgrn+iiGnNjsJsH4mrnIGex4qbLdWWNza3AW5W36ZRrlBID0eM6bdKH4OStQ==} - prosemirror-markdown@1.13.2: - resolution: {integrity: sha512-FPD9rHPdA9fqzNmIIDhhnYQ6WgNoSWX9StUZ8LEKapaXU9i6XgykaHKhp6XMyXlOWetmaFgGDS/nu/w9/vUc5g==} + prosemirror-markdown@1.13.4: + resolution: {integrity: sha512-D98dm4cQ3Hs6EmjK500TdAOew4Z03EV71ajEFiWra3Upr7diytJsjF4mPV2dW+eK5uNectiRj0xFxYI9NLXDbw==} prosemirror-model@1.25.4: resolution: {integrity: sha512-PIM7E43PBxKce8OQeezAs9j4TP+5yDpZVbuurd1h5phUxEKIu+G2a+EUZzIC5nS1mJktDJWzbqS23n1tsAf5QA==} @@ -20978,6 +21117,13 @@ packages: pure-rand@7.0.1: resolution: {integrity: sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==} + pvtsutils@1.3.6: + resolution: {integrity: sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==} + + pvutils@1.1.5: + resolution: {integrity: sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA==} + engines: {node: '>=16.0.0'} + q@1.5.1: resolution: {integrity: sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==} engines: {node: '>=0.6.0', teleport: '>=0.2.0'} @@ -20990,12 +21136,8 @@ packages: resolution: {integrity: sha512-tsSGN1x3h569ZSU1u6diwhltLyfUWDp3YbFHedapTmpBl0B3P6U3+Qptg7xu+v+1io1EwhdPyyRHYbEw0KN2FA==} engines: {node: '>=20'} - qs@6.14.1: - resolution: {integrity: sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==} - engines: {node: '>=0.6'} - - qs@6.5.3: - resolution: {integrity: sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==} + qs@6.14.2: + resolution: {integrity: sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==} engines: {node: '>=0.6'} query-string@4.3.4: @@ -21623,6 +21765,9 @@ packages: redux@5.0.1: resolution: {integrity: sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==} + reflect-metadata@0.2.2: + resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==} + reflect.getprototypeof@1.0.10: resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} engines: {node: '>= 0.4'} @@ -21682,6 +21827,9 @@ packages: resolution: {integrity: sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==} hasBin: true + rehype-katex@7.0.1: + resolution: {integrity: sha512-OiM2wrZ/wuhKkigASodFoo8wimG3H12LWQaH8qSPVJn9apWKFSH3YOCtbKpBorTVw/eI7cuT21XBbvwEswbIOA==} + rehype-raw@6.1.0: resolution: {integrity: sha512-12j2UiiYJgZFdjnHDny77NY5BF3eW4Jsl0vtgL1DWdTzcHjPpbhumU+GtPUdivEWwQc8x9OdEuO0oxaGz7Tvyg==} @@ -21708,6 +21856,9 @@ packages: remark-gfm@4.0.1: resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==} + remark-math@6.0.0: + resolution: {integrity: sha512-MMqgnP74Igy+S3WwnhQ7kqGlEerTETXMvJhrUzDikVZ2/uogJCb+WHUg97hK9/jcfc0dkD73s3LN8zU49cTEtA==} + remark-mdx@1.6.22: resolution: {integrity: sha512-phMHBJgeV76uyFkH4rvzCftLfKCr2RZuF+/gmVcaKrpsihyzmhXjA0BEMDaPTXG5y8qZOKPVo83NAOX01LPnOQ==} @@ -22094,7 +22245,7 @@ packages: resolution: {integrity: sha512-oL+CMBXrj6BZ/zOq4os+UECPL+bWqt6OAC6DWS8Ln8GZRcMDjlJ4JC3FBDuHJdYaFWIdKNIBYmtZtK2MaMkNIw==} engines: {node: '>= 18.12.0'} peerDependencies: - '@rspack/core': 0.x || 1.x + '@rspack/core': 0.x || ^1.0.0 || ^2.0.0-0 node-sass: ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 sass: ^1.3.0 sass-embedded: '*' @@ -22183,9 +22334,9 @@ packages: selfsigned@1.10.14: resolution: {integrity: sha512-lkjaiAye+wBZDCBsu5BGi0XiLRxeUlsGod5ZP924CRSEoGuZAw/f7y9RKu28rwTfiHVhdavhB0qH0INV6P1lEA==} - selfsigned@2.4.1: - resolution: {integrity: sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==} - engines: {node: '>=10'} + selfsigned@5.5.0: + resolution: {integrity: sha512-ftnu3TW4+3eBfLRFnDEkzGxSF/10BJBkaLJuBHZX0kiPS7bRdlpZGu6YGt4KngMkdTwJE6MbjavFpqHvqVt+Ew==} + engines: {node: '>=18'} semver-diff@2.1.0: resolution: {integrity: sha512-gL8F8L4ORwsS0+iQ34yCYv///jsOq0ZL7WP55d1HnJ32o7tyFYEFQZQA22mrLIacZdU6xecaBBZ+uEiffGNyXw==} @@ -23205,6 +23356,22 @@ packages: uglify-js: optional: true + terser-webpack-plugin@5.3.16: + resolution: {integrity: sha512-h9oBFCWrq78NyWWVcSwZarJkZ01c2AyGrzs1crmHZO3QUg9D61Wu4NPjBy69n7JqylFF5y+CsUZYmYEIZ3mR+Q==} + engines: {node: '>= 10.13.0'} + peerDependencies: + '@swc/core': '*' + esbuild: '*' + uglify-js: '*' + webpack: ^5.1.0 + peerDependenciesMeta: + '@swc/core': + optional: true + esbuild: + optional: true + uglify-js: + optional: true + terser@4.8.1: resolution: {integrity: sha512-4GnLC0x667eJG0ewJTa6z/yXrbLGv80D9Ru6HIpCQmO+Q4PfEtBFi0ObSckqwL6VyQv/7ENJieXHo2ANmdQwgw==} engines: {node: '>=6.0.0'} @@ -23665,6 +23832,10 @@ packages: peerDependencies: typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' + tsyringe@4.10.0: + resolution: {integrity: sha512-axr3IdNuVIxnaK5XGEUFTu3YmAQ6lllgrvqfEoR16g/HGnYY/6We4oWENtAnzK6/LpJ2ur9PAb80RBt7/U4ugw==} + engines: {node: '>= 6.0.0'} + ttf2eot@2.0.0: resolution: {integrity: sha512-U56aG2Ylw7psLOmakjemAzmpqVgeadwENg9oaDjaZG5NYX4WB6+7h74bNPcc+0BXsoU5A/XWiHabDXyzFOmsxQ==} hasBin: true @@ -23796,8 +23967,8 @@ packages: engines: {node: '>=4.2.0'} hasBin: true - typescript@4.1.3: - resolution: {integrity: sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg==} + typescript@4.2.4: + resolution: {integrity: sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==} engines: {node: '>=4.2.0'} hasBin: true @@ -23873,8 +24044,8 @@ packages: undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} - undici@7.20.0: - resolution: {integrity: sha512-MJZrkjyd7DeC+uPZh+5/YaMDxFiiEEaDgbUSVMXayofAkDWF1088CDo+2RPg7B1BuS1qf1vgNE7xqwPxE0DuSQ==} + undici@7.21.0: + resolution: {integrity: sha512-Hn2tCQpoDt1wv23a68Ctc8Cr/BHpUSfaPYrkajTXOS9IKpxVRx/X5m1K2YkbK2ipgZgxXSgsUinl3x+2YdSSfg==} engines: {node: '>=20.18.1'} unfetch@4.2.0: @@ -23958,6 +24129,9 @@ packages: unist-builder@2.0.3: resolution: {integrity: sha512-f98yt5pnlMWlzP539tPc4grGMsFaQQlP/vM396b00jngsiINumNmsY8rkXjfoi1c6QaM8nQ3vaGDuoKWbe/1Uw==} + unist-util-find-after@5.0.0: + resolution: {integrity: sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==} + unist-util-generated@1.1.6: resolution: {integrity: sha512-cln2Mm1/CZzN5ttGK7vkoGw+RZ8VcUH6BtGbq98DDtRGquAAOXig1mrBQYelOwMXYS8rK+vZDyyojSjp7JX+Lg==} @@ -23985,6 +24159,9 @@ packages: unist-util-remove-position@2.0.1: resolution: {integrity: sha512-fDZsLYIe2uT+oGFnuZmy73K6ZxOPG/Qcm+w7jbEjaFcJgbQ6cqjs/eSPzXhsmGpAsWPkqZM9pYjww5QTn3LHMA==} + unist-util-remove-position@5.0.0: + resolution: {integrity: sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==} + unist-util-remove@2.1.0: resolution: {integrity: sha512-J8NYPyBm4baYLdCbjmf1bhPu45Cr1MWTm77qd9istEkzWpnN6O9tMsEbB2JhNnBCqGENRqEWomQ+He6au0B27Q==} @@ -24615,8 +24792,8 @@ packages: peerDependencies: webpack: ^2.2.0 || ^3.0.0 - webpack-dev-server@5.2.1: - resolution: {integrity: sha512-ml/0HIj9NLpVKOMq+SuBPLHcmbG+TGIjXRHsYfZwocUBIqEvws8NnS/V9AFQ5FKP+tgn5adwVwRrTEpGL33QFQ==} + webpack-dev-server@5.2.3: + resolution: {integrity: sha512-9Gyu2F7+bg4Vv+pjbovuYDhHX+mqdqITykfzdM9UyKqKHlsE5aAjRhR+oOEfXW5vBeu8tarzlJFIZva4ZjAdrQ==} engines: {node: '>= 18.12.0'} hasBin: true peerDependencies: @@ -24698,18 +24875,8 @@ packages: webpack-command: optional: true - webpack@5.103.0: - resolution: {integrity: sha512-HU1JOuV1OavsZ+mfigY0j8d1TgQgbZ6M+J75zDkpEAwYeXjWSqrGJtgnPblJjd/mAyTNQ7ygw0MiKOn6etz8yw==} - engines: {node: '>=10.13.0'} - hasBin: true - peerDependencies: - webpack-cli: '*' - peerDependenciesMeta: - webpack-cli: - optional: true - - webpack@5.99.9: - resolution: {integrity: sha512-brOPwM3JnmOa+7kd3NsmOUOwbDAj8FT9xDsG3IW0MgbN9yZV7Oi/s/+MNQ/EcSMqw7qfoRyXPoeEWT8zLVdVGg==} + webpack@5.104.1: + resolution: {integrity: sha512-Qphch25abbMNtekmEGJmeRUhLDbe+QfiWTiqpKYkpCOWY64v9eyl+KRRLmqOFA2AvKPpc9DC6+u2n76tQLBoaA==} engines: {node: '>=10.13.0'} hasBin: true peerDependencies: @@ -25336,7 +25503,7 @@ snapshots: '@aws-sdk/util-user-agent-node': 3.816.0 '@aws-sdk/xml-builder': 3.804.0 '@smithy/config-resolver': 4.4.6 - '@smithy/core': 3.22.1 + '@smithy/core': 3.23.0 '@smithy/eventstream-serde-browser': 4.2.8 '@smithy/eventstream-serde-config-resolver': 4.3.8 '@smithy/eventstream-serde-node': 4.2.8 @@ -25347,25 +25514,25 @@ snapshots: '@smithy/invalid-dependency': 4.2.8 '@smithy/md5-js': 4.2.8 '@smithy/middleware-content-length': 4.2.8 - '@smithy/middleware-endpoint': 4.4.13 - '@smithy/middleware-retry': 4.4.30 + '@smithy/middleware-endpoint': 4.4.14 + '@smithy/middleware-retry': 4.4.31 '@smithy/middleware-serde': 4.2.9 '@smithy/middleware-stack': 4.2.8 '@smithy/node-config-provider': 4.3.8 - '@smithy/node-http-handler': 4.4.9 + '@smithy/node-http-handler': 4.4.10 '@smithy/protocol-http': 5.3.8 - '@smithy/smithy-client': 4.11.2 + '@smithy/smithy-client': 4.11.3 '@smithy/types': 4.12.0 '@smithy/url-parser': 4.2.8 '@smithy/util-base64': 4.3.0 '@smithy/util-body-length-browser': 4.2.0 '@smithy/util-body-length-node': 4.2.1 - '@smithy/util-defaults-mode-browser': 4.3.29 - '@smithy/util-defaults-mode-node': 4.2.32 + '@smithy/util-defaults-mode-browser': 4.3.30 + '@smithy/util-defaults-mode-node': 4.2.33 '@smithy/util-endpoints': 3.2.8 '@smithy/util-middleware': 4.2.8 '@smithy/util-retry': 4.2.8 - '@smithy/util-stream': 4.5.11 + '@smithy/util-stream': 4.5.12 '@smithy/util-utf8': 4.2.0 '@smithy/util-waiter': 4.2.8 tslib: 2.8.1 @@ -25387,26 +25554,26 @@ snapshots: '@aws-sdk/util-user-agent-browser': 3.804.0 '@aws-sdk/util-user-agent-node': 3.816.0 '@smithy/config-resolver': 4.4.6 - '@smithy/core': 3.22.1 + '@smithy/core': 3.23.0 '@smithy/fetch-http-handler': 5.3.9 '@smithy/hash-node': 4.2.8 '@smithy/invalid-dependency': 4.2.8 '@smithy/middleware-content-length': 4.2.8 - '@smithy/middleware-endpoint': 4.4.13 - '@smithy/middleware-retry': 4.4.30 + '@smithy/middleware-endpoint': 4.4.14 + '@smithy/middleware-retry': 4.4.31 '@smithy/middleware-serde': 4.2.9 '@smithy/middleware-stack': 4.2.8 '@smithy/node-config-provider': 4.3.8 - '@smithy/node-http-handler': 4.4.9 + '@smithy/node-http-handler': 4.4.10 '@smithy/protocol-http': 5.3.8 - '@smithy/smithy-client': 4.11.2 + '@smithy/smithy-client': 4.11.3 '@smithy/types': 4.12.0 '@smithy/url-parser': 4.2.8 '@smithy/util-base64': 4.3.0 '@smithy/util-body-length-browser': 4.2.0 '@smithy/util-body-length-node': 4.2.1 - '@smithy/util-defaults-mode-browser': 4.3.29 - '@smithy/util-defaults-mode-node': 4.2.32 + '@smithy/util-defaults-mode-browser': 4.3.30 + '@smithy/util-defaults-mode-node': 4.2.33 '@smithy/util-endpoints': 3.2.8 '@smithy/util-middleware': 4.2.8 '@smithy/util-retry': 4.2.8 @@ -25418,12 +25585,12 @@ snapshots: '@aws-sdk/core@3.816.0': dependencies: '@aws-sdk/types': 3.804.0 - '@smithy/core': 3.22.1 + '@smithy/core': 3.23.0 '@smithy/node-config-provider': 4.3.8 '@smithy/property-provider': 4.2.8 '@smithy/protocol-http': 5.3.8 '@smithy/signature-v4': 5.3.8 - '@smithy/smithy-client': 4.11.2 + '@smithy/smithy-client': 4.11.3 '@smithy/types': 4.12.0 '@smithy/util-middleware': 4.2.8 fast-xml-parser: 5.3.4 @@ -25442,12 +25609,12 @@ snapshots: '@aws-sdk/core': 3.816.0 '@aws-sdk/types': 3.804.0 '@smithy/fetch-http-handler': 5.3.9 - '@smithy/node-http-handler': 4.4.9 + '@smithy/node-http-handler': 4.4.10 '@smithy/property-provider': 4.2.8 '@smithy/protocol-http': 5.3.8 - '@smithy/smithy-client': 4.11.2 + '@smithy/smithy-client': 4.11.3 '@smithy/types': 4.12.0 - '@smithy/util-stream': 4.5.11 + '@smithy/util-stream': 4.5.12 tslib: 2.8.1 '@aws-sdk/credential-provider-ini@3.817.0': @@ -25547,7 +25714,7 @@ snapshots: '@smithy/protocol-http': 5.3.8 '@smithy/types': 4.12.0 '@smithy/util-middleware': 4.2.8 - '@smithy/util-stream': 4.5.11 + '@smithy/util-stream': 4.5.12 '@smithy/util-utf8': 4.2.0 tslib: 2.8.1 @@ -25582,15 +25749,15 @@ snapshots: '@aws-sdk/core': 3.816.0 '@aws-sdk/types': 3.804.0 '@aws-sdk/util-arn-parser': 3.804.0 - '@smithy/core': 3.22.1 + '@smithy/core': 3.23.0 '@smithy/node-config-provider': 4.3.8 '@smithy/protocol-http': 5.3.8 '@smithy/signature-v4': 5.3.8 - '@smithy/smithy-client': 4.11.2 + '@smithy/smithy-client': 4.11.3 '@smithy/types': 4.12.0 '@smithy/util-config-provider': 4.2.0 '@smithy/util-middleware': 4.2.8 - '@smithy/util-stream': 4.5.11 + '@smithy/util-stream': 4.5.12 '@smithy/util-utf8': 4.2.0 tslib: 2.8.1 @@ -25605,7 +25772,7 @@ snapshots: '@aws-sdk/core': 3.816.0 '@aws-sdk/types': 3.804.0 '@aws-sdk/util-endpoints': 3.808.0 - '@smithy/core': 3.22.1 + '@smithy/core': 3.23.0 '@smithy/protocol-http': 5.3.8 '@smithy/types': 4.12.0 tslib: 2.8.1 @@ -25625,26 +25792,26 @@ snapshots: '@aws-sdk/util-user-agent-browser': 3.804.0 '@aws-sdk/util-user-agent-node': 3.816.0 '@smithy/config-resolver': 4.4.6 - '@smithy/core': 3.22.1 + '@smithy/core': 3.23.0 '@smithy/fetch-http-handler': 5.3.9 '@smithy/hash-node': 4.2.8 '@smithy/invalid-dependency': 4.2.8 '@smithy/middleware-content-length': 4.2.8 - '@smithy/middleware-endpoint': 4.4.13 - '@smithy/middleware-retry': 4.4.30 + '@smithy/middleware-endpoint': 4.4.14 + '@smithy/middleware-retry': 4.4.31 '@smithy/middleware-serde': 4.2.9 '@smithy/middleware-stack': 4.2.8 '@smithy/node-config-provider': 4.3.8 - '@smithy/node-http-handler': 4.4.9 + '@smithy/node-http-handler': 4.4.10 '@smithy/protocol-http': 5.3.8 - '@smithy/smithy-client': 4.11.2 + '@smithy/smithy-client': 4.11.3 '@smithy/types': 4.12.0 '@smithy/url-parser': 4.2.8 '@smithy/util-base64': 4.3.0 '@smithy/util-body-length-browser': 4.2.0 '@smithy/util-body-length-node': 4.2.1 - '@smithy/util-defaults-mode-browser': 4.3.29 - '@smithy/util-defaults-mode-node': 4.2.32 + '@smithy/util-defaults-mode-browser': 4.3.30 + '@smithy/util-defaults-mode-node': 4.2.33 '@smithy/util-endpoints': 3.2.8 '@smithy/util-middleware': 4.2.8 '@smithy/util-retry': 4.2.8 @@ -25712,7 +25879,7 @@ snapshots: dependencies: '@aws-sdk/types': 3.804.0 '@smithy/types': 4.12.0 - bowser: 2.13.1 + bowser: 2.14.1 tslib: 2.8.1 '@aws-sdk/util-user-agent-node@3.816.0': @@ -25791,8 +25958,8 @@ snapshots: '@azure/core-tracing': 1.3.1 '@azure/core-util': 1.13.1 '@azure/logger': 1.3.0 - '@azure/msal-browser': 4.28.1 - '@azure/msal-node': 3.8.6 + '@azure/msal-browser': 4.28.2 + '@azure/msal-node': 3.8.7 open: 10.2.0 tslib: 2.8.1 transitivePeerDependencies: @@ -25805,15 +25972,15 @@ snapshots: transitivePeerDependencies: - supports-color - '@azure/msal-browser@4.28.1': + '@azure/msal-browser@4.28.2': dependencies: - '@azure/msal-common': 15.14.1 + '@azure/msal-common': 15.14.2 - '@azure/msal-common@15.14.1': {} + '@azure/msal-common@15.14.2': {} - '@azure/msal-node@3.8.6': + '@azure/msal-node@3.8.7': dependencies: - '@azure/msal-common': 15.14.1 + '@azure/msal-common': 15.14.2 jsonwebtoken: 9.0.3 uuid: 8.3.2 @@ -27629,12 +27796,12 @@ snapshots: '@cacheable/memory@2.0.7': dependencies: - '@cacheable/utils': 2.3.3 + '@cacheable/utils': 2.3.4 '@keyv/bigmap': 1.3.1(keyv@5.6.0) hookified: 1.15.1 keyv: 5.6.0 - '@cacheable/utils@2.3.3': + '@cacheable/utils@2.3.4': dependencies: hashery: 1.4.0 keyv: 5.6.0 @@ -27993,6 +28160,31 @@ snapshots: '@discoveryjs/json-ext@0.6.3': {} + '@dnd-kit/accessibility@3.1.1(react@18.2.0)': + dependencies: + react: 18.2.0 + tslib: 2.8.1 + + '@dnd-kit/core@6.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + dependencies: + '@dnd-kit/accessibility': 3.1.1(react@18.2.0) + '@dnd-kit/utilities': 3.2.2(react@18.2.0) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + tslib: 2.8.1 + + '@dnd-kit/sortable@8.0.0(@dnd-kit/core@6.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react@18.2.0)': + dependencies: + '@dnd-kit/core': 6.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@dnd-kit/utilities': 3.2.2(react@18.2.0) + react: 18.2.0 + tslib: 2.8.1 + + '@dnd-kit/utilities@3.2.2(react@18.2.0)': + dependencies: + react: 18.2.0 + tslib: 2.8.1 + '@dual-bundle/import-meta-resolve@4.2.1': {} '@emnapi/core@1.8.1': @@ -28100,51 +28292,51 @@ snapshots: '@emotion/memoize@0.9.0': {} - '@emotion/react@11.14.0(@types/react@18.2.0)(react@18.2.0)': + '@emotion/react@11.14.0(@types/react@17.0.37)(react@19.1.0)': dependencies: '@babel/runtime': 7.28.6 '@emotion/babel-plugin': 11.13.5 '@emotion/cache': 11.14.0 '@emotion/serialize': 1.3.3 - '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@18.2.0) + '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.1.0) '@emotion/utils': 1.4.2 '@emotion/weak-memoize': 0.4.0 hoist-non-react-statics: 3.3.2 - react: 18.2.0 + react: 19.1.0 optionalDependencies: - '@types/react': 18.2.0 + '@types/react': 17.0.37 transitivePeerDependencies: - supports-color - '@emotion/react@11.9.3(@babel/core@7.27.1)(@types/react@18.2.0)(react@18.2.0)': + '@emotion/react@11.14.0(@types/react@18.2.0)(react@18.2.0)': dependencies: '@babel/runtime': 7.28.6 '@emotion/babel-plugin': 11.13.5 '@emotion/cache': 11.14.0 '@emotion/serialize': 1.3.3 + '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@18.2.0) '@emotion/utils': 1.4.2 - '@emotion/weak-memoize': 0.2.5 + '@emotion/weak-memoize': 0.4.0 hoist-non-react-statics: 3.3.2 react: 18.2.0 optionalDependencies: - '@babel/core': 7.27.1 '@types/react': 18.2.0 transitivePeerDependencies: - supports-color - '@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@17.0.37)(react@19.1.0)': + '@emotion/react@11.14.0(@types/react@18.2.0)(react@19.1.0)': dependencies: '@babel/runtime': 7.28.6 '@emotion/babel-plugin': 11.13.5 '@emotion/cache': 11.14.0 '@emotion/serialize': 1.3.3 + '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.1.0) '@emotion/utils': 1.4.2 - '@emotion/weak-memoize': 0.2.5 + '@emotion/weak-memoize': 0.4.0 hoist-non-react-statics: 3.3.2 react: 19.1.0 optionalDependencies: - '@babel/core': 7.29.0 - '@types/react': 17.0.37 + '@types/react': 18.2.0 transitivePeerDependencies: - supports-color @@ -28218,38 +28410,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@emotion/styled@11.10.5(@babel/core@7.27.1)(@emotion/react@11.9.3(@babel/core@7.27.1)(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0)(react@18.2.0)': - dependencies: - '@babel/runtime': 7.28.6 - '@emotion/babel-plugin': 11.13.5 - '@emotion/is-prop-valid': 1.4.0 - '@emotion/react': 11.9.3(@babel/core@7.27.1)(@types/react@18.2.0)(react@18.2.0) - '@emotion/serialize': 1.3.3 - '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@18.2.0) - '@emotion/utils': 1.4.2 - react: 18.2.0 - optionalDependencies: - '@babel/core': 7.27.1 - '@types/react': 18.2.0 - transitivePeerDependencies: - - supports-color - - '@emotion/styled@11.10.5(@babel/core@7.29.0)(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@17.0.37)(react@19.1.0))(@types/react@17.0.37)(react@19.1.0)': - dependencies: - '@babel/runtime': 7.28.6 - '@emotion/babel-plugin': 11.13.5 - '@emotion/is-prop-valid': 1.4.0 - '@emotion/react': 11.9.3(@babel/core@7.29.0)(@types/react@17.0.37)(react@19.1.0) - '@emotion/serialize': 1.3.3 - '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.1.0) - '@emotion/utils': 1.4.2 - react: 19.1.0 - optionalDependencies: - '@babel/core': 7.29.0 - '@types/react': 17.0.37 - transitivePeerDependencies: - - supports-color - '@emotion/styled@11.10.5(@babel/core@7.29.0)(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0)(react@18.2.0)': dependencies: '@babel/runtime': 7.28.6 @@ -28297,27 +28457,27 @@ snapshots: transitivePeerDependencies: - supports-color - '@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0)(react@18.2.0)': + '@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@17.0.37)(react@19.1.0))(@types/react@17.0.37)(react@19.1.0)': dependencies: '@babel/runtime': 7.28.6 '@emotion/babel-plugin': 11.13.5 '@emotion/is-prop-valid': 1.4.0 - '@emotion/react': 11.14.0(@types/react@18.2.0)(react@18.2.0) + '@emotion/react': 11.14.0(@types/react@17.0.37)(react@19.1.0) '@emotion/serialize': 1.3.3 - '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@18.2.0) + '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.1.0) '@emotion/utils': 1.4.2 - react: 18.2.0 + react: 19.1.0 optionalDependencies: - '@types/react': 18.2.0 + '@types/react': 17.0.37 transitivePeerDependencies: - supports-color - '@emotion/styled@11.14.0(@emotion/react@11.9.3(@babel/core@7.27.1)(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0)(react@18.2.0)': + '@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0)(react@18.2.0)': dependencies: '@babel/runtime': 7.28.6 '@emotion/babel-plugin': 11.13.5 '@emotion/is-prop-valid': 1.4.0 - '@emotion/react': 11.9.3(@babel/core@7.27.1)(@types/react@18.2.0)(react@18.2.0) + '@emotion/react': 11.14.0(@types/react@18.2.0)(react@18.2.0) '@emotion/serialize': 1.3.3 '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@18.2.0) '@emotion/utils': 1.4.2 @@ -28327,12 +28487,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@emotion/styled@11.14.0(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0)(react@18.2.0)': + '@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@18.2.0)(react@19.1.0))(@types/react@18.2.0)(react@18.2.0)': dependencies: '@babel/runtime': 7.28.6 '@emotion/babel-plugin': 11.13.5 '@emotion/is-prop-valid': 1.4.0 - '@emotion/react': 11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@18.2.0) + '@emotion/react': 11.14.0(@types/react@18.2.0)(react@19.1.0) '@emotion/serialize': 1.3.3 '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@18.2.0) '@emotion/utils': 1.4.2 @@ -28342,16 +28502,16 @@ snapshots: transitivePeerDependencies: - supports-color - '@emotion/styled@11.14.0(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@19.1.0))(@types/react@18.2.0)(react@18.2.0)': + '@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@18.2.0)(react@19.1.0))(@types/react@18.2.0)(react@19.1.0)': dependencies: '@babel/runtime': 7.28.6 '@emotion/babel-plugin': 11.13.5 '@emotion/is-prop-valid': 1.4.0 - '@emotion/react': 11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@19.1.0) + '@emotion/react': 11.14.0(@types/react@18.2.0)(react@19.1.0) '@emotion/serialize': 1.3.3 - '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@18.2.0) + '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.1.0) '@emotion/utils': 1.4.2 - react: 18.2.0 + react: 19.1.0 optionalDependencies: '@types/react': 18.2.0 transitivePeerDependencies: @@ -28747,14 +28907,14 @@ snapshots: '@radix-ui/react-visually-hidden': 1.2.4(@types/react-dom@18.2.0)(@types/react@18.2.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@types/codemirror': 5.60.17 clsx: 1.2.1 - codemirror: 5.65.20 - codemirror-graphql: 2.2.4(@codemirror/language@6.11.3)(codemirror@5.65.20)(graphql@16.11.0) + codemirror: 5.65.21 + codemirror-graphql: 2.2.4(@codemirror/language@6.11.3)(codemirror@5.65.21)(graphql@16.11.0) copy-to-clipboard: 3.3.3 framer-motion: 6.5.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) get-value: 3.0.1 graphql: 16.11.0 graphql-language-service: 5.5.0(graphql@16.11.0) - markdown-it: 14.1.0 + markdown-it: 14.1.1 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) set-value: 4.1.0 @@ -28812,9 +28972,9 @@ snapshots: react-dom: 18.2.0(react@18.2.0) use-sync-external-store: 1.6.0(react@18.2.0) - '@hono/node-server@1.19.9(hono@4.11.7)': + '@hono/node-server@1.19.9(hono@4.11.9)': dependencies: - hono: 4.11.7 + hono: 4.11.9 '@hookform/resolvers@2.8.0(react-hook-form@7.56.4(react@18.2.0))': dependencies: @@ -28847,12 +29007,6 @@ snapshots: '@iarna/toml@2.2.5': {} - '@isaacs/balanced-match@4.0.1': {} - - '@isaacs/brace-expansion@5.0.1': - dependencies: - '@isaacs/balanced-match': 4.0.1 - '@isaacs/cliui@8.0.2': dependencies: string-width: 5.1.2 @@ -29463,7 +29617,7 @@ snapshots: dependencies: tslib: 2.8.1 - '@jsonjoy.com/base64@17.65.0(tslib@2.8.1)': + '@jsonjoy.com/base64@17.67.0(tslib@2.8.1)': dependencies: tslib: 2.8.1 @@ -29471,7 +29625,7 @@ snapshots: dependencies: tslib: 2.8.1 - '@jsonjoy.com/buffers@17.65.0(tslib@2.8.1)': + '@jsonjoy.com/buffers@17.67.0(tslib@2.8.1)': dependencies: tslib: 2.8.1 @@ -29479,7 +29633,7 @@ snapshots: dependencies: tslib: 2.8.1 - '@jsonjoy.com/codegen@17.65.0(tslib@2.8.1)': + '@jsonjoy.com/codegen@17.67.0(tslib@2.8.1)': dependencies: tslib: 2.8.1 @@ -29533,10 +29687,10 @@ snapshots: '@jsonjoy.com/fs-snapshot@4.56.10(tslib@2.8.1)': dependencies: - '@jsonjoy.com/buffers': 17.65.0(tslib@2.8.1) + '@jsonjoy.com/buffers': 17.67.0(tslib@2.8.1) '@jsonjoy.com/fs-node-utils': 4.56.10(tslib@2.8.1) - '@jsonjoy.com/json-pack': 17.65.0(tslib@2.8.1) - '@jsonjoy.com/util': 17.65.0(tslib@2.8.1) + '@jsonjoy.com/json-pack': 17.67.0(tslib@2.8.1) + '@jsonjoy.com/util': 17.67.0(tslib@2.8.1) tslib: 2.8.1 '@jsonjoy.com/json-pack@1.21.0(tslib@2.8.1)': @@ -29551,13 +29705,13 @@ snapshots: tree-dump: 1.1.0(tslib@2.8.1) tslib: 2.8.1 - '@jsonjoy.com/json-pack@17.65.0(tslib@2.8.1)': + '@jsonjoy.com/json-pack@17.67.0(tslib@2.8.1)': dependencies: - '@jsonjoy.com/base64': 17.65.0(tslib@2.8.1) - '@jsonjoy.com/buffers': 17.65.0(tslib@2.8.1) - '@jsonjoy.com/codegen': 17.65.0(tslib@2.8.1) - '@jsonjoy.com/json-pointer': 17.65.0(tslib@2.8.1) - '@jsonjoy.com/util': 17.65.0(tslib@2.8.1) + '@jsonjoy.com/base64': 17.67.0(tslib@2.8.1) + '@jsonjoy.com/buffers': 17.67.0(tslib@2.8.1) + '@jsonjoy.com/codegen': 17.67.0(tslib@2.8.1) + '@jsonjoy.com/json-pointer': 17.67.0(tslib@2.8.1) + '@jsonjoy.com/util': 17.67.0(tslib@2.8.1) hyperdyperid: 1.2.0 thingies: 2.5.0(tslib@2.8.1) tree-dump: 1.1.0(tslib@2.8.1) @@ -29569,9 +29723,9 @@ snapshots: '@jsonjoy.com/util': 1.9.0(tslib@2.8.1) tslib: 2.8.1 - '@jsonjoy.com/json-pointer@17.65.0(tslib@2.8.1)': + '@jsonjoy.com/json-pointer@17.67.0(tslib@2.8.1)': dependencies: - '@jsonjoy.com/util': 17.65.0(tslib@2.8.1) + '@jsonjoy.com/util': 17.67.0(tslib@2.8.1) tslib: 2.8.1 '@jsonjoy.com/util@1.9.0(tslib@2.8.1)': @@ -29580,10 +29734,10 @@ snapshots: '@jsonjoy.com/codegen': 1.0.0(tslib@2.8.1) tslib: 2.8.1 - '@jsonjoy.com/util@17.65.0(tslib@2.8.1)': + '@jsonjoy.com/util@17.67.0(tslib@2.8.1)': dependencies: - '@jsonjoy.com/buffers': 17.65.0(tslib@2.8.1) - '@jsonjoy.com/codegen': 17.65.0(tslib@2.8.1) + '@jsonjoy.com/buffers': 17.67.0(tslib@2.8.1) + '@jsonjoy.com/codegen': 17.67.0(tslib@2.8.1) tslib: 2.8.1 '@juggle/resize-observer@3.4.0': {} @@ -30140,7 +30294,7 @@ snapshots: '@modelcontextprotocol/sdk@1.26.0': dependencies: - '@hono/node-server': 1.19.9(hono@4.11.7) + '@hono/node-server': 1.19.9(hono@4.11.9) ajv: 8.17.1 ajv-formats: 3.0.1(ajv@8.17.1) content-type: 1.0.5 @@ -30150,7 +30304,7 @@ snapshots: eventsource-parser: 3.0.6 express: 5.2.1 express-rate-limit: 8.2.1(express@5.2.1) - hono: 4.11.7 + hono: 4.11.9 jose: 6.1.3 json-schema-typed: 8.0.2 pkce-challenge: 5.0.1 @@ -30239,6 +30393,8 @@ snapshots: '@nevware21/ts-utils@0.12.6': {} + '@noble/hashes@1.4.0': {} + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -30355,6 +30511,96 @@ snapshots: '@parcel/watcher-win32-x64': 2.5.6 optional: true + '@peculiar/asn1-cms@2.6.1': + dependencies: + '@peculiar/asn1-schema': 2.6.0 + '@peculiar/asn1-x509': 2.6.1 + '@peculiar/asn1-x509-attr': 2.6.1 + asn1js: 3.0.7 + tslib: 2.8.1 + + '@peculiar/asn1-csr@2.6.1': + dependencies: + '@peculiar/asn1-schema': 2.6.0 + '@peculiar/asn1-x509': 2.6.1 + asn1js: 3.0.7 + tslib: 2.8.1 + + '@peculiar/asn1-ecc@2.6.1': + dependencies: + '@peculiar/asn1-schema': 2.6.0 + '@peculiar/asn1-x509': 2.6.1 + asn1js: 3.0.7 + tslib: 2.8.1 + + '@peculiar/asn1-pfx@2.6.1': + dependencies: + '@peculiar/asn1-cms': 2.6.1 + '@peculiar/asn1-pkcs8': 2.6.1 + '@peculiar/asn1-rsa': 2.6.1 + '@peculiar/asn1-schema': 2.6.0 + asn1js: 3.0.7 + tslib: 2.8.1 + + '@peculiar/asn1-pkcs8@2.6.1': + dependencies: + '@peculiar/asn1-schema': 2.6.0 + '@peculiar/asn1-x509': 2.6.1 + asn1js: 3.0.7 + tslib: 2.8.1 + + '@peculiar/asn1-pkcs9@2.6.1': + dependencies: + '@peculiar/asn1-cms': 2.6.1 + '@peculiar/asn1-pfx': 2.6.1 + '@peculiar/asn1-pkcs8': 2.6.1 + '@peculiar/asn1-schema': 2.6.0 + '@peculiar/asn1-x509': 2.6.1 + '@peculiar/asn1-x509-attr': 2.6.1 + asn1js: 3.0.7 + tslib: 2.8.1 + + '@peculiar/asn1-rsa@2.6.1': + dependencies: + '@peculiar/asn1-schema': 2.6.0 + '@peculiar/asn1-x509': 2.6.1 + asn1js: 3.0.7 + tslib: 2.8.1 + + '@peculiar/asn1-schema@2.6.0': + dependencies: + asn1js: 3.0.7 + pvtsutils: 1.3.6 + tslib: 2.8.1 + + '@peculiar/asn1-x509-attr@2.6.1': + dependencies: + '@peculiar/asn1-schema': 2.6.0 + '@peculiar/asn1-x509': 2.6.1 + asn1js: 3.0.7 + tslib: 2.8.1 + + '@peculiar/asn1-x509@2.6.1': + dependencies: + '@peculiar/asn1-schema': 2.6.0 + asn1js: 3.0.7 + pvtsutils: 1.3.6 + tslib: 2.8.1 + + '@peculiar/x509@1.14.3': + dependencies: + '@peculiar/asn1-cms': 2.6.1 + '@peculiar/asn1-csr': 2.6.1 + '@peculiar/asn1-ecc': 2.6.1 + '@peculiar/asn1-pkcs9': 2.6.1 + '@peculiar/asn1-rsa': 2.6.1 + '@peculiar/asn1-schema': 2.6.0 + '@peculiar/asn1-x509': 2.6.1 + pvtsutils: 1.3.6 + reflect-metadata: 0.2.2 + tslib: 2.8.1 + tsyringe: 4.10.0 + '@pkgjs/parseargs@0.11.0': optional: true @@ -30378,7 +30624,7 @@ snapshots: '@types/webpack': 4.41.40 webpack-hot-middleware: 2.26.1 - '@pmmmwh/react-refresh-webpack-plugin@0.5.17(@types/webpack@5.28.5(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1))(react-refresh@0.11.0)(type-fest@4.41.0)(webpack-dev-server@5.2.1)(webpack-hot-middleware@2.26.1)(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1))': + '@pmmmwh/react-refresh-webpack-plugin@0.5.17(@types/webpack@5.28.5(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1))(react-refresh@0.11.0)(type-fest@4.41.0)(webpack-dev-server@5.2.3)(webpack-hot-middleware@2.26.1)(webpack@5.104.1)': dependencies: ansi-html: 0.0.9 core-js-pure: 3.48.0 @@ -30388,14 +30634,14 @@ snapshots: react-refresh: 0.11.0 schema-utils: 4.3.3 source-map: 0.7.6 - webpack: 5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) optionalDependencies: '@types/webpack': 5.28.5(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) type-fest: 4.41.0 - webpack-dev-server: 5.2.1(webpack-cli@6.0.1)(webpack@5.99.9) + webpack-dev-server: 5.2.3(webpack-cli@6.0.1)(webpack@5.105.2) webpack-hot-middleware: 2.26.1 - '@pmmmwh/react-refresh-webpack-plugin@0.5.17(@types/webpack@5.28.5(@swc/core@1.15.11(@swc/helpers@0.5.18)))(react-refresh@0.11.0)(type-fest@4.41.0)(webpack-dev-server@5.2.1(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))))(webpack-hot-middleware@2.26.1)(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18)))': + '@pmmmwh/react-refresh-webpack-plugin@0.5.17(@types/webpack@5.28.5(@swc/core@1.15.11(@swc/helpers@0.5.18)))(react-refresh@0.11.0)(type-fest@4.41.0)(webpack-dev-server@5.2.3(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))))(webpack-hot-middleware@2.26.1)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18)))': dependencies: ansi-html: 0.0.9 core-js-pure: 3.48.0 @@ -30405,14 +30651,14 @@ snapshots: react-refresh: 0.11.0 schema-utils: 4.3.3 source-map: 0.7.6 - webpack: 5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18)) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18)) optionalDependencies: '@types/webpack': 5.28.5(@swc/core@1.15.11(@swc/helpers@0.5.18)) type-fest: 4.41.0 - webpack-dev-server: 5.2.1(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))) + webpack-dev-server: 5.2.3(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))) webpack-hot-middleware: 2.26.1 - '@pmmmwh/react-refresh-webpack-plugin@0.5.17(@types/webpack@5.28.5(webpack-cli@4.10.0))(react-refresh@0.11.0)(type-fest@4.41.0)(webpack-dev-server@5.2.1)(webpack-hot-middleware@2.26.1)(webpack@5.103.0(webpack-cli@4.10.0))': + '@pmmmwh/react-refresh-webpack-plugin@0.5.17(@types/webpack@5.28.5(webpack-cli@4.10.0))(react-refresh@0.11.0)(type-fest@4.41.0)(webpack-dev-server@5.2.3)(webpack-hot-middleware@2.26.1)(webpack@5.105.2)': dependencies: ansi-html: 0.0.9 core-js-pure: 3.48.0 @@ -30422,14 +30668,14 @@ snapshots: react-refresh: 0.11.0 schema-utils: 4.3.3 source-map: 0.7.6 - webpack: 5.103.0(webpack-cli@4.10.0) + webpack: 5.105.2(webpack-cli@4.10.0) optionalDependencies: '@types/webpack': 5.28.5(webpack-cli@4.10.0) type-fest: 4.41.0 - webpack-dev-server: 5.2.1(webpack-cli@4.10.0)(webpack@5.99.9) + webpack-dev-server: 5.2.3(webpack-cli@4.10.0)(webpack@5.105.2) webpack-hot-middleware: 2.26.1 - '@pmmmwh/react-refresh-webpack-plugin@0.5.17(@types/webpack@5.28.5(webpack-cli@5.1.4))(react-refresh@0.11.0)(type-fest@4.41.0)(webpack-dev-server@5.2.1)(webpack-hot-middleware@2.26.1)(webpack@5.103.0(webpack-cli@5.1.4))': + '@pmmmwh/react-refresh-webpack-plugin@0.5.17(@types/webpack@5.28.5(webpack-cli@5.1.4))(react-refresh@0.11.0)(type-fest@4.41.0)(webpack-dev-server@5.2.3)(webpack-hot-middleware@2.26.1)(webpack@5.105.2)': dependencies: ansi-html: 0.0.9 core-js-pure: 3.48.0 @@ -30439,14 +30685,14 @@ snapshots: react-refresh: 0.11.0 schema-utils: 4.3.3 source-map: 0.7.6 - webpack: 5.103.0(webpack-cli@5.1.4) + webpack: 5.105.2(webpack-cli@5.1.4) optionalDependencies: '@types/webpack': 5.28.5(webpack-cli@5.1.4) type-fest: 4.41.0 - webpack-dev-server: 5.2.1(webpack-cli@5.1.4)(webpack@5.99.9) + webpack-dev-server: 5.2.3(webpack-cli@5.1.4)(webpack@5.105.2) webpack-hot-middleware: 2.26.1 - '@pmmmwh/react-refresh-webpack-plugin@0.5.17(@types/webpack@5.28.5)(react-refresh@0.11.0)(type-fest@4.41.0)(webpack-dev-server@5.2.1(webpack@5.103.0))(webpack-hot-middleware@2.26.1)(webpack@5.103.0)': + '@pmmmwh/react-refresh-webpack-plugin@0.5.17(@types/webpack@5.28.5)(react-refresh@0.11.0)(type-fest@4.41.0)(webpack-dev-server@5.2.3(webpack@5.105.2))(webpack-hot-middleware@2.26.1)(webpack@5.105.2)': dependencies: ansi-html: 0.0.9 core-js-pure: 3.48.0 @@ -30456,14 +30702,14 @@ snapshots: react-refresh: 0.11.0 schema-utils: 4.3.3 source-map: 0.7.6 - webpack: 5.103.0(webpack-cli@6.0.1) + webpack: 5.105.2(webpack-cli@5.1.4) optionalDependencies: - '@types/webpack': 5.28.5 + '@types/webpack': 5.28.5(webpack-cli@5.1.4) type-fest: 4.41.0 - webpack-dev-server: 5.2.1(webpack@5.103.0) + webpack-dev-server: 5.2.3(webpack-cli@5.1.4)(webpack@5.104.1) webpack-hot-middleware: 2.26.1 - '@pmmmwh/react-refresh-webpack-plugin@0.6.0(@types/webpack@5.28.5(webpack-cli@5.1.4))(react-refresh@0.11.0)(type-fest@4.41.0)(webpack-dev-server@5.2.1)(webpack-hot-middleware@2.26.1)(webpack@5.99.9)': + '@pmmmwh/react-refresh-webpack-plugin@0.6.0(@types/webpack@5.28.5(webpack-cli@5.1.4))(react-refresh@0.11.0)(type-fest@4.41.0)(webpack-dev-server@5.2.3)(webpack-hot-middleware@2.26.1)(webpack@5.104.1)': dependencies: anser: 2.3.5 core-js-pure: 3.48.0 @@ -30472,11 +30718,11 @@ snapshots: react-refresh: 0.11.0 schema-utils: 4.3.3 source-map: 0.7.6 - webpack: 5.99.9(webpack-cli@5.1.4) + webpack: 5.105.2(webpack-cli@5.1.4) optionalDependencies: '@types/webpack': 5.28.5(webpack-cli@5.1.4) type-fest: 4.41.0 - webpack-dev-server: 5.2.1(webpack-cli@5.1.4)(webpack@5.99.9) + webpack-dev-server: 5.2.3(webpack-cli@5.1.4)(webpack@5.105.2) webpack-hot-middleware: 2.26.1 '@popperjs/core@2.11.8': {} @@ -30539,35 +30785,9 @@ snapshots: - '@types/react' - supports-color - '@projectstorm/react-diagrams-core@7.0.3(@emotion/react@11.9.3(@babel/core@7.27.1)(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0)': - dependencies: - '@emotion/styled': 11.14.0(@emotion/react@11.9.3(@babel/core@7.27.1)(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0)(react@18.2.0) - '@projectstorm/geometry': 7.0.3 - '@projectstorm/react-canvas-core': 7.0.3(@types/react@18.2.0) - lodash: 4.17.23 - react: 18.2.0 - resize-observer-polyfill: 1.5.1 - transitivePeerDependencies: - - '@emotion/react' - - '@types/react' - - supports-color - - '@projectstorm/react-diagrams-core@7.0.3(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0)': - dependencies: - '@emotion/styled': 11.14.0(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0)(react@18.2.0) - '@projectstorm/geometry': 7.0.3 - '@projectstorm/react-canvas-core': 7.0.3(@types/react@18.2.0) - lodash: 4.17.23 - react: 18.2.0 - resize-observer-polyfill: 1.5.1 - transitivePeerDependencies: - - '@emotion/react' - - '@types/react' - - supports-color - - '@projectstorm/react-diagrams-core@7.0.3(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@19.1.0))(@types/react@18.2.0)': + '@projectstorm/react-diagrams-core@7.0.3(@emotion/react@11.14.0(@types/react@18.2.0)(react@19.1.0))(@types/react@18.2.0)': dependencies: - '@emotion/styled': 11.14.0(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@19.1.0))(@types/react@18.2.0)(react@18.2.0) + '@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@18.2.0)(react@19.1.0))(@types/react@18.2.0)(react@18.2.0) '@projectstorm/geometry': 7.0.3 '@projectstorm/react-canvas-core': 7.0.3(@types/react@18.2.0) lodash: 4.17.23 @@ -30588,23 +30808,23 @@ snapshots: transitivePeerDependencies: - resize-observer-polyfill - '@projectstorm/react-diagrams-defaults@6.7.4(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@18.2.0))(@emotion/styled@11.10.5(@babel/core@7.29.0)(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0)(react@18.2.0))(lodash@4.17.23)(react@18.2.0)(resize-observer-polyfill@1.5.1)': + '@projectstorm/react-diagrams-defaults@6.7.4(@emotion/react@11.14.0(@types/react@18.2.0)(react@19.1.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@18.2.0)(react@19.1.0))(@types/react@18.2.0)(react@19.1.0))(lodash@4.17.23)(react@19.1.0)(resize-observer-polyfill@1.5.1)': dependencies: - '@emotion/react': 11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@18.2.0) - '@emotion/styled': 11.10.5(@babel/core@7.29.0)(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0)(react@18.2.0) - '@projectstorm/react-diagrams-core': 6.7.4(lodash@4.17.23)(react@18.2.0)(resize-observer-polyfill@1.5.1) + '@emotion/react': 11.14.0(@types/react@18.2.0)(react@19.1.0) + '@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@18.2.0)(react@19.1.0))(@types/react@18.2.0)(react@19.1.0) + '@projectstorm/react-diagrams-core': 6.7.4(lodash@4.17.23)(react@19.1.0)(resize-observer-polyfill@1.5.1) lodash: 4.17.23 - react: 18.2.0 + react: 19.1.0 transitivePeerDependencies: - resize-observer-polyfill - '@projectstorm/react-diagrams-defaults@6.7.4(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@19.1.0))(@emotion/styled@11.10.5(@babel/core@7.29.0)(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@19.1.0))(@types/react@18.2.0)(react@19.1.0))(lodash@4.17.23)(react@19.1.0)(resize-observer-polyfill@1.5.1)': + '@projectstorm/react-diagrams-defaults@6.7.4(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@18.2.0))(@emotion/styled@11.10.5(@babel/core@7.29.0)(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0)(react@18.2.0))(lodash@4.17.23)(react@18.2.0)(resize-observer-polyfill@1.5.1)': dependencies: - '@emotion/react': 11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@19.1.0) - '@emotion/styled': 11.10.5(@babel/core@7.29.0)(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@19.1.0))(@types/react@18.2.0)(react@19.1.0) - '@projectstorm/react-diagrams-core': 6.7.4(lodash@4.17.23)(react@19.1.0)(resize-observer-polyfill@1.5.1) + '@emotion/react': 11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@18.2.0) + '@emotion/styled': 11.10.5(@babel/core@7.29.0)(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0)(react@18.2.0) + '@projectstorm/react-diagrams-core': 6.7.4(lodash@4.17.23)(react@18.2.0)(resize-observer-polyfill@1.5.1) lodash: 4.17.23 - react: 19.1.0 + react: 18.2.0 transitivePeerDependencies: - resize-observer-polyfill @@ -30636,31 +30856,31 @@ snapshots: - '@emotion/styled' - resize-observer-polyfill - '@projectstorm/react-diagrams-routing@6.7.4(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@18.2.0))(@emotion/styled@11.10.5(@babel/core@7.29.0)(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0)(react@18.2.0))(dagre@0.8.5)(lodash@4.17.23)(pathfinding@0.4.18)(paths-js@0.4.11)(react@18.2.0)(resize-observer-polyfill@1.5.1)': + '@projectstorm/react-diagrams-routing@6.7.4(@emotion/react@11.14.0(@types/react@18.2.0)(react@19.1.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@18.2.0)(react@19.1.0))(@types/react@18.2.0)(react@19.1.0))(dagre@0.8.5)(lodash@4.17.23)(pathfinding@0.4.18)(paths-js@0.4.11)(react@19.1.0)(resize-observer-polyfill@1.5.1)': dependencies: '@projectstorm/geometry': 6.7.4 - '@projectstorm/react-diagrams-core': 6.7.4(lodash@4.17.23)(react@18.2.0)(resize-observer-polyfill@1.5.1) - '@projectstorm/react-diagrams-defaults': 6.7.4(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@18.2.0))(@emotion/styled@11.10.5(@babel/core@7.29.0)(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0)(react@18.2.0))(lodash@4.17.23)(react@18.2.0)(resize-observer-polyfill@1.5.1) + '@projectstorm/react-diagrams-core': 6.7.4(lodash@4.17.23)(react@19.1.0)(resize-observer-polyfill@1.5.1) + '@projectstorm/react-diagrams-defaults': 6.7.4(@emotion/react@11.14.0(@types/react@18.2.0)(react@19.1.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@18.2.0)(react@19.1.0))(@types/react@18.2.0)(react@19.1.0))(lodash@4.17.23)(react@19.1.0)(resize-observer-polyfill@1.5.1) dagre: 0.8.5 lodash: 4.17.23 pathfinding: 0.4.18 paths-js: 0.4.11 - react: 18.2.0 + react: 19.1.0 transitivePeerDependencies: - '@emotion/react' - '@emotion/styled' - resize-observer-polyfill - '@projectstorm/react-diagrams-routing@6.7.4(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@19.1.0))(@emotion/styled@11.10.5(@babel/core@7.29.0)(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@19.1.0))(@types/react@18.2.0)(react@19.1.0))(dagre@0.8.5)(lodash@4.17.23)(pathfinding@0.4.18)(paths-js@0.4.11)(react@19.1.0)(resize-observer-polyfill@1.5.1)': + '@projectstorm/react-diagrams-routing@6.7.4(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@18.2.0))(@emotion/styled@11.10.5(@babel/core@7.29.0)(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0)(react@18.2.0))(dagre@0.8.5)(lodash@4.17.23)(pathfinding@0.4.18)(paths-js@0.4.11)(react@18.2.0)(resize-observer-polyfill@1.5.1)': dependencies: '@projectstorm/geometry': 6.7.4 - '@projectstorm/react-diagrams-core': 6.7.4(lodash@4.17.23)(react@19.1.0)(resize-observer-polyfill@1.5.1) - '@projectstorm/react-diagrams-defaults': 6.7.4(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@19.1.0))(@emotion/styled@11.10.5(@babel/core@7.29.0)(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@19.1.0))(@types/react@18.2.0)(react@19.1.0))(lodash@4.17.23)(react@19.1.0)(resize-observer-polyfill@1.5.1) + '@projectstorm/react-diagrams-core': 6.7.4(lodash@4.17.23)(react@18.2.0)(resize-observer-polyfill@1.5.1) + '@projectstorm/react-diagrams-defaults': 6.7.4(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@18.2.0))(@emotion/styled@11.10.5(@babel/core@7.29.0)(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0)(react@18.2.0))(lodash@4.17.23)(react@18.2.0)(resize-observer-polyfill@1.5.1) dagre: 0.8.5 lodash: 4.17.23 pathfinding: 0.4.18 paths-js: 0.4.11 - react: 19.1.0 + react: 18.2.0 transitivePeerDependencies: - '@emotion/react' - '@emotion/styled' @@ -30682,38 +30902,6 @@ snapshots: - '@types/react' - supports-color - '@projectstorm/react-diagrams-routing@7.1.3(@emotion/react@11.9.3(@babel/core@7.27.1)(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0)': - dependencies: - '@projectstorm/geometry': 7.0.3 - '@projectstorm/react-canvas-core': 7.0.3(@types/react@18.2.0) - '@projectstorm/react-diagrams-core': 7.0.3(@emotion/react@11.9.3(@babel/core@7.27.1)(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0) - '@projectstorm/react-diagrams-defaults': 7.1.3(@types/react@18.2.0) - dagre: 0.8.5 - lodash: 4.17.23 - pathfinding: 0.4.18 - paths-js: 0.4.11 - react: 18.2.0 - transitivePeerDependencies: - - '@emotion/react' - - '@types/react' - - supports-color - - '@projectstorm/react-diagrams-routing@7.1.3(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0)': - dependencies: - '@projectstorm/geometry': 7.0.3 - '@projectstorm/react-canvas-core': 7.0.3(@types/react@18.2.0) - '@projectstorm/react-diagrams-core': 7.0.3(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0) - '@projectstorm/react-diagrams-defaults': 7.1.3(@types/react@18.2.0) - dagre: 0.8.5 - lodash: 4.17.23 - pathfinding: 0.4.18 - paths-js: 0.4.11 - react: 18.2.0 - transitivePeerDependencies: - - '@emotion/react' - - '@types/react' - - supports-color - '@projectstorm/react-diagrams@6.7.4(@emotion/react@11.14.0(@types/react@18.2.0)(react@18.2.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0)(react@18.2.0))(dagre@0.8.5)(lodash@4.17.23)(pathfinding@0.4.18)(paths-js@0.4.11)(react@18.2.0)(resize-observer-polyfill@1.5.1)': dependencies: '@projectstorm/react-diagrams-core': 6.7.4(lodash@4.17.23)(react@18.2.0)(resize-observer-polyfill@1.5.1) @@ -30729,11 +30917,11 @@ snapshots: - react - resize-observer-polyfill - '@projectstorm/react-diagrams@6.7.4(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@18.2.0))(@emotion/styled@11.10.5(@babel/core@7.29.0)(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0)(react@18.2.0))(dagre@0.8.5)(lodash@4.17.23)(pathfinding@0.4.18)(paths-js@0.4.11)(react@18.2.0)(resize-observer-polyfill@1.5.1)': + '@projectstorm/react-diagrams@6.7.4(@emotion/react@11.14.0(@types/react@18.2.0)(react@19.1.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@18.2.0)(react@19.1.0))(@types/react@18.2.0)(react@19.1.0))(dagre@0.8.5)(lodash@4.17.23)(pathfinding@0.4.18)(paths-js@0.4.11)(react@19.1.0)(resize-observer-polyfill@1.5.1)': dependencies: - '@projectstorm/react-diagrams-core': 6.7.4(lodash@4.17.23)(react@18.2.0)(resize-observer-polyfill@1.5.1) - '@projectstorm/react-diagrams-defaults': 6.7.4(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@18.2.0))(@emotion/styled@11.10.5(@babel/core@7.29.0)(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0)(react@18.2.0))(lodash@4.17.23)(react@18.2.0)(resize-observer-polyfill@1.5.1) - '@projectstorm/react-diagrams-routing': 6.7.4(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@18.2.0))(@emotion/styled@11.10.5(@babel/core@7.29.0)(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0)(react@18.2.0))(dagre@0.8.5)(lodash@4.17.23)(pathfinding@0.4.18)(paths-js@0.4.11)(react@18.2.0)(resize-observer-polyfill@1.5.1) + '@projectstorm/react-diagrams-core': 6.7.4(lodash@4.17.23)(react@19.1.0)(resize-observer-polyfill@1.5.1) + '@projectstorm/react-diagrams-defaults': 6.7.4(@emotion/react@11.14.0(@types/react@18.2.0)(react@19.1.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@18.2.0)(react@19.1.0))(@types/react@18.2.0)(react@19.1.0))(lodash@4.17.23)(react@19.1.0)(resize-observer-polyfill@1.5.1) + '@projectstorm/react-diagrams-routing': 6.7.4(@emotion/react@11.14.0(@types/react@18.2.0)(react@19.1.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@18.2.0)(react@19.1.0))(@types/react@18.2.0)(react@19.1.0))(dagre@0.8.5)(lodash@4.17.23)(pathfinding@0.4.18)(paths-js@0.4.11)(react@19.1.0)(resize-observer-polyfill@1.5.1) transitivePeerDependencies: - '@emotion/react' - '@emotion/styled' @@ -30744,11 +30932,11 @@ snapshots: - react - resize-observer-polyfill - '@projectstorm/react-diagrams@6.7.4(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@19.1.0))(@emotion/styled@11.10.5(@babel/core@7.29.0)(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@19.1.0))(@types/react@18.2.0)(react@19.1.0))(dagre@0.8.5)(lodash@4.17.23)(pathfinding@0.4.18)(paths-js@0.4.11)(react@19.1.0)(resize-observer-polyfill@1.5.1)': + '@projectstorm/react-diagrams@6.7.4(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@18.2.0))(@emotion/styled@11.10.5(@babel/core@7.29.0)(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0)(react@18.2.0))(dagre@0.8.5)(lodash@4.17.23)(pathfinding@0.4.18)(paths-js@0.4.11)(react@18.2.0)(resize-observer-polyfill@1.5.1)': dependencies: - '@projectstorm/react-diagrams-core': 6.7.4(lodash@4.17.23)(react@19.1.0)(resize-observer-polyfill@1.5.1) - '@projectstorm/react-diagrams-defaults': 6.7.4(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@19.1.0))(@emotion/styled@11.10.5(@babel/core@7.29.0)(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@19.1.0))(@types/react@18.2.0)(react@19.1.0))(lodash@4.17.23)(react@19.1.0)(resize-observer-polyfill@1.5.1) - '@projectstorm/react-diagrams-routing': 6.7.4(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@19.1.0))(@emotion/styled@11.10.5(@babel/core@7.29.0)(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@19.1.0))(@types/react@18.2.0)(react@19.1.0))(dagre@0.8.5)(lodash@4.17.23)(pathfinding@0.4.18)(paths-js@0.4.11)(react@19.1.0)(resize-observer-polyfill@1.5.1) + '@projectstorm/react-diagrams-core': 6.7.4(lodash@4.17.23)(react@18.2.0)(resize-observer-polyfill@1.5.1) + '@projectstorm/react-diagrams-defaults': 6.7.4(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@18.2.0))(@emotion/styled@11.10.5(@babel/core@7.29.0)(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0)(react@18.2.0))(lodash@4.17.23)(react@18.2.0)(resize-observer-polyfill@1.5.1) + '@projectstorm/react-diagrams-routing': 6.7.4(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@18.2.0))(@emotion/styled@11.10.5(@babel/core@7.29.0)(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0)(react@18.2.0))(dagre@0.8.5)(lodash@4.17.23)(pathfinding@0.4.18)(paths-js@0.4.11)(react@18.2.0)(resize-observer-polyfill@1.5.1) transitivePeerDependencies: - '@emotion/react' - '@emotion/styled' @@ -30770,28 +30958,6 @@ snapshots: - '@types/react' - supports-color - '@projectstorm/react-diagrams@7.0.4(@emotion/react@11.9.3(@babel/core@7.27.1)(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0)': - dependencies: - '@projectstorm/react-canvas-core': 7.0.3(@types/react@18.2.0) - '@projectstorm/react-diagrams-core': 7.0.3(@emotion/react@11.9.3(@babel/core@7.27.1)(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0) - '@projectstorm/react-diagrams-defaults': 7.1.3(@types/react@18.2.0) - '@projectstorm/react-diagrams-routing': 7.1.3(@emotion/react@11.9.3(@babel/core@7.27.1)(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0) - transitivePeerDependencies: - - '@emotion/react' - - '@types/react' - - supports-color - - '@projectstorm/react-diagrams@7.0.4(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0)': - dependencies: - '@projectstorm/react-canvas-core': 7.0.3(@types/react@18.2.0) - '@projectstorm/react-diagrams-core': 7.0.3(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0) - '@projectstorm/react-diagrams-defaults': 7.1.3(@types/react@18.2.0) - '@projectstorm/react-diagrams-routing': 7.1.3(@emotion/react@11.9.3(@babel/core@7.29.0)(@types/react@18.2.0)(react@18.2.0))(@types/react@18.2.0) - transitivePeerDependencies: - - '@emotion/react' - - '@types/react' - - supports-color - '@protobufjs/aspromise@1.1.2': {} '@protobufjs/base64@1.1.2': {} @@ -32337,7 +32503,7 @@ snapshots: '@redhat-developer/page-objects@1.18.1(selenium-webdriver@4.40.0)(typescript@5.8.3)': dependencies: - clipboardy: 5.2.1 + clipboardy: 5.3.0 clone-deep: 4.0.1 compare-versions: 6.1.1 fs-extra: 11.3.3 @@ -32671,7 +32837,7 @@ snapshots: '@smithy/util-middleware': 4.2.8 tslib: 2.8.1 - '@smithy/core@3.22.1': + '@smithy/core@3.23.0': dependencies: '@smithy/middleware-serde': 4.2.9 '@smithy/protocol-http': 5.3.8 @@ -32679,7 +32845,7 @@ snapshots: '@smithy/util-base64': 4.3.0 '@smithy/util-body-length-browser': 4.2.0 '@smithy/util-middleware': 4.2.8 - '@smithy/util-stream': 4.5.11 + '@smithy/util-stream': 4.5.12 '@smithy/util-utf8': 4.2.0 '@smithy/uuid': 1.1.0 tslib: 2.8.1 @@ -32775,9 +32941,9 @@ snapshots: '@smithy/types': 4.12.0 tslib: 2.8.1 - '@smithy/middleware-endpoint@4.4.13': + '@smithy/middleware-endpoint@4.4.14': dependencies: - '@smithy/core': 3.22.1 + '@smithy/core': 3.23.0 '@smithy/middleware-serde': 4.2.9 '@smithy/node-config-provider': 4.3.8 '@smithy/shared-ini-file-loader': 4.4.3 @@ -32786,12 +32952,12 @@ snapshots: '@smithy/util-middleware': 4.2.8 tslib: 2.8.1 - '@smithy/middleware-retry@4.4.30': + '@smithy/middleware-retry@4.4.31': dependencies: '@smithy/node-config-provider': 4.3.8 '@smithy/protocol-http': 5.3.8 '@smithy/service-error-classification': 4.2.8 - '@smithy/smithy-client': 4.11.2 + '@smithy/smithy-client': 4.11.3 '@smithy/types': 4.12.0 '@smithy/util-middleware': 4.2.8 '@smithy/util-retry': 4.2.8 @@ -32816,7 +32982,7 @@ snapshots: '@smithy/types': 4.12.0 tslib: 2.8.1 - '@smithy/node-http-handler@4.4.9': + '@smithy/node-http-handler@4.4.10': dependencies: '@smithy/abort-controller': 4.2.8 '@smithy/protocol-http': 5.3.8 @@ -32865,14 +33031,14 @@ snapshots: '@smithy/util-utf8': 4.2.0 tslib: 2.8.1 - '@smithy/smithy-client@4.11.2': + '@smithy/smithy-client@4.11.3': dependencies: - '@smithy/core': 3.22.1 - '@smithy/middleware-endpoint': 4.4.13 + '@smithy/core': 3.23.0 + '@smithy/middleware-endpoint': 4.4.14 '@smithy/middleware-stack': 4.2.8 '@smithy/protocol-http': 5.3.8 '@smithy/types': 4.12.0 - '@smithy/util-stream': 4.5.11 + '@smithy/util-stream': 4.5.12 tslib: 2.8.1 '@smithy/types@4.12.0': @@ -32913,20 +33079,20 @@ snapshots: dependencies: tslib: 2.8.1 - '@smithy/util-defaults-mode-browser@4.3.29': + '@smithy/util-defaults-mode-browser@4.3.30': dependencies: '@smithy/property-provider': 4.2.8 - '@smithy/smithy-client': 4.11.2 + '@smithy/smithy-client': 4.11.3 '@smithy/types': 4.12.0 tslib: 2.8.1 - '@smithy/util-defaults-mode-node@4.2.32': + '@smithy/util-defaults-mode-node@4.2.33': dependencies: '@smithy/config-resolver': 4.4.6 '@smithy/credential-provider-imds': 4.2.8 '@smithy/node-config-provider': 4.3.8 '@smithy/property-provider': 4.2.8 - '@smithy/smithy-client': 4.11.2 + '@smithy/smithy-client': 4.11.3 '@smithy/types': 4.12.0 tslib: 2.8.1 @@ -32951,10 +33117,10 @@ snapshots: '@smithy/types': 4.12.0 tslib: 2.8.1 - '@smithy/util-stream@4.5.11': + '@smithy/util-stream@4.5.12': dependencies: '@smithy/fetch-http-handler': 5.3.9 - '@smithy/node-http-handler': 4.4.9 + '@smithy/node-http-handler': 4.4.10 '@smithy/types': 4.12.0 '@smithy/util-base64': 4.3.0 '@smithy/util-buffer-from': 4.2.0 @@ -33292,7 +33458,7 @@ snapshots: storybook: 8.6.14(prettier@3.5.3) ts-dedent: 2.2.0 - '@storybook/addon-docs@6.5.16(@babel/core@7.27.1)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@6.0.1)(webpack@5.99.9)': + '@storybook/addon-docs@6.5.16(@babel/core@7.27.1)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@6.0.1)(webpack@5.104.1)': dependencies: '@babel/plugin-transform-react-jsx': 7.28.6(@babel/core@7.27.1) '@babel/preset-env': 7.27.2(@babel/core@7.27.1) @@ -33312,7 +33478,7 @@ snapshots: '@storybook/source-loader': 6.5.16(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@storybook/store': 6.5.16(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@storybook/theming': 6.5.16(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - babel-loader: 8.4.1(@babel/core@7.27.1)(webpack@5.99.9) + babel-loader: 8.4.1(@babel/core@7.27.1)(webpack@5.104.1) core-js: 3.48.0 fast-deep-equal: 3.1.3 global: 4.4.0 @@ -33335,7 +33501,7 @@ snapshots: - webpack-cli - webpack-command - '@storybook/addon-docs@6.5.9(@babel/core@7.27.1)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@4.10.0)(webpack@5.99.9)': + '@storybook/addon-docs@6.5.9(@babel/core@7.27.1)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@4.10.0)(webpack@5.104.1)': dependencies: '@babel/plugin-transform-react-jsx': 7.28.6(@babel/core@7.27.1) '@babel/preset-env': 7.27.2(@babel/core@7.27.1) @@ -33355,7 +33521,7 @@ snapshots: '@storybook/source-loader': 6.5.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@storybook/store': 6.5.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@storybook/theming': 6.5.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - babel-loader: 8.4.1(@babel/core@7.27.1)(webpack@5.99.9) + babel-loader: 8.4.1(@babel/core@7.27.1)(webpack@5.104.1) core-js: 3.48.0 fast-deep-equal: 3.1.3 global: 4.4.0 @@ -33449,13 +33615,13 @@ snapshots: transitivePeerDependencies: - '@types/react' - '@storybook/addon-essentials@6.5.16(@babel/core@7.27.1)(@storybook/builder-webpack5@6.5.16(@swc/core@1.15.11(@swc/helpers@0.5.18))(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@6.0.1))(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@6.0.1)(webpack@5.99.9)': + '@storybook/addon-essentials@6.5.16(@babel/core@7.27.1)(@storybook/builder-webpack5@6.5.16(@swc/core@1.15.11(@swc/helpers@0.5.18))(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@6.0.1))(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@6.0.1)(webpack@5.104.1)': dependencies: '@babel/core': 7.27.1 '@storybook/addon-actions': 6.5.16(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@storybook/addon-backgrounds': 6.5.16(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@storybook/addon-controls': 6.5.16(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@6.0.1) - '@storybook/addon-docs': 6.5.16(@babel/core@7.27.1)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@6.0.1)(webpack@5.99.9) + '@storybook/addon-docs': 6.5.16(@babel/core@7.27.1)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@6.0.1)(webpack@5.104.1) '@storybook/addon-measure': 6.5.16(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@storybook/addon-outline': 6.5.16(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@storybook/addon-toolbars': 6.5.16(react-dom@18.2.0(react@18.2.0))(react@18.2.0) @@ -33471,7 +33637,7 @@ snapshots: '@storybook/builder-webpack5': 6.5.16(@swc/core@1.15.11(@swc/helpers@0.5.18))(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@6.0.1) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - webpack: 5.99.9(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) transitivePeerDependencies: - '@storybook/mdx2-csf' - eslint @@ -33481,13 +33647,13 @@ snapshots: - webpack-cli - webpack-command - '@storybook/addon-essentials@6.5.9(@babel/core@7.27.1)(@storybook/builder-webpack5@6.5.9(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@4.10.0))(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@4.10.0)(webpack@5.99.9)': + '@storybook/addon-essentials@6.5.9(@babel/core@7.27.1)(@storybook/builder-webpack5@6.5.9(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@4.10.0))(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@4.10.0)(webpack@5.104.1)': dependencies: '@babel/core': 7.27.1 '@storybook/addon-actions': 6.5.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@storybook/addon-backgrounds': 6.5.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@storybook/addon-controls': 6.5.9(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@4.10.0) - '@storybook/addon-docs': 6.5.9(@babel/core@7.27.1)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@4.10.0)(webpack@5.99.9) + '@storybook/addon-docs': 6.5.9(@babel/core@7.27.1)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@4.10.0)(webpack@5.104.1) '@storybook/addon-measure': 6.5.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@storybook/addon-outline': 6.5.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@storybook/addon-toolbars': 6.5.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0) @@ -33503,7 +33669,7 @@ snapshots: '@storybook/builder-webpack5': 6.5.9(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@4.10.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - webpack: 5.99.9(webpack-cli@4.10.0) + webpack: 5.105.2(webpack-cli@4.10.0) transitivePeerDependencies: - '@storybook/mdx2-csf' - eslint @@ -33608,7 +33774,7 @@ snapshots: core-js: 3.48.0 global: 4.4.0 prop-types: 15.8.1 - qs: 6.14.1 + qs: 6.14.2 regenerator-runtime: 0.13.11 ts-dedent: 2.2.0 optionalDependencies: @@ -33626,7 +33792,7 @@ snapshots: core-js: 3.48.0 global: 4.4.0 prop-types: 15.8.1 - qs: 6.14.1 + qs: 6.14.2 regenerator-runtime: 0.13.11 ts-dedent: 2.2.0 optionalDependencies: @@ -34014,7 +34180,7 @@ snapshots: global: 4.4.0 lodash: 4.17.23 memoizerific: 1.11.3 - qs: 6.14.1 + qs: 6.14.2 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) regenerator-runtime: 0.13.11 @@ -34393,7 +34559,7 @@ snapshots: style-loader: 1.3.0(webpack@4.47.0(webpack-cli@6.0.1)) terser-webpack-plugin: 4.2.3(webpack@4.47.0(webpack-cli@6.0.1)) ts-dedent: 2.2.0 - url-loader: 4.1.1(file-loader@6.2.0(webpack@5.99.9))(webpack@4.47.0(webpack-cli@6.0.1)) + url-loader: 4.1.1(file-loader@6.2.0(webpack@5.104.1))(webpack@4.47.0(webpack-cli@6.0.1)) util-deprecate: 1.0.2 webpack: 4.47.0(webpack-cli@6.0.1) webpack-dev-middleware: 3.7.3(webpack@4.47.0(webpack-cli@6.0.1)) @@ -34548,27 +34714,27 @@ snapshots: '@storybook/store': 6.5.16(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@storybook/theming': 6.5.16(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@types/node': 16.18.126 - babel-loader: 8.4.1(@babel/core@7.27.1)(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1)) + babel-loader: 8.4.1(@babel/core@7.27.1)(webpack@5.104.1) babel-plugin-named-exports-order: 0.0.2 browser-assert: 1.2.1 case-sensitive-paths-webpack-plugin: 2.4.0 core-js: 3.48.0 - css-loader: 5.2.7(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1)) - fork-ts-checker-webpack-plugin: 6.5.3(eslint@9.39.2(jiti@2.6.1))(typescript@5.8.3)(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1)) + css-loader: 5.2.7(webpack@5.104.1) + fork-ts-checker-webpack-plugin: 6.5.3(eslint@9.39.2(jiti@2.6.1))(typescript@5.8.3)(webpack@5.104.1) glob: 7.2.3 glob-promise: 3.4.0(glob@7.2.3) - html-webpack-plugin: 5.6.6(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1)) + html-webpack-plugin: 5.6.6(webpack@5.104.1) path-browserify: 1.0.1 process: 0.11.10 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) stable: 0.1.8 - style-loader: 2.0.0(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1)) - terser-webpack-plugin: 5.3.14(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1)) + style-loader: 2.0.0(webpack@5.104.1) + terser-webpack-plugin: 5.3.14(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack@5.104.1) ts-dedent: 2.2.0 util-deprecate: 1.0.2 - webpack: 5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) - webpack-dev-middleware: 4.3.0(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1)) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) + webpack-dev-middleware: 4.3.0(webpack@5.104.1) webpack-hot-middleware: 2.26.1 webpack-virtual-modules: 0.4.6 optionalDependencies: @@ -34603,27 +34769,27 @@ snapshots: '@storybook/store': 6.5.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@storybook/theming': 6.5.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@types/node': 16.18.126 - babel-loader: 8.4.1(@babel/core@7.27.1)(webpack@5.103.0(webpack-cli@4.10.0)) + babel-loader: 8.4.1(@babel/core@7.27.1)(webpack@5.104.1) babel-plugin-named-exports-order: 0.0.2 browser-assert: 1.2.1 case-sensitive-paths-webpack-plugin: 2.4.0 core-js: 3.48.0 - css-loader: 5.2.7(webpack@5.103.0(webpack-cli@4.10.0)) - fork-ts-checker-webpack-plugin: 6.5.3(eslint@9.39.2(jiti@2.6.1))(typescript@5.8.3)(webpack@5.103.0(webpack-cli@4.10.0)) + css-loader: 5.2.7(webpack@5.104.1) + fork-ts-checker-webpack-plugin: 6.5.3(eslint@9.39.2(jiti@2.6.1))(typescript@5.8.3)(webpack@5.104.1) glob: 7.2.3 glob-promise: 3.4.0(glob@7.2.3) - html-webpack-plugin: 5.6.6(webpack@5.103.0(webpack-cli@4.10.0)) + html-webpack-plugin: 5.6.6(webpack@5.104.1) path-browserify: 1.0.1 process: 0.11.10 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) stable: 0.1.8 - style-loader: 2.0.0(webpack@5.103.0(webpack-cli@4.10.0)) - terser-webpack-plugin: 5.3.14(webpack@5.103.0(webpack-cli@4.10.0)) + style-loader: 2.0.0(webpack@5.104.1) + terser-webpack-plugin: 5.3.14(webpack@5.104.1) ts-dedent: 2.2.0 util-deprecate: 1.0.2 - webpack: 5.103.0(webpack-cli@4.10.0) - webpack-dev-middleware: 4.3.0(webpack@5.103.0(webpack-cli@4.10.0)) + webpack: 5.105.2(webpack-cli@4.10.0) + webpack-dev-middleware: 4.3.0(webpack@5.105.2) webpack-hot-middleware: 2.26.1 webpack-virtual-modules: 0.4.6 optionalDependencies: @@ -34653,28 +34819,28 @@ snapshots: '@swc/core': 1.15.11(@swc/helpers@0.5.18) '@types/node': 16.18.126 '@types/semver': 7.7.1 - babel-loader: 9.2.1(@babel/core@7.27.1)(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))) + babel-loader: 9.2.1(@babel/core@7.27.1)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))) babel-plugin-named-exports-order: 0.0.2 browser-assert: 1.2.1 case-sensitive-paths-webpack-plugin: 2.4.0 constants-browserify: 1.0.0 - css-loader: 6.11.0(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))) + css-loader: 6.11.0(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))) express: 4.22.1 - fork-ts-checker-webpack-plugin: 8.0.0(typescript@5.8.3)(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))) + fork-ts-checker-webpack-plugin: 8.0.0(typescript@5.8.3)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))) fs-extra: 11.3.0 - html-webpack-plugin: 5.6.6(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))) + html-webpack-plugin: 5.6.6(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))) path-browserify: 1.0.1 process: 0.11.10 semver: 7.7.4 - style-loader: 3.3.4(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))) - swc-loader: 0.2.7(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))) - terser-webpack-plugin: 5.3.14(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))) + style-loader: 3.3.4(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))) + swc-loader: 0.2.7(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))) + terser-webpack-plugin: 5.3.14(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))) ts-dedent: 2.2.0 url: 0.11.4 util: 0.12.5 util-deprecate: 1.0.2 - webpack: 5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18)) - webpack-dev-middleware: 6.1.3(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18)) + webpack-dev-middleware: 6.1.3(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))) webpack-hot-middleware: 2.26.1 webpack-virtual-modules: 0.5.0 optionalDependencies: @@ -34702,28 +34868,28 @@ snapshots: '@swc/core': 1.15.11(@swc/helpers@0.5.18) '@types/node': 16.18.126 '@types/semver': 7.7.1 - babel-loader: 9.2.1(@babel/core@7.27.1)(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@5.1.4)) + babel-loader: 9.2.1(@babel/core@7.27.1)(webpack@5.104.1) babel-plugin-named-exports-order: 0.0.2 browser-assert: 1.2.1 case-sensitive-paths-webpack-plugin: 2.4.0 constants-browserify: 1.0.0 - css-loader: 6.11.0(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@5.1.4)) + css-loader: 6.11.0(webpack@5.105.2) express: 4.22.1 - fork-ts-checker-webpack-plugin: 8.0.0(typescript@5.8.3)(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@5.1.4)) + fork-ts-checker-webpack-plugin: 8.0.0(typescript@5.8.3)(webpack@5.104.1) fs-extra: 11.3.0 - html-webpack-plugin: 5.6.6(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@5.1.4)) + html-webpack-plugin: 5.6.6(webpack@5.104.1) path-browserify: 1.0.1 process: 0.11.10 semver: 7.7.4 - style-loader: 3.3.4(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@5.1.4)) - swc-loader: 0.2.7(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@5.1.4)) - terser-webpack-plugin: 5.3.14(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@5.1.4)) + style-loader: 3.3.4(webpack@5.104.1) + swc-loader: 0.2.7(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack@5.104.1) + terser-webpack-plugin: 5.3.14(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack@5.104.1) ts-dedent: 2.2.0 url: 0.11.4 util: 0.12.5 util-deprecate: 1.0.2 - webpack: 5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@5.1.4) - webpack-dev-middleware: 6.1.3(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@5.1.4)) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@5.1.4) + webpack-dev-middleware: 6.1.3(webpack@5.104.1) webpack-hot-middleware: 2.26.1 webpack-virtual-modules: 0.5.0 optionalDependencies: @@ -34745,23 +34911,23 @@ snapshots: case-sensitive-paths-webpack-plugin: 2.4.0 cjs-module-lexer: 1.4.3 constants-browserify: 1.0.0 - css-loader: 6.11.0(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12)) + css-loader: 6.11.0(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12)) es-module-lexer: 1.7.0 - fork-ts-checker-webpack-plugin: 8.0.0(typescript@5.8.3)(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12)) - html-webpack-plugin: 5.6.6(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12)) + fork-ts-checker-webpack-plugin: 8.0.0(typescript@5.8.3)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12)) + html-webpack-plugin: 5.6.6(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12)) magic-string: 0.30.21 path-browserify: 1.0.1 process: 0.11.10 semver: 7.7.4 storybook: 8.6.14(prettier@3.5.3) - style-loader: 3.3.4(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12)) - terser-webpack-plugin: 5.3.14(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12)(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12)) + style-loader: 3.3.4(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12)) + terser-webpack-plugin: 5.3.14(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12)) ts-dedent: 2.2.0 url: 0.11.4 util: 0.12.5 util-deprecate: 1.0.2 - webpack: 5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12) - webpack-dev-middleware: 6.1.3(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12)) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12) + webpack-dev-middleware: 6.1.3(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12)) webpack-hot-middleware: 2.26.1 webpack-virtual-modules: 0.6.2 optionalDependencies: @@ -34781,23 +34947,23 @@ snapshots: case-sensitive-paths-webpack-plugin: 2.4.0 cjs-module-lexer: 1.4.3 constants-browserify: 1.0.0 - css-loader: 6.11.0(webpack@5.103.0(webpack-cli@5.1.4)) + css-loader: 6.11.0(webpack@5.105.2) es-module-lexer: 1.7.0 - fork-ts-checker-webpack-plugin: 8.0.0(typescript@5.8.3)(webpack@5.103.0(webpack-cli@5.1.4)) - html-webpack-plugin: 5.6.6(webpack@5.103.0(webpack-cli@5.1.4)) + fork-ts-checker-webpack-plugin: 8.0.0(typescript@5.8.3)(webpack@5.104.1) + html-webpack-plugin: 5.6.6(webpack@5.104.1) magic-string: 0.30.21 path-browserify: 1.0.1 process: 0.11.10 semver: 7.7.4 storybook: 8.6.14(prettier@3.5.3) - style-loader: 3.3.4(webpack@5.103.0(webpack-cli@5.1.4)) - terser-webpack-plugin: 5.3.14(webpack@5.103.0(webpack-cli@5.1.4)) + style-loader: 3.3.4(webpack@5.104.1) + terser-webpack-plugin: 5.3.14(webpack@5.104.1) ts-dedent: 2.2.0 url: 0.11.4 util: 0.12.5 util-deprecate: 1.0.2 - webpack: 5.103.0(webpack-cli@5.1.4) - webpack-dev-middleware: 6.1.3(webpack@5.103.0(webpack-cli@5.1.4)) + webpack: 5.105.2(webpack-cli@5.1.4) + webpack-dev-middleware: 6.1.3(webpack@5.105.2) webpack-hot-middleware: 2.26.1 webpack-virtual-modules: 0.6.2 optionalDependencies: @@ -34816,7 +34982,7 @@ snapshots: '@storybook/core-events': 6.3.7 core-js: 3.48.0 global: 4.4.0 - qs: 6.14.1 + qs: 6.14.2 telejson: 5.3.3 '@storybook/channel-postmessage@6.5.16': @@ -34826,7 +34992,7 @@ snapshots: '@storybook/core-events': 6.5.16 core-js: 3.48.0 global: 4.4.0 - qs: 6.14.1 + qs: 6.14.2 telejson: 6.0.8 '@storybook/channel-postmessage@6.5.9': @@ -34836,7 +35002,7 @@ snapshots: '@storybook/core-events': 6.5.9 core-js: 3.48.0 global: 4.4.0 - qs: 6.14.1 + qs: 6.14.2 telejson: 6.0.8 '@storybook/channel-websocket@6.5.16': @@ -34878,7 +35044,7 @@ snapshots: '@storybook/client-logger': 7.4.0 '@storybook/core-events': 7.4.0 '@storybook/global': 5.0.0 - qs: 6.14.1 + qs: 6.14.2 telejson: 7.2.0 tiny-invariant: 1.3.3 @@ -34887,7 +35053,7 @@ snapshots: '@storybook/client-logger': 7.6.10 '@storybook/core-events': 7.6.10 '@storybook/global': 5.0.0 - qs: 6.14.1 + qs: 6.14.2 telejson: 7.2.0 tiny-invariant: 1.3.3 @@ -34983,7 +35149,7 @@ snapshots: global: 4.4.0 lodash: 4.17.23 memoizerific: 1.11.3 - qs: 6.14.1 + qs: 6.14.2 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) regenerator-runtime: 0.13.11 @@ -35010,7 +35176,7 @@ snapshots: global: 4.4.0 lodash: 4.17.23 memoizerific: 1.11.3 - qs: 6.14.1 + qs: 6.14.2 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) regenerator-runtime: 0.13.11 @@ -35035,7 +35201,7 @@ snapshots: global: 4.4.0 lodash: 4.17.23 memoizerific: 1.11.3 - qs: 6.14.1 + qs: 6.14.2 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) regenerator-runtime: 0.13.11 @@ -35060,7 +35226,7 @@ snapshots: global: 4.4.0 lodash: 4.17.23 memoizerific: 1.11.3 - qs: 6.14.1 + qs: 6.14.2 react: 19.1.0 react-dom: 19.1.0(react@19.1.0) regenerator-runtime: 0.13.11 @@ -35170,7 +35336,7 @@ snapshots: '@storybook/theming': 6.5.16(react-dom@18.2.0(react@18.2.0))(react@18.2.0) core-js: 3.48.0 memoizerific: 1.11.3 - qs: 6.14.1 + qs: 6.14.2 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) regenerator-runtime: 0.13.11 @@ -35184,7 +35350,7 @@ snapshots: '@types/react-syntax-highlighter': 11.0.5 core-js: 3.48.0 memoizerific: 1.11.3 - qs: 6.14.1 + qs: 6.14.2 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) react-syntax-highlighter: 15.6.1(react@18.2.0) @@ -35199,7 +35365,7 @@ snapshots: '@types/react-syntax-highlighter': 11.0.5 core-js: 3.48.0 memoizerific: 1.11.3 - qs: 6.14.1 + qs: 6.14.2 react: 19.1.0 react-dom: 19.1.0(react@19.1.0) react-syntax-highlighter: 15.6.1(react@19.1.0) @@ -35260,7 +35426,7 @@ snapshots: core-js: 3.48.0 global: 4.4.0 lodash: 4.17.23 - qs: 6.14.1 + qs: 6.14.2 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) regenerator-runtime: 0.13.11 @@ -35291,7 +35457,7 @@ snapshots: core-js: 3.48.0 global: 4.4.0 lodash: 4.17.23 - qs: 6.14.1 + qs: 6.14.2 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) regenerator-runtime: 0.13.11 @@ -35319,7 +35485,7 @@ snapshots: core-js: 3.48.0 global: 4.4.0 lodash: 4.17.23 - qs: 6.14.1 + qs: 6.14.2 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) regenerator-runtime: 0.13.11 @@ -35330,7 +35496,7 @@ snapshots: optionalDependencies: typescript: 5.8.3 - '@storybook/core-client@6.5.16(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1))': + '@storybook/core-client@6.5.16(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18)))': dependencies: '@storybook/addons': 6.5.16(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@storybook/channel-postmessage': 6.5.16 @@ -35347,18 +35513,18 @@ snapshots: core-js: 3.48.0 global: 4.4.0 lodash: 4.17.23 - qs: 6.14.1 + qs: 6.14.2 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) regenerator-runtime: 0.13.11 ts-dedent: 2.2.0 unfetch: 4.2.0 util-deprecate: 1.0.2 - webpack: 5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18)) optionalDependencies: typescript: 5.8.3 - '@storybook/core-client@6.5.16(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18)))': + '@storybook/core-client@6.5.16(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack@5.105.2)': dependencies: '@storybook/addons': 6.5.16(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@storybook/channel-postmessage': 6.5.16 @@ -35375,42 +35541,14 @@ snapshots: core-js: 3.48.0 global: 4.4.0 lodash: 4.17.23 - qs: 6.14.1 + qs: 6.14.2 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) regenerator-runtime: 0.13.11 ts-dedent: 2.2.0 unfetch: 4.2.0 util-deprecate: 1.0.2 - webpack: 5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18)) - optionalDependencies: - typescript: 5.8.3 - - '@storybook/core-client@6.5.16(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack@5.103.0)': - dependencies: - '@storybook/addons': 6.5.16(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@storybook/channel-postmessage': 6.5.16 - '@storybook/channel-websocket': 6.5.16 - '@storybook/client-api': 6.5.16(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@storybook/client-logger': 6.5.16 - '@storybook/core-events': 6.5.16 - '@storybook/csf': 0.0.2--canary.4566f4d.1 - '@storybook/preview-web': 6.5.16(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@storybook/store': 6.5.16(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@storybook/ui': 6.5.16(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - airbnb-js-shims: 2.2.1 - ansi-to-html: 0.6.15 - core-js: 3.48.0 - global: 4.4.0 - lodash: 4.17.23 - qs: 6.14.1 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - regenerator-runtime: 0.13.11 - ts-dedent: 2.2.0 - unfetch: 4.2.0 - util-deprecate: 1.0.2 - webpack: 5.103.0(webpack-cli@6.0.1) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) optionalDependencies: typescript: 5.8.3 @@ -35431,7 +35569,7 @@ snapshots: core-js: 3.48.0 global: 4.4.0 lodash: 4.17.23 - qs: 6.14.1 + qs: 6.14.2 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) regenerator-runtime: 0.13.11 @@ -35442,35 +35580,7 @@ snapshots: optionalDependencies: typescript: 5.8.3 - '@storybook/core-client@6.5.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1))': - dependencies: - '@storybook/addons': 6.5.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@storybook/channel-postmessage': 6.5.9 - '@storybook/channel-websocket': 6.5.9 - '@storybook/client-api': 6.5.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@storybook/client-logger': 6.5.9 - '@storybook/core-events': 6.5.9 - '@storybook/csf': 0.0.2--canary.4566f4d.1 - '@storybook/preview-web': 6.5.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@storybook/store': 6.5.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@storybook/ui': 6.5.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - airbnb-js-shims: 2.2.1 - ansi-to-html: 0.6.15 - core-js: 3.48.0 - global: 4.4.0 - lodash: 4.17.23 - qs: 6.14.1 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - regenerator-runtime: 0.13.11 - ts-dedent: 2.2.0 - unfetch: 4.2.0 - util-deprecate: 1.0.2 - webpack: 5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) - optionalDependencies: - typescript: 5.8.3 - - '@storybook/core-client@6.5.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack@5.103.0(webpack-cli@4.10.0))': + '@storybook/core-client@6.5.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack@5.104.1)': dependencies: '@storybook/addons': 6.5.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@storybook/channel-postmessage': 6.5.9 @@ -35487,14 +35597,14 @@ snapshots: core-js: 3.48.0 global: 4.4.0 lodash: 4.17.23 - qs: 6.14.1 + qs: 6.14.2 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) regenerator-runtime: 0.13.11 ts-dedent: 2.2.0 unfetch: 4.2.0 util-deprecate: 1.0.2 - webpack: 5.103.0(webpack-cli@4.10.0) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) optionalDependencies: typescript: 5.8.3 @@ -35515,7 +35625,7 @@ snapshots: core-js: 3.48.0 global: 4.4.0 lodash: 4.17.23 - qs: 6.14.1 + qs: 6.14.2 react: 19.1.0 react-dom: 19.1.0(react@19.1.0) regenerator-runtime: 0.13.11 @@ -35526,7 +35636,7 @@ snapshots: optionalDependencies: typescript: 4.9.4 - '@storybook/core-client@6.5.9(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@4.9.4)(webpack@5.103.0)': + '@storybook/core-client@6.5.9(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@4.9.4)(webpack@5.104.1)': dependencies: '@storybook/addons': 6.5.9(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@storybook/channel-postmessage': 6.5.9 @@ -35543,14 +35653,14 @@ snapshots: core-js: 3.48.0 global: 4.4.0 lodash: 4.17.23 - qs: 6.14.1 + qs: 6.14.2 react: 19.1.0 react-dom: 19.1.0(react@19.1.0) regenerator-runtime: 0.13.11 ts-dedent: 2.2.0 unfetch: 4.2.0 util-deprecate: 1.0.2 - webpack: 5.103.0(webpack-cli@6.0.1) + webpack: 5.105.2(webpack-cli@5.1.4) optionalDependencies: typescript: 4.9.4 @@ -36467,13 +36577,13 @@ snapshots: - webpack-cli - webpack-command - '@storybook/core@6.5.16(@storybook/builder-webpack5@6.5.16(@swc/core@1.15.11(@swc/helpers@0.5.18))(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@6.0.1))(@storybook/manager-webpack5@6.5.9(@swc/core@1.15.11(@swc/helpers@0.5.18))(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@6.0.1))(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@6.0.1)(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1))': + '@storybook/core@6.5.16(@storybook/builder-webpack5@6.5.16(@swc/core@1.15.11(@swc/helpers@0.5.18))(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@6.0.1))(@storybook/manager-webpack5@6.5.9(@swc/core@1.15.11(@swc/helpers@0.5.18))(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@6.0.1))(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@6.0.1)(webpack@5.104.1)': dependencies: - '@storybook/core-client': 6.5.16(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1)) + '@storybook/core-client': 6.5.16(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack@5.104.1) '@storybook/core-server': 6.5.16(@storybook/builder-webpack5@6.5.16(@swc/core@1.15.11(@swc/helpers@0.5.18))(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@6.0.1))(@storybook/manager-webpack5@6.5.9(@swc/core@1.15.11(@swc/helpers@0.5.18))(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@6.0.1))(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@6.0.1) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - webpack: 5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) optionalDependencies: '@storybook/builder-webpack5': 6.5.16(@swc/core@1.15.11(@swc/helpers@0.5.18))(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@6.0.1) '@storybook/manager-webpack5': 6.5.9(@swc/core@1.15.11(@swc/helpers@0.5.18))(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@6.0.1) @@ -36489,13 +36599,13 @@ snapshots: - webpack-cli - webpack-command - '@storybook/core@6.5.16(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18)))': + '@storybook/core@6.5.16(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18)))': dependencies: - '@storybook/core-client': 6.5.16(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))) + '@storybook/core-client': 6.5.16(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))) '@storybook/core-server': 6.5.16(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - webpack: 5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18)) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18)) optionalDependencies: typescript: 5.8.3 transitivePeerDependencies: @@ -36509,13 +36619,13 @@ snapshots: - webpack-cli - webpack-command - '@storybook/core@6.5.16(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack@5.103.0)': + '@storybook/core@6.5.16(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack@5.104.1)': dependencies: - '@storybook/core-client': 6.5.16(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack@5.103.0) + '@storybook/core-client': 6.5.16(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack@5.104.1) '@storybook/core-server': 6.5.16(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - webpack: 5.103.0(webpack-cli@6.0.1) + webpack: 5.104.1(webpack-cli@5.1.4) optionalDependencies: typescript: 5.8.3 transitivePeerDependencies: @@ -36529,13 +36639,13 @@ snapshots: - webpack-cli - webpack-command - '@storybook/core@6.5.9(@storybook/builder-webpack5@6.5.9(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@4.10.0))(@storybook/manager-webpack5@6.5.9(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@4.10.0))(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@4.10.0)(webpack@5.103.0(webpack-cli@4.10.0))': + '@storybook/core@6.5.9(@storybook/builder-webpack5@6.5.9(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@4.10.0))(@storybook/manager-webpack5@6.5.9(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@4.10.0))(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@4.10.0)(webpack@5.104.1)': dependencies: - '@storybook/core-client': 6.5.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack@5.103.0(webpack-cli@4.10.0)) + '@storybook/core-client': 6.5.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack@5.104.1) '@storybook/core-server': 6.5.9(@storybook/builder-webpack5@6.5.9(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@4.10.0))(@storybook/manager-webpack5@6.5.9(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@4.10.0))(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@4.10.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - webpack: 5.103.0(webpack-cli@4.10.0) + webpack: 5.105.2(webpack-cli@4.10.0) optionalDependencies: '@storybook/builder-webpack5': 6.5.9(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@4.10.0) '@storybook/manager-webpack5': 6.5.9(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@4.10.0) @@ -36551,13 +36661,13 @@ snapshots: - webpack-cli - webpack-command - '@storybook/core@6.5.9(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@4.9.4)(webpack@5.103.0)': + '@storybook/core@6.5.9(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@4.9.4)(webpack@5.104.1)': dependencies: - '@storybook/core-client': 6.5.9(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@4.9.4)(webpack@5.103.0) + '@storybook/core-client': 6.5.9(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@4.9.4)(webpack@5.104.1) '@storybook/core-server': 6.5.9(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@4.9.4) react: 19.1.0 react-dom: 19.1.0(react@19.1.0) - webpack: 5.103.0(webpack-cli@6.0.1) + webpack: 5.105.2(webpack-cli@5.1.4) optionalDependencies: typescript: 4.9.4 transitivePeerDependencies: @@ -36996,7 +37106,7 @@ snapshots: telejson: 6.0.8 terser-webpack-plugin: 4.2.3(webpack@4.47.0(webpack-cli@6.0.1)) ts-dedent: 2.2.0 - url-loader: 4.1.1(file-loader@6.2.0(webpack@5.99.9))(webpack@4.47.0(webpack-cli@6.0.1)) + url-loader: 4.1.1(file-loader@6.2.0(webpack@5.104.1))(webpack@4.47.0(webpack-cli@6.0.1)) util-deprecate: 1.0.2 webpack: 4.47.0(webpack-cli@6.0.1) webpack-dev-middleware: 3.7.3(webpack@4.47.0(webpack-cli@6.0.1)) @@ -37115,21 +37225,21 @@ snapshots: '@babel/plugin-transform-template-literals': 7.27.1(@babel/core@7.27.1) '@babel/preset-react': 7.27.1(@babel/core@7.27.1) '@storybook/addons': 6.5.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@storybook/core-client': 6.5.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1)) + '@storybook/core-client': 6.5.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack@5.104.1) '@storybook/core-common': 6.5.9(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@6.0.1) '@storybook/node-logger': 6.5.9 '@storybook/theming': 6.5.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@storybook/ui': 6.5.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@types/node': 16.18.126 - babel-loader: 8.4.1(@babel/core@7.27.1)(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1)) + babel-loader: 8.4.1(@babel/core@7.27.1)(webpack@5.104.1) case-sensitive-paths-webpack-plugin: 2.4.0 chalk: 4.1.2 core-js: 3.48.0 - css-loader: 5.2.7(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1)) + css-loader: 5.2.7(webpack@5.104.1) express: 4.22.1 find-up: 5.0.0 fs-extra: 9.1.0 - html-webpack-plugin: 5.6.6(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1)) + html-webpack-plugin: 5.6.6(webpack@5.104.1) node-fetch: 2.6.7(encoding@0.1.13) process: 0.11.10 react: 18.2.0 @@ -37137,13 +37247,13 @@ snapshots: read-pkg-up: 7.0.1 regenerator-runtime: 0.13.11 resolve-from: 5.0.0 - style-loader: 2.0.0(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1)) + style-loader: 2.0.0(webpack@5.105.2) telejson: 6.0.8 - terser-webpack-plugin: 5.3.14(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1)) + terser-webpack-plugin: 5.3.14(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack@5.104.1) ts-dedent: 2.2.0 util-deprecate: 1.0.2 - webpack: 5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) - webpack-dev-middleware: 4.3.0(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1)) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) + webpack-dev-middleware: 4.3.0(webpack@5.104.1) webpack-virtual-modules: 0.4.6 optionalDependencies: typescript: 5.8.3 @@ -37165,21 +37275,21 @@ snapshots: '@babel/plugin-transform-template-literals': 7.27.1(@babel/core@7.27.1) '@babel/preset-react': 7.27.1(@babel/core@7.27.1) '@storybook/addons': 6.5.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@storybook/core-client': 6.5.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack@5.103.0(webpack-cli@4.10.0)) + '@storybook/core-client': 6.5.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack@5.104.1) '@storybook/core-common': 6.5.9(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@4.10.0) '@storybook/node-logger': 6.5.9 '@storybook/theming': 6.5.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@storybook/ui': 6.5.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@types/node': 16.18.126 - babel-loader: 8.4.1(@babel/core@7.27.1)(webpack@5.103.0(webpack-cli@4.10.0)) + babel-loader: 8.4.1(@babel/core@7.27.1)(webpack@5.104.1) case-sensitive-paths-webpack-plugin: 2.4.0 chalk: 4.1.2 core-js: 3.48.0 - css-loader: 5.2.7(webpack@5.103.0(webpack-cli@4.10.0)) + css-loader: 5.2.7(webpack@5.104.1) express: 4.22.1 find-up: 5.0.0 fs-extra: 9.1.0 - html-webpack-plugin: 5.6.6(webpack@5.103.0(webpack-cli@4.10.0)) + html-webpack-plugin: 5.6.6(webpack@5.104.1) node-fetch: 2.6.7(encoding@0.1.13) process: 0.11.10 react: 18.2.0 @@ -37187,13 +37297,13 @@ snapshots: read-pkg-up: 7.0.1 regenerator-runtime: 0.13.11 resolve-from: 5.0.0 - style-loader: 2.0.0(webpack@5.103.0(webpack-cli@4.10.0)) + style-loader: 2.0.0(webpack@5.105.2) telejson: 6.0.8 - terser-webpack-plugin: 5.3.14(webpack@5.103.0(webpack-cli@4.10.0)) + terser-webpack-plugin: 5.3.14(webpack@5.104.1) ts-dedent: 2.2.0 util-deprecate: 1.0.2 - webpack: 5.103.0(webpack-cli@4.10.0) - webpack-dev-middleware: 4.3.0(webpack@5.103.0(webpack-cli@4.10.0)) + webpack: 5.105.2(webpack-cli@4.10.0) + webpack-dev-middleware: 4.3.0(webpack@5.105.2) webpack-virtual-modules: 0.4.6 optionalDependencies: typescript: 5.8.3 @@ -37268,16 +37378,16 @@ snapshots: '@storybook/postinstall@7.4.0': {} - '@storybook/preset-react-webpack@7.4.0(@babel/core@7.29.0)(@types/webpack@5.28.5(webpack-cli@5.1.4))(encoding@0.1.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(type-fest@4.41.0)(typescript@5.8.3)(webpack-cli@5.1.4)(webpack-dev-server@5.2.1)(webpack-hot-middleware@2.26.1)': + '@storybook/preset-react-webpack@7.4.0(@babel/core@7.29.0)(@types/webpack@5.28.5(webpack-cli@5.1.4))(encoding@0.1.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(type-fest@4.41.0)(typescript@5.8.3)(webpack-cli@5.1.4)(webpack-dev-server@5.2.3)(webpack-hot-middleware@2.26.1)': dependencies: '@babel/preset-flow': 7.27.1(@babel/core@7.29.0) '@babel/preset-react': 7.27.1(@babel/core@7.29.0) - '@pmmmwh/react-refresh-webpack-plugin': 0.5.17(@types/webpack@5.28.5(webpack-cli@5.1.4))(react-refresh@0.11.0)(type-fest@4.41.0)(webpack-dev-server@5.2.1)(webpack-hot-middleware@2.26.1)(webpack@5.103.0(webpack-cli@5.1.4)) + '@pmmmwh/react-refresh-webpack-plugin': 0.5.17(@types/webpack@5.28.5(webpack-cli@5.1.4))(react-refresh@0.11.0)(type-fest@4.41.0)(webpack-dev-server@5.2.3)(webpack-hot-middleware@2.26.1)(webpack@5.104.1) '@storybook/core-webpack': 7.4.0(encoding@0.1.13) '@storybook/docs-tools': 7.4.0(encoding@0.1.13) '@storybook/node-logger': 7.4.0 '@storybook/react': 7.4.0(encoding@0.1.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3) - '@storybook/react-docgen-typescript-plugin': 1.0.6--canary.9.0c3f3b7.0(typescript@5.8.3)(webpack@5.103.0(webpack-cli@5.1.4)) + '@storybook/react-docgen-typescript-plugin': 1.0.6--canary.9.0c3f3b7.0(typescript@5.8.3)(webpack@5.104.1) '@types/node': 16.18.126 '@types/semver': 7.7.1 babel-plugin-add-react-displayname: 0.0.5 @@ -37287,7 +37397,7 @@ snapshots: react-dom: 18.2.0(react@18.2.0) react-refresh: 0.11.0 semver: 7.7.4 - webpack: 5.103.0(webpack-cli@5.1.4) + webpack: 5.104.1(webpack-cli@5.1.4) optionalDependencies: '@babel/core': 7.29.0 typescript: 5.8.3 @@ -37309,12 +37419,12 @@ snapshots: dependencies: '@babel/preset-flow': 7.27.1(@babel/core@7.29.0) '@babel/preset-react': 7.27.1(@babel/core@7.29.0) - '@pmmmwh/react-refresh-webpack-plugin': 0.5.17(@types/webpack@5.28.5)(react-refresh@0.11.0)(type-fest@4.41.0)(webpack-dev-server@5.2.1(webpack@5.103.0))(webpack-hot-middleware@2.26.1)(webpack@5.103.0) + '@pmmmwh/react-refresh-webpack-plugin': 0.5.17(@types/webpack@5.28.5)(react-refresh@0.11.0)(type-fest@4.41.0)(webpack-dev-server@5.2.3(webpack@5.104.1))(webpack-hot-middleware@2.26.1)(webpack@5.104.1) '@storybook/core-webpack': 7.4.0(encoding@0.1.13) '@storybook/docs-tools': 7.4.0(encoding@0.1.13) '@storybook/node-logger': 7.4.0 '@storybook/react': 7.4.0(encoding@0.1.13)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@5.8.3) - '@storybook/react-docgen-typescript-plugin': 1.0.6--canary.9.0c3f3b7.0(typescript@5.8.3)(webpack@5.103.0) + '@storybook/react-docgen-typescript-plugin': 1.0.6--canary.9.0c3f3b7.0(typescript@5.8.3)(webpack@5.104.1) '@types/node': 16.18.126 '@types/semver': 7.7.1 babel-plugin-add-react-displayname: 0.0.5 @@ -37324,7 +37434,7 @@ snapshots: react-dom: 19.1.0(react@19.1.0) react-refresh: 0.11.0 semver: 7.7.4 - webpack: 5.103.0(webpack-cli@6.0.1) + webpack: 5.104.1(webpack-cli@5.1.4) optionalDependencies: '@babel/core': 7.29.0 typescript: 5.8.3 @@ -37346,7 +37456,7 @@ snapshots: dependencies: '@storybook/core-webpack': 8.6.14(storybook@8.6.14(prettier@3.5.3)) '@storybook/react': 8.6.14(@storybook/test@8.6.14(storybook@8.6.14(prettier@3.5.3)))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(storybook@8.6.14(prettier@3.5.3))(typescript@5.8.3) - '@storybook/react-docgen-typescript-plugin': 1.0.6--canary.9.0c3f3b7.0(typescript@5.8.3)(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12)) + '@storybook/react-docgen-typescript-plugin': 1.0.6--canary.9.0c3f3b7.0(typescript@5.8.3)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12)) '@types/semver': 7.7.1 find-up: 5.0.0 magic-string: 0.30.21 @@ -37357,7 +37467,7 @@ snapshots: semver: 7.7.4 storybook: 8.6.14(prettier@3.5.3) tsconfig-paths: 4.2.0 - webpack: 5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12) optionalDependencies: typescript: 5.8.3 transitivePeerDependencies: @@ -37372,7 +37482,7 @@ snapshots: dependencies: '@storybook/core-webpack': 8.6.14(storybook@8.6.14(prettier@3.5.3)) '@storybook/react': 8.6.14(@storybook/test@8.6.14(storybook@8.6.14(prettier@3.5.3)))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(storybook@8.6.14(prettier@3.5.3))(typescript@5.8.3) - '@storybook/react-docgen-typescript-plugin': 1.0.6--canary.9.0c3f3b7.0(typescript@5.8.3)(webpack@5.103.0(webpack-cli@5.1.4)) + '@storybook/react-docgen-typescript-plugin': 1.0.6--canary.9.0c3f3b7.0(typescript@5.8.3)(webpack@5.104.1) '@types/semver': 7.7.1 find-up: 5.0.0 magic-string: 0.30.21 @@ -37383,7 +37493,7 @@ snapshots: semver: 7.7.4 storybook: 8.6.14(prettier@3.5.3) tsconfig-paths: 4.2.0 - webpack: 5.103.0(webpack-cli@5.1.4) + webpack: 5.105.2(webpack-cli@5.1.4) optionalDependencies: typescript: 5.8.3 transitivePeerDependencies: @@ -37406,7 +37516,7 @@ snapshots: dequal: 2.0.3 lodash: 4.17.23 memoizerific: 1.11.3 - qs: 6.14.1 + qs: 6.14.2 synchronous-promise: 2.0.17 ts-dedent: 2.2.0 util-deprecate: 1.0.2 @@ -37423,7 +37533,7 @@ snapshots: dequal: 2.0.3 lodash: 4.17.23 memoizerific: 1.11.3 - qs: 6.14.1 + qs: 6.14.2 synchronous-promise: 2.0.17 ts-dedent: 2.2.0 util-deprecate: 1.0.2 @@ -37444,7 +37554,7 @@ snapshots: core-js: 3.48.0 global: 4.4.0 lodash: 4.17.23 - qs: 6.14.1 + qs: 6.14.2 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) regenerator-runtime: 0.13.11 @@ -37465,7 +37575,7 @@ snapshots: core-js: 3.48.0 global: 4.4.0 lodash: 4.17.23 - qs: 6.14.1 + qs: 6.14.2 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) regenerator-runtime: 0.13.11 @@ -37486,7 +37596,7 @@ snapshots: core-js: 3.48.0 global: 4.4.0 lodash: 4.17.23 - qs: 6.14.1 + qs: 6.14.2 react: 19.1.0 react-dom: 19.1.0(react@19.1.0) regenerator-runtime: 0.13.11 @@ -37511,7 +37621,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@storybook/react-docgen-typescript-plugin@1.0.2-canary.6.9d540b91e815f8fc2f8829189deb00553559ff63.0(typescript@4.9.4)(webpack@5.103.0)': + '@storybook/react-docgen-typescript-plugin@1.0.2-canary.6.9d540b91e815f8fc2f8829189deb00553559ff63.0(typescript@4.9.4)(webpack@5.104.1)': dependencies: debug: 4.4.3(supports-color@8.1.1) endent: 2.1.0 @@ -37521,39 +37631,11 @@ snapshots: react-docgen-typescript: 2.4.0(typescript@4.9.4) tslib: 2.8.1 typescript: 4.9.4 - webpack: 5.103.0(webpack-cli@6.0.1) - transitivePeerDependencies: - - supports-color - - '@storybook/react-docgen-typescript-plugin@1.0.2-canary.6.9d540b91e815f8fc2f8829189deb00553559ff63.0(typescript@5.8.3)(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1))': - dependencies: - debug: 4.4.3(supports-color@8.1.1) - endent: 2.1.0 - find-cache-dir: 3.3.2 - flat-cache: 3.2.0 - micromatch: 4.0.8 - react-docgen-typescript: 2.4.0(typescript@5.8.3) - tslib: 2.8.1 - typescript: 5.8.3 - webpack: 5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) - transitivePeerDependencies: - - supports-color - - '@storybook/react-docgen-typescript-plugin@1.0.2-canary.6.9d540b91e815f8fc2f8829189deb00553559ff63.0(typescript@5.8.3)(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18)))': - dependencies: - debug: 4.4.3(supports-color@8.1.1) - endent: 2.1.0 - find-cache-dir: 3.3.2 - flat-cache: 3.2.0 - micromatch: 4.0.8 - react-docgen-typescript: 2.4.0(typescript@5.8.3) - tslib: 2.8.1 - typescript: 5.8.3 - webpack: 5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18)) + webpack: 5.104.1(webpack-cli@5.1.4) transitivePeerDependencies: - supports-color - '@storybook/react-docgen-typescript-plugin@1.0.2-canary.6.9d540b91e815f8fc2f8829189deb00553559ff63.0(typescript@5.8.3)(webpack@5.103.0(webpack-cli@4.10.0))': + '@storybook/react-docgen-typescript-plugin@1.0.2-canary.6.9d540b91e815f8fc2f8829189deb00553559ff63.0(typescript@5.8.3)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18)))': dependencies: debug: 4.4.3(supports-color@8.1.1) endent: 2.1.0 @@ -37563,11 +37645,11 @@ snapshots: react-docgen-typescript: 2.4.0(typescript@5.8.3) tslib: 2.8.1 typescript: 5.8.3 - webpack: 5.103.0(webpack-cli@4.10.0) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18)) transitivePeerDependencies: - supports-color - '@storybook/react-docgen-typescript-plugin@1.0.2-canary.6.9d540b91e815f8fc2f8829189deb00553559ff63.0(typescript@5.8.3)(webpack@5.103.0)': + '@storybook/react-docgen-typescript-plugin@1.0.2-canary.6.9d540b91e815f8fc2f8829189deb00553559ff63.0(typescript@5.8.3)(webpack@5.105.2)': dependencies: debug: 4.4.3(supports-color@8.1.1) endent: 2.1.0 @@ -37577,11 +37659,11 @@ snapshots: react-docgen-typescript: 2.4.0(typescript@5.8.3) tslib: 2.8.1 typescript: 5.8.3 - webpack: 5.103.0(webpack-cli@6.0.1) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) transitivePeerDependencies: - supports-color - '@storybook/react-docgen-typescript-plugin@1.0.6--canary.9.0c3f3b7.0(typescript@5.8.3)(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12))': + '@storybook/react-docgen-typescript-plugin@1.0.6--canary.9.0c3f3b7.0(typescript@5.8.3)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12))': dependencies: debug: 4.4.3(supports-color@8.1.1) endent: 2.1.0 @@ -37591,11 +37673,11 @@ snapshots: react-docgen-typescript: 2.4.0(typescript@5.8.3) tslib: 2.8.1 typescript: 5.8.3 - webpack: 5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12) transitivePeerDependencies: - supports-color - '@storybook/react-docgen-typescript-plugin@1.0.6--canary.9.0c3f3b7.0(typescript@5.8.3)(webpack@5.103.0(webpack-cli@5.1.4))': + '@storybook/react-docgen-typescript-plugin@1.0.6--canary.9.0c3f3b7.0(typescript@5.8.3)(webpack@5.105.2)': dependencies: debug: 4.4.3(supports-color@8.1.1) endent: 2.1.0 @@ -37605,21 +37687,7 @@ snapshots: react-docgen-typescript: 2.4.0(typescript@5.8.3) tslib: 2.8.1 typescript: 5.8.3 - webpack: 5.103.0(webpack-cli@5.1.4) - transitivePeerDependencies: - - supports-color - - '@storybook/react-docgen-typescript-plugin@1.0.6--canary.9.0c3f3b7.0(typescript@5.8.3)(webpack@5.103.0)': - dependencies: - debug: 4.4.3(supports-color@8.1.1) - endent: 2.1.0 - find-cache-dir: 3.3.2 - flat-cache: 3.2.0 - micromatch: 4.0.8 - react-docgen-typescript: 2.4.0(typescript@5.8.3) - tslib: 2.8.1 - typescript: 5.8.3 - webpack: 5.103.0(webpack-cli@6.0.1) + webpack: 5.105.2(webpack-cli@5.1.4) transitivePeerDependencies: - supports-color @@ -37667,10 +37735,10 @@ snapshots: - supports-color - typescript - '@storybook/react-webpack5@7.4.0(@babel/core@7.29.0)(@swc/helpers@0.5.18)(@types/webpack@5.28.5(webpack-cli@5.1.4))(encoding@0.1.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(type-fest@4.41.0)(typescript@5.8.3)(webpack-cli@5.1.4)(webpack-dev-server@5.2.1)(webpack-hot-middleware@2.26.1)': + '@storybook/react-webpack5@7.4.0(@babel/core@7.29.0)(@swc/helpers@0.5.18)(@types/webpack@5.28.5(webpack-cli@5.1.4))(encoding@0.1.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(type-fest@4.41.0)(typescript@5.8.3)(webpack-cli@5.1.4)(webpack-dev-server@5.2.3)(webpack-hot-middleware@2.26.1)': dependencies: '@storybook/builder-webpack5': 7.4.0(@swc/helpers@0.5.18)(encoding@0.1.13)(typescript@5.8.3)(webpack-cli@5.1.4) - '@storybook/preset-react-webpack': 7.4.0(@babel/core@7.29.0)(@types/webpack@5.28.5(webpack-cli@5.1.4))(encoding@0.1.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(type-fest@4.41.0)(typescript@5.8.3)(webpack-cli@5.1.4)(webpack-dev-server@5.2.1)(webpack-hot-middleware@2.26.1) + '@storybook/preset-react-webpack': 7.4.0(@babel/core@7.29.0)(@types/webpack@5.28.5(webpack-cli@5.1.4))(encoding@0.1.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(type-fest@4.41.0)(typescript@5.8.3)(webpack-cli@5.1.4)(webpack-dev-server@5.2.3)(webpack-hot-middleware@2.26.1) '@storybook/react': 7.4.0(encoding@0.1.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3) '@types/node': 16.18.126 react: 18.2.0 @@ -37853,19 +37921,19 @@ snapshots: - webpack-hot-middleware - webpack-plugin-serve - '@storybook/react@6.5.16(@babel/core@7.27.1)(@storybook/builder-webpack5@6.5.16(@swc/core@1.15.11(@swc/helpers@0.5.18))(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@6.0.1))(@storybook/manager-webpack5@6.5.9(@swc/core@1.15.11(@swc/helpers@0.5.18))(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@6.0.1))(@swc/core@1.15.11(@swc/helpers@0.5.18))(@types/webpack@5.28.5(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1))(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(require-from-string@2.0.2)(type-fest@4.41.0)(typescript@5.8.3)(webpack-cli@6.0.1)(webpack-dev-server@5.2.1)(webpack-hot-middleware@2.26.1)': + '@storybook/react@6.5.16(@babel/core@7.27.1)(@storybook/builder-webpack5@6.5.16(@swc/core@1.15.11(@swc/helpers@0.5.18))(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@6.0.1))(@storybook/manager-webpack5@6.5.9(@swc/core@1.15.11(@swc/helpers@0.5.18))(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@6.0.1))(@swc/core@1.15.11(@swc/helpers@0.5.18))(@types/webpack@5.28.5(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1))(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(require-from-string@2.0.2)(type-fest@4.41.0)(typescript@5.8.3)(webpack-cli@6.0.1)(webpack-dev-server@5.2.3)(webpack-hot-middleware@2.26.1)': dependencies: '@babel/preset-flow': 7.27.1(@babel/core@7.27.1) '@babel/preset-react': 7.27.1(@babel/core@7.27.1) - '@pmmmwh/react-refresh-webpack-plugin': 0.5.17(@types/webpack@5.28.5(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1))(react-refresh@0.11.0)(type-fest@4.41.0)(webpack-dev-server@5.2.1)(webpack-hot-middleware@2.26.1)(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1)) + '@pmmmwh/react-refresh-webpack-plugin': 0.5.17(@types/webpack@5.28.5(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1))(react-refresh@0.11.0)(type-fest@4.41.0)(webpack-dev-server@5.2.3)(webpack-hot-middleware@2.26.1)(webpack@5.104.1) '@storybook/addons': 6.5.16(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@storybook/client-logger': 6.5.16 - '@storybook/core': 6.5.16(@storybook/builder-webpack5@6.5.16(@swc/core@1.15.11(@swc/helpers@0.5.18))(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@6.0.1))(@storybook/manager-webpack5@6.5.9(@swc/core@1.15.11(@swc/helpers@0.5.18))(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@6.0.1))(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@6.0.1)(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1)) + '@storybook/core': 6.5.16(@storybook/builder-webpack5@6.5.16(@swc/core@1.15.11(@swc/helpers@0.5.18))(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@6.0.1))(@storybook/manager-webpack5@6.5.9(@swc/core@1.15.11(@swc/helpers@0.5.18))(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@6.0.1))(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@6.0.1)(webpack@5.104.1) '@storybook/core-common': 6.5.16(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@6.0.1) '@storybook/csf': 0.0.2--canary.4566f4d.1 '@storybook/docs-tools': 6.5.16(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@storybook/node-logger': 6.5.16 - '@storybook/react-docgen-typescript-plugin': 1.0.2-canary.6.9d540b91e815f8fc2f8829189deb00553559ff63.0(typescript@5.8.3)(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1)) + '@storybook/react-docgen-typescript-plugin': 1.0.2-canary.6.9d540b91e815f8fc2f8829189deb00553559ff63.0(typescript@5.8.3)(webpack@5.105.2) '@storybook/semver': 7.3.2 '@storybook/store': 6.5.16(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@types/estree': 0.0.51 @@ -37892,7 +37960,7 @@ snapshots: require-from-string: 2.0.2 ts-dedent: 2.2.0 util-deprecate: 1.0.2 - webpack: 5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) optionalDependencies: '@babel/core': 7.27.1 '@storybook/builder-webpack5': 6.5.16(@swc/core@1.15.11(@swc/helpers@0.5.18))(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@6.0.1) @@ -37918,19 +37986,19 @@ snapshots: - webpack-hot-middleware - webpack-plugin-serve - '@storybook/react@6.5.16(@babel/core@7.27.1)(@swc/core@1.15.11(@swc/helpers@0.5.18))(@types/webpack@5.28.5(@swc/core@1.15.11(@swc/helpers@0.5.18)))(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(require-from-string@2.0.2)(type-fest@4.41.0)(typescript@5.8.3)(webpack-dev-server@5.2.1(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))))(webpack-hot-middleware@2.26.1)': + '@storybook/react@6.5.16(@babel/core@7.27.1)(@swc/core@1.15.11(@swc/helpers@0.5.18))(@types/webpack@5.28.5(@swc/core@1.15.11(@swc/helpers@0.5.18)))(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(require-from-string@2.0.2)(type-fest@4.41.0)(typescript@5.8.3)(webpack-dev-server@5.2.3(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))))(webpack-hot-middleware@2.26.1)': dependencies: '@babel/preset-flow': 7.27.1(@babel/core@7.27.1) '@babel/preset-react': 7.27.1(@babel/core@7.27.1) - '@pmmmwh/react-refresh-webpack-plugin': 0.5.17(@types/webpack@5.28.5(@swc/core@1.15.11(@swc/helpers@0.5.18)))(react-refresh@0.11.0)(type-fest@4.41.0)(webpack-dev-server@5.2.1(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))))(webpack-hot-middleware@2.26.1)(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))) + '@pmmmwh/react-refresh-webpack-plugin': 0.5.17(@types/webpack@5.28.5(@swc/core@1.15.11(@swc/helpers@0.5.18)))(react-refresh@0.11.0)(type-fest@4.41.0)(webpack-dev-server@5.2.3(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))))(webpack-hot-middleware@2.26.1)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))) '@storybook/addons': 6.5.16(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@storybook/client-logger': 6.5.16 - '@storybook/core': 6.5.16(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))) + '@storybook/core': 6.5.16(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))) '@storybook/core-common': 6.5.16(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3) '@storybook/csf': 0.0.2--canary.4566f4d.1 '@storybook/docs-tools': 6.5.16(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@storybook/node-logger': 6.5.16 - '@storybook/react-docgen-typescript-plugin': 1.0.2-canary.6.9d540b91e815f8fc2f8829189deb00553559ff63.0(typescript@5.8.3)(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))) + '@storybook/react-docgen-typescript-plugin': 1.0.2-canary.6.9d540b91e815f8fc2f8829189deb00553559ff63.0(typescript@5.8.3)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))) '@storybook/semver': 7.3.2 '@storybook/store': 6.5.16(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@types/estree': 0.0.51 @@ -37957,7 +38025,7 @@ snapshots: require-from-string: 2.0.2 ts-dedent: 2.2.0 util-deprecate: 1.0.2 - webpack: 5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18)) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18)) optionalDependencies: '@babel/core': 7.27.1 typescript: 5.8.3 @@ -37981,19 +38049,19 @@ snapshots: - webpack-hot-middleware - webpack-plugin-serve - '@storybook/react@6.5.16(@babel/core@7.29.0)(@types/webpack@5.28.5)(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(require-from-string@2.0.2)(type-fest@4.41.0)(typescript@5.8.3)(webpack-dev-server@5.2.1(webpack@5.103.0))(webpack-hot-middleware@2.26.1)': + '@storybook/react@6.5.16(@babel/core@7.29.0)(@types/webpack@5.28.5)(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(require-from-string@2.0.2)(type-fest@4.41.0)(typescript@5.8.3)(webpack-dev-server@5.2.3(webpack@5.104.1))(webpack-hot-middleware@2.26.1)': dependencies: '@babel/preset-flow': 7.27.1(@babel/core@7.29.0) '@babel/preset-react': 7.27.1(@babel/core@7.29.0) - '@pmmmwh/react-refresh-webpack-plugin': 0.5.17(@types/webpack@5.28.5)(react-refresh@0.11.0)(type-fest@4.41.0)(webpack-dev-server@5.2.1(webpack@5.103.0))(webpack-hot-middleware@2.26.1)(webpack@5.103.0) + '@pmmmwh/react-refresh-webpack-plugin': 0.5.17(@types/webpack@5.28.5)(react-refresh@0.11.0)(type-fest@4.41.0)(webpack-dev-server@5.2.3(webpack@5.104.1))(webpack-hot-middleware@2.26.1)(webpack@5.104.1) '@storybook/addons': 6.5.16(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@storybook/client-logger': 6.5.16 - '@storybook/core': 6.5.16(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack@5.103.0) + '@storybook/core': 6.5.16(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack@5.104.1) '@storybook/core-common': 6.5.16(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3) '@storybook/csf': 0.0.2--canary.4566f4d.1 '@storybook/docs-tools': 6.5.16(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@storybook/node-logger': 6.5.16 - '@storybook/react-docgen-typescript-plugin': 1.0.2-canary.6.9d540b91e815f8fc2f8829189deb00553559ff63.0(typescript@5.8.3)(webpack@5.103.0) + '@storybook/react-docgen-typescript-plugin': 1.0.2-canary.6.9d540b91e815f8fc2f8829189deb00553559ff63.0(typescript@5.8.3)(webpack@5.105.2) '@storybook/semver': 7.3.2 '@storybook/store': 6.5.16(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@types/estree': 0.0.51 @@ -38020,7 +38088,7 @@ snapshots: require-from-string: 2.0.2 ts-dedent: 2.2.0 util-deprecate: 1.0.2 - webpack: 5.103.0(webpack-cli@6.0.1) + webpack: 5.104.1(webpack-cli@5.1.4) optionalDependencies: '@babel/core': 7.29.0 typescript: 5.8.3 @@ -38044,19 +38112,19 @@ snapshots: - webpack-hot-middleware - webpack-plugin-serve - '@storybook/react@6.5.9(@babel/core@7.27.1)(@storybook/builder-webpack5@6.5.9(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@4.10.0))(@storybook/manager-webpack5@6.5.9(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@4.10.0))(@types/webpack@5.28.5(webpack-cli@4.10.0))(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(require-from-string@2.0.2)(type-fest@4.41.0)(typescript@5.8.3)(webpack-cli@4.10.0)(webpack-dev-server@5.2.1)(webpack-hot-middleware@2.26.1)': + '@storybook/react@6.5.9(@babel/core@7.27.1)(@storybook/builder-webpack5@6.5.9(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@4.10.0))(@storybook/manager-webpack5@6.5.9(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@4.10.0))(@types/webpack@5.28.5(webpack-cli@4.10.0))(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(require-from-string@2.0.2)(type-fest@4.41.0)(typescript@5.8.3)(webpack-cli@4.10.0)(webpack-dev-server@5.2.3)(webpack-hot-middleware@2.26.1)': dependencies: '@babel/preset-flow': 7.27.1(@babel/core@7.27.1) '@babel/preset-react': 7.27.1(@babel/core@7.27.1) - '@pmmmwh/react-refresh-webpack-plugin': 0.5.17(@types/webpack@5.28.5(webpack-cli@4.10.0))(react-refresh@0.11.0)(type-fest@4.41.0)(webpack-dev-server@5.2.1)(webpack-hot-middleware@2.26.1)(webpack@5.103.0(webpack-cli@4.10.0)) + '@pmmmwh/react-refresh-webpack-plugin': 0.5.17(@types/webpack@5.28.5(webpack-cli@4.10.0))(react-refresh@0.11.0)(type-fest@4.41.0)(webpack-dev-server@5.2.3)(webpack-hot-middleware@2.26.1)(webpack@5.104.1) '@storybook/addons': 6.5.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@storybook/client-logger': 6.5.9 - '@storybook/core': 6.5.9(@storybook/builder-webpack5@6.5.9(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@4.10.0))(@storybook/manager-webpack5@6.5.9(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@4.10.0))(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@4.10.0)(webpack@5.103.0(webpack-cli@4.10.0)) + '@storybook/core': 6.5.9(@storybook/builder-webpack5@6.5.9(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@4.10.0))(@storybook/manager-webpack5@6.5.9(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@4.10.0))(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@4.10.0)(webpack@5.104.1) '@storybook/core-common': 6.5.9(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@4.10.0) '@storybook/csf': 0.0.2--canary.4566f4d.1 '@storybook/docs-tools': 6.5.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@storybook/node-logger': 6.5.9 - '@storybook/react-docgen-typescript-plugin': 1.0.2-canary.6.9d540b91e815f8fc2f8829189deb00553559ff63.0(typescript@5.8.3)(webpack@5.103.0(webpack-cli@4.10.0)) + '@storybook/react-docgen-typescript-plugin': 1.0.2-canary.6.9d540b91e815f8fc2f8829189deb00553559ff63.0(typescript@5.8.3)(webpack@5.104.1) '@storybook/semver': 7.3.2 '@storybook/store': 6.5.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@types/estree': 0.0.51 @@ -38083,7 +38151,7 @@ snapshots: require-from-string: 2.0.2 ts-dedent: 2.2.0 util-deprecate: 1.0.2 - webpack: 5.103.0(webpack-cli@4.10.0) + webpack: 5.105.2(webpack-cli@4.10.0) optionalDependencies: '@babel/core': 7.27.1 '@storybook/builder-webpack5': 6.5.9(eslint@9.39.2(jiti@2.6.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.8.3)(webpack-cli@4.10.0) @@ -38109,19 +38177,19 @@ snapshots: - webpack-hot-middleware - webpack-plugin-serve - '@storybook/react@6.5.9(@babel/core@7.29.0)(@types/webpack@5.28.5)(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(require-from-string@2.0.2)(type-fest@4.41.0)(typescript@4.9.4)(webpack-dev-server@5.2.1(webpack@5.103.0))(webpack-hot-middleware@2.26.1)': + '@storybook/react@6.5.9(@babel/core@7.29.0)(@types/webpack@5.28.5)(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(require-from-string@2.0.2)(type-fest@4.41.0)(typescript@4.9.4)(webpack-dev-server@5.2.3(webpack@5.104.1))(webpack-hot-middleware@2.26.1)': dependencies: '@babel/preset-flow': 7.27.1(@babel/core@7.29.0) '@babel/preset-react': 7.27.1(@babel/core@7.29.0) - '@pmmmwh/react-refresh-webpack-plugin': 0.5.17(@types/webpack@5.28.5)(react-refresh@0.11.0)(type-fest@4.41.0)(webpack-dev-server@5.2.1(webpack@5.103.0))(webpack-hot-middleware@2.26.1)(webpack@5.103.0) + '@pmmmwh/react-refresh-webpack-plugin': 0.5.17(@types/webpack@5.28.5)(react-refresh@0.11.0)(type-fest@4.41.0)(webpack-dev-server@5.2.3(webpack@5.104.1))(webpack-hot-middleware@2.26.1)(webpack@5.104.1) '@storybook/addons': 6.5.9(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@storybook/client-logger': 6.5.9 - '@storybook/core': 6.5.9(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@4.9.4)(webpack@5.103.0) + '@storybook/core': 6.5.9(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@4.9.4)(webpack@5.104.1) '@storybook/core-common': 6.5.9(eslint@9.39.2(jiti@2.6.1))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@4.9.4) '@storybook/csf': 0.0.2--canary.4566f4d.1 '@storybook/docs-tools': 6.5.9(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@storybook/node-logger': 6.5.9 - '@storybook/react-docgen-typescript-plugin': 1.0.2-canary.6.9d540b91e815f8fc2f8829189deb00553559ff63.0(typescript@4.9.4)(webpack@5.103.0) + '@storybook/react-docgen-typescript-plugin': 1.0.2-canary.6.9d540b91e815f8fc2f8829189deb00553559ff63.0(typescript@4.9.4)(webpack@5.104.1) '@storybook/semver': 7.3.2 '@storybook/store': 6.5.9(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@types/estree': 0.0.51 @@ -38148,7 +38216,7 @@ snapshots: require-from-string: 2.0.2 ts-dedent: 2.2.0 util-deprecate: 1.0.2 - webpack: 5.103.0(webpack-cli@6.0.1) + webpack: 5.105.2(webpack-cli@5.1.4) optionalDependencies: '@babel/core': 7.29.0 typescript: 4.9.4 @@ -38274,7 +38342,7 @@ snapshots: global: 4.4.0 lodash: 4.17.23 memoizerific: 1.11.3 - qs: 6.14.1 + qs: 6.14.2 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) ts-dedent: 2.2.0 @@ -38284,7 +38352,7 @@ snapshots: '@storybook/client-logger': 6.5.16 core-js: 3.48.0 memoizerific: 1.11.3 - qs: 6.14.1 + qs: 6.14.2 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) regenerator-runtime: 0.13.11 @@ -38294,7 +38362,7 @@ snapshots: '@storybook/client-logger': 6.5.9 core-js: 3.48.0 memoizerific: 1.11.3 - qs: 6.14.1 + qs: 6.14.2 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) regenerator-runtime: 0.13.11 @@ -38304,7 +38372,7 @@ snapshots: '@storybook/client-logger': 6.5.9 core-js: 3.48.0 memoizerific: 1.11.3 - qs: 6.14.1 + qs: 6.14.2 react: 19.1.0 react-dom: 19.1.0(react@19.1.0) regenerator-runtime: 0.13.11 @@ -38313,7 +38381,7 @@ snapshots: dependencies: '@storybook/client-logger': 7.4.0 memoizerific: 1.11.3 - qs: 6.14.1 + qs: 6.14.2 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -38321,7 +38389,7 @@ snapshots: dependencies: '@storybook/client-logger': 7.4.0 memoizerific: 1.11.3 - qs: 6.14.1 + qs: 6.14.2 react: 19.1.0 react-dom: 19.1.0(react@19.1.0) @@ -38656,7 +38724,7 @@ snapshots: markdown-to-jsx: 6.11.4(react@18.2.0) memoizerific: 1.11.3 polished: 4.3.1 - qs: 6.14.1 + qs: 6.14.2 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) react-draggable: 4.5.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) @@ -38682,7 +38750,7 @@ snapshots: '@storybook/theming': 6.5.16(react-dom@18.2.0(react@18.2.0))(react@18.2.0) core-js: 3.48.0 memoizerific: 1.11.3 - qs: 6.14.1 + qs: 6.14.2 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) regenerator-runtime: 0.13.11 @@ -38701,7 +38769,7 @@ snapshots: '@storybook/theming': 6.5.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0) core-js: 3.48.0 memoizerific: 1.11.3 - qs: 6.14.1 + qs: 6.14.2 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) regenerator-runtime: 0.13.11 @@ -38720,7 +38788,7 @@ snapshots: '@storybook/theming': 6.5.9(react-dom@19.1.0(react@19.1.0))(react@19.1.0) core-js: 3.48.0 memoizerific: 1.11.3 - qs: 6.14.1 + qs: 6.14.2 react: 19.1.0 react-dom: 19.1.0(react@19.1.0) regenerator-runtime: 0.13.11 @@ -39081,7 +39149,7 @@ snapshots: '@swagger-api/apidom-core': 1.4.0 '@swagger-api/apidom-error': 1.4.0 '@types/ramda': 0.30.2 - axios: 1.13.4 + axios: 1.13.5 minimatch: 7.4.6 process: 0.11.10 ramda: 0.30.1 @@ -39346,7 +39414,7 @@ snapshots: '@ts-morph/common@0.27.0': dependencies: fast-glob: 3.3.3 - minimatch: 10.1.2 + minimatch: 10.2.0 path-browserify: 1.0.1 '@tsconfig/node10@1.0.12': {} @@ -39615,6 +39683,8 @@ snapshots: dependencies: '@types/node': 22.15.24 + '@types/katex@0.16.8': {} + '@types/linkify-it@5.0.0': {} '@types/lodash.camelcase@4.3.0': @@ -39701,10 +39771,6 @@ snapshots: '@types/node': 16.18.126 form-data: 4.0.5 - '@types/node-forge@1.3.14': - dependencies: - '@types/node': 22.15.24 - '@types/node@14.18.63': {} '@types/node@16.18.126': {} @@ -39753,7 +39819,7 @@ snapshots: '@types/pretty-hrtime@1.0.3': {} - '@types/prismjs@1.26.5': {} + '@types/prismjs@1.26.6': {} '@types/prop-types@15.7.15': {} @@ -39935,8 +40001,6 @@ snapshots: '@types/vscode@1.81.0': {} - '@types/vscode@1.83.1': {} - '@types/vscode@1.84.0': {} '@types/webpack-env@1.18.8': {} @@ -39956,23 +40020,11 @@ snapshots: anymatch: 3.1.3 source-map: 0.6.1 - '@types/webpack@5.28.5': - dependencies: - '@types/node': 22.15.24 - tapable: 2.3.0 - webpack: 5.103.0(webpack-cli@6.0.1) - transitivePeerDependencies: - - '@swc/core' - - esbuild - - uglify-js - - webpack-cli - optional: true - '@types/webpack@5.28.5(@swc/core@1.15.11(@swc/helpers@0.5.18))': dependencies: '@types/node': 22.15.24 tapable: 2.3.0 - webpack: 5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18)) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18)) transitivePeerDependencies: - '@swc/core' - esbuild @@ -39984,7 +40036,7 @@ snapshots: dependencies: '@types/node': 22.15.24 tapable: 2.3.0 - webpack: 5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) transitivePeerDependencies: - '@swc/core' - esbuild @@ -39995,7 +40047,7 @@ snapshots: dependencies: '@types/node': 22.15.24 tapable: 2.3.0 - webpack: 5.103.0(webpack-cli@4.10.0) + webpack: 5.105.2(webpack-cli@4.10.0) transitivePeerDependencies: - '@swc/core' - esbuild @@ -40007,7 +40059,7 @@ snapshots: dependencies: '@types/node': 22.15.24 tapable: 2.3.0 - webpack: 5.103.0(webpack-cli@5.1.4) + webpack: 5.105.2(webpack-cli@5.1.4) transitivePeerDependencies: - '@swc/core' - esbuild @@ -40599,7 +40651,7 @@ snapshots: hosted-git-info: 4.1.0 jsonc-parser: 3.3.1 leven: 3.1.0 - markdown-it: 14.1.0 + markdown-it: 14.1.1 mime: 1.6.0 minimatch: 3.1.2 parse-semver: 1.1.1 @@ -40635,7 +40687,7 @@ snapshots: hosted-git-info: 4.1.0 jsonc-parser: 3.3.1 leven: 3.1.0 - markdown-it: 14.1.0 + markdown-it: 14.1.1 mime: 1.6.0 minimatch: 3.1.2 parse-semver: 1.1.1 @@ -40850,84 +40902,69 @@ snapshots: '@webassemblyjs/wast-parser': 1.9.0 '@xtuc/long': 4.2.2 - '@webpack-cli/configtest@1.2.0(webpack-cli@4.10.0)(webpack@5.99.9)': - dependencies: - webpack: 5.99.9(webpack-cli@4.10.0) - webpack-cli: 4.10.0(webpack-dev-server@5.2.1)(webpack@5.99.9) - - '@webpack-cli/configtest@2.1.1(webpack-cli@5.1.4)(webpack@5.99.9)': + '@webpack-cli/configtest@1.2.0(webpack-cli@4.10.0)(webpack@5.104.1)': dependencies: - webpack: 5.99.9(webpack-cli@5.1.4) - webpack-cli: 5.1.4(webpack@5.99.9) + webpack: 5.105.2(webpack-cli@4.10.0) + webpack-cli: 4.10.0(webpack-dev-server@5.2.3)(webpack@5.105.2) - '@webpack-cli/configtest@3.0.1(webpack-cli@6.0.1)(webpack@5.103.0)': + '@webpack-cli/configtest@2.1.1(webpack-cli@5.1.4)(webpack@5.105.2)': dependencies: - webpack: 5.103.0(webpack-cli@6.0.1) - webpack-cli: 6.0.1(webpack@5.103.0) + webpack: 5.105.2(webpack-cli@5.1.4) + webpack-cli: 5.1.4(webpack@5.105.2) - '@webpack-cli/configtest@3.0.1(webpack-cli@6.0.1)(webpack@5.99.9)': + '@webpack-cli/configtest@3.0.1(webpack-cli@6.0.1)(webpack@5.105.2)': dependencies: - webpack: 5.99.9(webpack-cli@6.0.1) - webpack-cli: 6.0.1(webpack@5.99.9) + webpack: 5.105.2(webpack-cli@6.0.1) + webpack-cli: 6.0.1(webpack@5.105.2) '@webpack-cli/info@1.5.0(webpack-cli@4.10.0)': dependencies: envinfo: 7.21.0 - webpack-cli: 4.10.0(webpack-dev-server@5.2.1)(webpack@5.99.9) - - '@webpack-cli/info@2.0.2(webpack-cli@5.1.4)(webpack@5.99.9)': - dependencies: - webpack: 5.99.9(webpack-cli@5.1.4) - webpack-cli: 5.1.4(webpack@5.99.9) + webpack-cli: 4.10.0(webpack-dev-server@5.2.3)(webpack@5.105.2) - '@webpack-cli/info@3.0.1(webpack-cli@6.0.1)(webpack@5.103.0)': + '@webpack-cli/info@2.0.2(webpack-cli@5.1.4)(webpack@5.105.2)': dependencies: - webpack: 5.103.0(webpack-cli@6.0.1) - webpack-cli: 6.0.1(webpack@5.103.0) + webpack: 5.105.2(webpack-cli@5.1.4) + webpack-cli: 5.1.4(webpack@5.105.2) - '@webpack-cli/info@3.0.1(webpack-cli@6.0.1)(webpack@5.99.9)': + '@webpack-cli/info@3.0.1(webpack-cli@6.0.1)(webpack@5.105.2)': dependencies: - webpack: 5.99.9(webpack-cli@6.0.1) - webpack-cli: 6.0.1(webpack@5.99.9) + webpack: 5.105.2(webpack-cli@6.0.1) + webpack-cli: 6.0.1(webpack@5.105.2) '@webpack-cli/serve@1.7.0(webpack-cli@4.10.0)': dependencies: - webpack-cli: 4.10.0(webpack@5.99.9) + webpack-cli: 4.10.0(webpack@5.105.2) - '@webpack-cli/serve@1.7.0(webpack-cli@4.10.0)(webpack-dev-server@5.2.1)': + '@webpack-cli/serve@1.7.0(webpack-cli@4.10.0)(webpack-dev-server@5.2.3)': dependencies: - webpack-cli: 4.10.0(webpack-dev-server@5.2.1)(webpack@5.99.9) + webpack-cli: 4.10.0(webpack-dev-server@5.2.3)(webpack@5.105.2) optionalDependencies: - webpack-dev-server: 5.2.1(webpack-cli@4.10.0)(webpack@5.99.9) + webpack-dev-server: 5.2.3(webpack-cli@4.10.0)(webpack@5.105.2) - '@webpack-cli/serve@2.0.5(webpack-cli@5.1.4)(webpack-dev-server@5.2.1)(webpack@5.99.9)': + '@webpack-cli/serve@2.0.5(webpack-cli@5.1.4)(webpack-dev-server@5.2.3)(webpack@5.105.2)': dependencies: - webpack: 5.99.9(webpack-cli@5.1.4) - webpack-cli: 5.1.4(webpack-dev-server@5.2.1)(webpack@5.99.9) + webpack: 5.105.2(webpack-cli@5.1.4) + webpack-cli: 5.1.4(webpack-dev-server@5.2.3)(webpack@5.105.2) optionalDependencies: - webpack-dev-server: 5.2.1(webpack-cli@5.1.4)(webpack@5.99.9) + webpack-dev-server: 5.2.3(webpack-cli@5.1.4)(webpack@5.105.2) - '@webpack-cli/serve@2.0.5(webpack-cli@5.1.4)(webpack@5.99.9)': + '@webpack-cli/serve@2.0.5(webpack-cli@5.1.4)(webpack@5.105.2)': dependencies: - webpack: 5.99.9(webpack-cli@5.1.4) - webpack-cli: 5.1.4(webpack@5.99.9) + webpack: 5.105.2(webpack-cli@5.1.4) + webpack-cli: 5.1.4(webpack@5.105.2) - '@webpack-cli/serve@3.0.1(webpack-cli@6.0.1)(webpack-dev-server@5.2.1)(webpack@5.99.9)': + '@webpack-cli/serve@3.0.1(webpack-cli@6.0.1)(webpack-dev-server@5.2.3)(webpack@5.105.2)': dependencies: - webpack: 5.99.9(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) - webpack-cli: 6.0.1(webpack-dev-server@5.2.1)(webpack@5.99.9) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) + webpack-cli: 6.0.1(webpack-dev-server@5.2.3)(webpack@5.104.1) optionalDependencies: - webpack-dev-server: 5.2.1(webpack-cli@6.0.1)(webpack@5.99.9) - - '@webpack-cli/serve@3.0.1(webpack-cli@6.0.1)(webpack@5.103.0)': - dependencies: - webpack: 5.103.0(webpack-cli@6.0.1) - webpack-cli: 6.0.1(webpack@5.103.0) + webpack-dev-server: 5.2.3(webpack-cli@6.0.1)(webpack@5.105.2) - '@webpack-cli/serve@3.0.1(webpack-cli@6.0.1)(webpack@5.99.9)': + '@webpack-cli/serve@3.0.1(webpack-cli@6.0.1)(webpack@5.105.2)': dependencies: - webpack: 5.99.9(webpack-cli@6.0.1) - webpack-cli: 6.0.1(webpack@5.99.9) + webpack: 5.105.2(webpack-cli@6.0.1) + webpack-cli: 6.0.1(webpack@5.105.2) '@xmldom/xmldom@0.7.13': {} @@ -41420,6 +41457,12 @@ snapshots: dependencies: safer-buffer: 2.1.2 + asn1js@3.0.7: + dependencies: + pvtsutils: 1.3.6 + pvutils: 1.1.5 + tslib: 2.8.1 + assert-plus@1.0.0: {} assert@1.5.1: @@ -41485,7 +41528,7 @@ snapshots: autoprefixer@10.4.19(postcss@8.5.3): dependencies: browserslist: 4.28.1 - caniuse-lite: 1.0.30001768 + caniuse-lite: 1.0.30001769 fraction.js: 4.3.7 normalize-range: 0.1.2 picocolors: 1.1.1 @@ -41495,7 +41538,7 @@ snapshots: autoprefixer@10.4.21(postcss@8.5.4): dependencies: browserslist: 4.28.1 - caniuse-lite: 1.0.30001768 + caniuse-lite: 1.0.30001769 fraction.js: 4.3.7 normalize-range: 0.1.2 picocolors: 1.1.1 @@ -41505,7 +41548,7 @@ snapshots: autoprefixer@6.7.7: dependencies: browserslist: 1.7.7 - caniuse-db: 1.0.30001768 + caniuse-db: 1.0.30001769 normalize-range: 0.1.2 num2fraction: 1.2.2 postcss: 5.2.18 @@ -41514,7 +41557,7 @@ snapshots: autoprefixer@7.1.6: dependencies: browserslist: 2.11.3 - caniuse-lite: 1.0.30001768 + caniuse-lite: 1.0.30001769 normalize-range: 0.1.2 num2fraction: 1.2.2 postcss: 6.0.23 @@ -41523,7 +41566,7 @@ snapshots: autoprefixer@9.8.8: dependencies: browserslist: 4.28.1 - caniuse-lite: 1.0.30001768 + caniuse-lite: 1.0.30001769 normalize-range: 0.1.2 num2fraction: 1.2.2 picocolors: 0.2.1 @@ -41544,23 +41587,7 @@ snapshots: axe-core@4.11.1: {} - axios@1.12.0: - dependencies: - follow-redirects: 1.15.11(debug@3.2.7) - form-data: 4.0.5 - proxy-from-env: 1.1.0 - transitivePeerDependencies: - - debug - - axios@1.13.4: - dependencies: - follow-redirects: 1.15.11(debug@3.2.7) - form-data: 4.0.5 - proxy-from-env: 1.1.0 - transitivePeerDependencies: - - debug - - axios@1.9.0: + axios@1.13.5: dependencies: follow-redirects: 1.15.11(debug@3.2.7) form-data: 4.0.5 @@ -41776,11 +41803,11 @@ snapshots: transitivePeerDependencies: - supports-color - babel-loader@10.0.0(@babel/core@7.27.1)(webpack@5.99.9): + babel-loader@10.0.0(@babel/core@7.27.1)(webpack@5.104.1): dependencies: '@babel/core': 7.27.1 find-up: 5.0.0 - webpack: 5.99.9(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) babel-loader@7.1.2(babel-core@7.0.0-bridge.0(@babel/core@7.27.1))(webpack@3.8.1): dependencies: @@ -41825,46 +41852,28 @@ snapshots: schema-utils: 2.7.1 webpack: 4.47.0 - babel-loader@8.4.1(@babel/core@7.27.1)(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1)): + babel-loader@8.4.1(@babel/core@7.27.1)(webpack@5.104.1): dependencies: '@babel/core': 7.27.1 find-cache-dir: 3.3.2 loader-utils: 2.0.4 make-dir: 3.1.0 schema-utils: 2.7.1 - webpack: 5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) - babel-loader@8.4.1(@babel/core@7.27.1)(webpack@5.103.0(webpack-cli@4.10.0)): - dependencies: - '@babel/core': 7.27.1 - find-cache-dir: 3.3.2 - loader-utils: 2.0.4 - make-dir: 3.1.0 - schema-utils: 2.7.1 - webpack: 5.103.0(webpack-cli@4.10.0) - - babel-loader@8.4.1(@babel/core@7.27.1)(webpack@5.99.9): - dependencies: - '@babel/core': 7.27.1 - find-cache-dir: 3.3.2 - loader-utils: 2.0.4 - make-dir: 3.1.0 - schema-utils: 2.7.1 - webpack: 5.99.9(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) - - babel-loader@9.2.1(@babel/core@7.27.1)(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@5.1.4)): + babel-loader@9.2.1(@babel/core@7.27.1)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))): dependencies: '@babel/core': 7.27.1 find-cache-dir: 4.0.0 schema-utils: 4.3.3 - webpack: 5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@5.1.4) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18)) - babel-loader@9.2.1(@babel/core@7.27.1)(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))): + babel-loader@9.2.1(@babel/core@7.27.1)(webpack@5.104.1): dependencies: '@babel/core': 7.27.1 find-cache-dir: 4.0.0 schema-utils: 4.3.3 - webpack: 5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18)) + webpack: 5.105.2(webpack-cli@5.1.4) babel-messages@6.23.0: dependencies: @@ -42469,6 +42478,10 @@ snapshots: balanced-match@2.0.0: {} + balanced-match@4.0.2: + dependencies: + jackspeak: 4.2.3 + base16@1.0.0: {} base64-js@1.5.1: {} @@ -42553,7 +42566,7 @@ snapshots: http-errors: 2.0.1 iconv-lite: 0.4.24 on-finished: 2.4.1 - qs: 6.14.1 + qs: 6.14.2 raw-body: 2.5.3 type-is: 1.6.18 unpipe: 1.0.0 @@ -42566,7 +42579,7 @@ snapshots: http-errors: 2.0.1 iconv-lite: 0.7.2 on-finished: 2.4.1 - qs: 6.14.1 + qs: 6.14.2 raw-body: 3.0.2 type-is: 2.0.1 transitivePeerDependencies: @@ -42590,7 +42603,7 @@ snapshots: boundary@2.0.0: {} - bowser@2.13.1: {} + bowser@2.14.1: {} boxen@1.3.0: dependencies: @@ -42642,6 +42655,10 @@ snapshots: dependencies: balanced-match: 1.0.2 + brace-expansion@5.0.2: + dependencies: + balanced-match: 4.0.2 + braces@3.0.3: dependencies: fill-range: 7.1.1 @@ -42708,17 +42725,17 @@ snapshots: browserslist@1.7.7: dependencies: - caniuse-db: 1.0.30001768 + caniuse-db: 1.0.30001769 electron-to-chromium: 1.5.286 browserslist@2.11.3: dependencies: - caniuse-lite: 1.0.30001768 + caniuse-lite: 1.0.30001769 electron-to-chromium: 1.5.286 browserslist@4.14.2: dependencies: - caniuse-lite: 1.0.30001768 + caniuse-lite: 1.0.30001769 electron-to-chromium: 1.5.286 escalade: 3.2.0 node-releases: 1.1.77 @@ -42726,7 +42743,7 @@ snapshots: browserslist@4.28.1: dependencies: baseline-browser-mapping: 2.9.19 - caniuse-lite: 1.0.30001768 + caniuse-lite: 1.0.30001769 electron-to-chromium: 1.5.286 node-releases: 2.0.27 update-browserslist-db: 1.2.3(browserslist@4.28.1) @@ -42808,6 +42825,8 @@ snapshots: bytes@3.1.2: {} + bytestreamjs@2.0.1: {} + c8@10.1.3: dependencies: '@bcoe/v8-coverage': 1.0.2 @@ -42938,7 +42957,7 @@ snapshots: cacheable@2.3.2: dependencies: '@cacheable/memory': 2.0.7 - '@cacheable/utils': 2.3.3 + '@cacheable/utils': 2.3.4 hookified: 1.15.1 keyv: 5.6.0 qified: 0.6.0 @@ -43007,20 +43026,20 @@ snapshots: caniuse-api@1.6.1: dependencies: browserslist: 1.7.7 - caniuse-db: 1.0.30001768 + caniuse-db: 1.0.30001769 lodash.memoize: 4.1.2 lodash.uniq: 4.5.0 caniuse-api@3.0.0: dependencies: browserslist: 4.28.1 - caniuse-lite: 1.0.30001768 + caniuse-lite: 1.0.30001769 lodash.memoize: 4.1.2 lodash.uniq: 4.5.0 - caniuse-db@1.0.30001768: {} + caniuse-db@1.0.30001769: {} - caniuse-lite@1.0.30001768: {} + caniuse-lite@1.0.30001769: {} canvas@3.2.1: dependencies: @@ -43143,7 +43162,7 @@ snapshots: parse5: 7.3.0 parse5-htmlparser2-tree-adapter: 7.1.0 parse5-parser-stream: 7.1.2 - undici: 7.20.0 + undici: 7.21.0 whatwg-mimetype: 4.0.0 chokidar@1.7.0: @@ -43313,7 +43332,7 @@ snapshots: is-wsl: 3.1.0 is64bit: 2.0.0 - clipboardy@5.2.1: + clipboardy@5.3.0: dependencies: clipboard-image: 0.1.0 execa: 9.6.1 @@ -43411,15 +43430,15 @@ snapshots: code-point-at@1.1.0: {} - codemirror-graphql@2.2.4(@codemirror/language@6.11.3)(codemirror@5.65.20)(graphql@16.11.0): + codemirror-graphql@2.2.4(@codemirror/language@6.11.3)(codemirror@5.65.21)(graphql@16.11.0): dependencies: '@codemirror/language': 6.11.3 '@types/codemirror': 0.0.90 - codemirror: 5.65.20 + codemirror: 5.65.21 graphql: 16.11.0 graphql-language-service: 5.5.0(graphql@16.11.0) - codemirror@5.65.20: {} + codemirror@5.65.21: {} codemirror@6.0.2: dependencies: @@ -43635,23 +43654,14 @@ snapshots: dependencies: toggle-selection: 1.0.6 - copy-webpack-plugin@13.0.0(webpack@5.103.0): - dependencies: - glob-parent: 6.0.2 - normalize-path: 3.0.0 - schema-utils: 4.3.3 - serialize-javascript: 6.0.2 - tinyglobby: 0.2.15 - webpack: 5.103.0(webpack-cli@6.0.1) - - copy-webpack-plugin@13.0.0(webpack@5.99.9): + copy-webpack-plugin@13.0.0(webpack@5.104.1): dependencies: glob-parent: 6.0.2 normalize-path: 3.0.0 schema-utils: 4.3.3 serialize-javascript: 6.0.2 tinyglobby: 0.2.15 - webpack: 5.99.9(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) copyfiles@2.4.1: dependencies: @@ -43900,7 +43910,7 @@ snapshots: dependencies: postcss: 8.5.4 - css-functions-list@3.2.3: {} + css-functions-list@3.3.3: {} css-loader@0.28.7: dependencies: @@ -43970,7 +43980,7 @@ snapshots: semver: 6.3.1 webpack: 4.47.0 - css-loader@5.2.7(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1)): + css-loader@5.2.7(webpack@5.105.2): dependencies: icss-utils: 5.1.0(postcss@8.5.4) loader-utils: 2.0.4 @@ -43982,63 +43992,9 @@ snapshots: postcss-value-parser: 4.2.0 schema-utils: 3.3.0 semver: 7.7.4 - webpack: 5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) + webpack: 5.104.1(webpack-cli@5.1.4) - css-loader@5.2.7(webpack@5.103.0(webpack-cli@4.10.0)): - dependencies: - icss-utils: 5.1.0(postcss@8.5.4) - loader-utils: 2.0.4 - postcss: 8.5.4 - postcss-modules-extract-imports: 3.1.0(postcss@8.5.4) - postcss-modules-local-by-default: 4.2.0(postcss@8.5.4) - postcss-modules-scope: 3.2.1(postcss@8.5.4) - postcss-modules-values: 4.0.0(postcss@8.5.4) - postcss-value-parser: 4.2.0 - schema-utils: 3.3.0 - semver: 7.7.4 - webpack: 5.103.0(webpack-cli@4.10.0) - - css-loader@5.2.7(webpack@5.99.9): - dependencies: - icss-utils: 5.1.0(postcss@8.5.4) - loader-utils: 2.0.4 - postcss: 8.5.4 - postcss-modules-extract-imports: 3.1.0(postcss@8.5.4) - postcss-modules-local-by-default: 4.2.0(postcss@8.5.4) - postcss-modules-scope: 3.2.1(postcss@8.5.4) - postcss-modules-values: 4.0.0(postcss@8.5.4) - postcss-value-parser: 4.2.0 - schema-utils: 3.3.0 - semver: 7.7.4 - webpack: 5.99.9(webpack-cli@5.1.4) - - css-loader@6.11.0(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12)): - dependencies: - icss-utils: 5.1.0(postcss@8.5.4) - postcss: 8.5.4 - postcss-modules-extract-imports: 3.1.0(postcss@8.5.4) - postcss-modules-local-by-default: 4.2.0(postcss@8.5.4) - postcss-modules-scope: 3.2.1(postcss@8.5.4) - postcss-modules-values: 4.0.0(postcss@8.5.4) - postcss-value-parser: 4.2.0 - semver: 7.7.4 - optionalDependencies: - webpack: 5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12) - - css-loader@6.11.0(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@5.1.4)): - dependencies: - icss-utils: 5.1.0(postcss@8.5.4) - postcss: 8.5.4 - postcss-modules-extract-imports: 3.1.0(postcss@8.5.4) - postcss-modules-local-by-default: 4.2.0(postcss@8.5.4) - postcss-modules-scope: 3.2.1(postcss@8.5.4) - postcss-modules-values: 4.0.0(postcss@8.5.4) - postcss-value-parser: 4.2.0 - semver: 7.7.4 - optionalDependencies: - webpack: 5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@5.1.4) - - css-loader@6.11.0(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))): + css-loader@6.11.0(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12)): dependencies: icss-utils: 5.1.0(postcss@8.5.4) postcss: 8.5.4 @@ -44049,9 +44005,9 @@ snapshots: postcss-value-parser: 4.2.0 semver: 7.7.4 optionalDependencies: - webpack: 5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18)) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12) - css-loader@6.11.0(webpack@5.103.0(webpack-cli@5.1.4)): + css-loader@6.11.0(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))): dependencies: icss-utils: 5.1.0(postcss@8.5.4) postcss: 8.5.4 @@ -44062,9 +44018,9 @@ snapshots: postcss-value-parser: 4.2.0 semver: 7.7.4 optionalDependencies: - webpack: 5.103.0(webpack-cli@5.1.4) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18)) - css-loader@7.1.2(webpack@5.103.0): + css-loader@6.11.0(webpack@5.105.2): dependencies: icss-utils: 5.1.0(postcss@8.5.4) postcss: 8.5.4 @@ -44075,9 +44031,9 @@ snapshots: postcss-value-parser: 4.2.0 semver: 7.7.4 optionalDependencies: - webpack: 5.103.0(webpack-cli@6.0.1) + webpack: 5.105.2(webpack-cli@5.1.4) - css-loader@7.1.2(webpack@5.99.9): + css-loader@7.1.3(webpack@5.105.2): dependencies: icss-utils: 5.1.0(postcss@8.5.4) postcss: 8.5.4 @@ -44088,7 +44044,7 @@ snapshots: postcss-value-parser: 4.2.0 semver: 7.7.4 optionalDependencies: - webpack: 5.99.9(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) css-select@4.3.0: dependencies: @@ -45013,6 +44969,8 @@ snapshots: es-module-lexer@1.7.0: {} + es-module-lexer@2.0.0: {} + es-object-atoms@1.1.1: dependencies: es-errors: 1.3.0 @@ -45725,7 +45683,7 @@ snapshots: parseurl: 1.3.3 path-to-regexp: 0.1.12 proxy-addr: 2.0.7 - qs: 6.14.1 + qs: 6.14.2 range-parser: 1.2.1 safe-buffer: 5.2.1 send: 0.19.2 @@ -45758,7 +45716,7 @@ snapshots: once: 1.4.0 parseurl: 1.3.3 proxy-addr: 2.0.7 - qs: 6.14.1 + qs: 6.14.2 range-parser: 1.2.1 router: 2.2.0 send: 1.2.1 @@ -45921,10 +45879,6 @@ snapshots: dependencies: escape-string-regexp: 1.0.5 - figures@3.2.0: - dependencies: - escape-string-regexp: 1.0.5 - figures@6.1.0: dependencies: is-unicode-supported: 2.1.0 @@ -45967,17 +45921,11 @@ snapshots: schema-utils: 3.3.0 webpack: 4.47.0 - file-loader@6.2.0(webpack@5.103.0): - dependencies: - loader-utils: 2.0.4 - schema-utils: 3.3.0 - webpack: 5.103.0(webpack-cli@6.0.1) - - file-loader@6.2.0(webpack@5.99.9): + file-loader@6.2.0(webpack@5.105.2): dependencies: loader-utils: 2.0.4 schema-utils: 3.3.0 - webpack: 5.99.9(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) file-system-cache@1.1.0: dependencies: @@ -46144,7 +46092,7 @@ snapshots: flatten@1.0.3: {} - flow-parser@0.299.0: {} + flow-parser@0.301.0: {} flush-write-stream@1.1.1: dependencies: @@ -46284,27 +46232,7 @@ snapshots: optionalDependencies: eslint: 9.39.2(jiti@2.6.1) - fork-ts-checker-webpack-plugin@6.5.3(eslint@9.39.2(jiti@2.6.1))(typescript@5.8.3)(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1)): - dependencies: - '@babel/code-frame': 7.29.0 - '@types/json-schema': 7.0.15 - chalk: 4.1.2 - chokidar: 3.6.0 - cosmiconfig: 6.0.0 - deepmerge: 4.3.1 - fs-extra: 9.1.0 - glob: 7.2.3 - memfs: 3.5.3 - minimatch: 3.1.2 - schema-utils: 2.7.0 - semver: 7.7.4 - tapable: 1.1.3 - typescript: 5.8.3 - webpack: 5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) - optionalDependencies: - eslint: 9.39.2(jiti@2.6.1) - - fork-ts-checker-webpack-plugin@6.5.3(eslint@9.39.2(jiti@2.6.1))(typescript@5.8.3)(webpack@5.103.0(webpack-cli@4.10.0)): + fork-ts-checker-webpack-plugin@6.5.3(eslint@9.39.2(jiti@2.6.1))(typescript@5.8.3)(webpack@5.104.1): dependencies: '@babel/code-frame': 7.29.0 '@types/json-schema': 7.0.15 @@ -46320,11 +46248,11 @@ snapshots: semver: 7.7.4 tapable: 1.1.3 typescript: 5.8.3 - webpack: 5.103.0(webpack-cli@4.10.0) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) optionalDependencies: eslint: 9.39.2(jiti@2.6.1) - fork-ts-checker-webpack-plugin@8.0.0(typescript@5.8.3)(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12)): + fork-ts-checker-webpack-plugin@8.0.0(typescript@5.8.3)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12)): dependencies: '@babel/code-frame': 7.29.0 chalk: 4.1.2 @@ -46339,9 +46267,9 @@ snapshots: semver: 7.7.4 tapable: 2.3.0 typescript: 5.8.3 - webpack: 5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12) - fork-ts-checker-webpack-plugin@8.0.0(typescript@5.8.3)(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@5.1.4)): + fork-ts-checker-webpack-plugin@8.0.0(typescript@5.8.3)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))): dependencies: '@babel/code-frame': 7.29.0 chalk: 4.1.2 @@ -46356,9 +46284,9 @@ snapshots: semver: 7.7.4 tapable: 2.3.0 typescript: 5.8.3 - webpack: 5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@5.1.4) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18)) - fork-ts-checker-webpack-plugin@8.0.0(typescript@5.8.3)(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))): + fork-ts-checker-webpack-plugin@8.0.0(typescript@5.8.3)(webpack@5.105.2): dependencies: '@babel/code-frame': 7.29.0 chalk: 4.1.2 @@ -46373,26 +46301,9 @@ snapshots: semver: 7.7.4 tapable: 2.3.0 typescript: 5.8.3 - webpack: 5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18)) + webpack: 5.105.2(webpack-cli@5.1.4) - fork-ts-checker-webpack-plugin@8.0.0(typescript@5.8.3)(webpack@5.103.0(webpack-cli@5.1.4)): - dependencies: - '@babel/code-frame': 7.29.0 - chalk: 4.1.2 - chokidar: 3.6.0 - cosmiconfig: 7.1.0 - deepmerge: 4.3.1 - fs-extra: 10.1.0 - memfs: 3.5.3 - minimatch: 3.1.2 - node-abort-controller: 3.1.1 - schema-utils: 3.3.0 - semver: 7.7.4 - tapable: 2.3.0 - typescript: 5.8.3 - webpack: 5.103.0(webpack-cli@5.1.4) - - fork-ts-checker-webpack-plugin@9.1.0(typescript@5.8.3)(webpack@5.99.9): + fork-ts-checker-webpack-plugin@9.1.0(typescript@5.8.3)(webpack@5.105.2): dependencies: '@babel/code-frame': 7.29.0 chalk: 4.1.2 @@ -46407,7 +46318,7 @@ snapshots: semver: 7.7.4 tapable: 2.3.0 typescript: 5.8.3 - webpack: 5.99.9(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) form-data-encoder@2.1.4: {} @@ -46437,6 +46348,16 @@ snapshots: fraction.js@4.3.7: {} + framer-motion@11.18.2(@emotion/is-prop-valid@1.4.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + dependencies: + motion-dom: 11.18.1 + motion-utils: 11.18.1 + tslib: 2.8.1 + optionalDependencies: + '@emotion/is-prop-valid': 1.4.0 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + framer-motion@6.5.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@motionone/dom': 10.12.0 @@ -46769,8 +46690,8 @@ snapshots: glob@11.0.2: dependencies: foreground-child: 3.3.1 - jackspeak: 4.2.1 - minimatch: 10.1.2 + jackspeak: 4.2.3 + minimatch: 10.2.0 minipass: 7.1.2 package-json-from-dist: 1.0.1 path-scurry: 2.0.1 @@ -46778,8 +46699,8 @@ snapshots: glob@11.1.0: dependencies: foreground-child: 3.3.1 - jackspeak: 4.2.1 - minimatch: 10.1.2 + jackspeak: 4.2.3 + minimatch: 10.2.0 minipass: 7.1.2 package-json-from-dist: 1.0.1 path-scurry: 2.0.1 @@ -47126,6 +47047,28 @@ snapshots: unist-util-is: 4.1.0 web-namespaces: 1.1.4 + hast-util-from-dom@5.0.1: + dependencies: + '@types/hast': 3.0.4 + hastscript: 9.0.1 + web-namespaces: 2.0.1 + + hast-util-from-html-isomorphic@2.0.0: + dependencies: + '@types/hast': 3.0.4 + hast-util-from-dom: 5.0.1 + hast-util-from-html: 2.0.3 + unist-util-remove-position: 5.0.0 + + hast-util-from-html@2.0.3: + dependencies: + '@types/hast': 3.0.4 + devlop: 1.1.0 + hast-util-from-parse5: 8.0.3 + parse5: 7.3.0 + vfile: 6.0.3 + vfile-message: 4.0.3 + hast-util-from-parse5@6.0.1: dependencies: '@types/parse5': 5.0.3 @@ -47156,6 +47099,10 @@ snapshots: vfile-location: 5.0.3 web-namespaces: 2.0.1 + hast-util-is-element@3.0.0: + dependencies: + '@types/hast': 3.0.4 + hast-util-parse-selector@2.2.5: {} hast-util-parse-selector@3.1.1: @@ -47256,6 +47203,13 @@ snapshots: web-namespaces: 2.0.1 zwitch: 2.0.4 + hast-util-to-text@4.0.2: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + hast-util-is-element: 3.0.0 + unist-util-find-after: 5.0.0 + hast-util-whitespace@3.0.0: dependencies: '@types/hast': 3.0.4 @@ -47315,7 +47269,7 @@ snapshots: dependencies: parse-passwd: 1.0.0 - hono@4.11.7: {} + hono@4.11.9: {} hookified@1.15.1: {} @@ -47386,8 +47340,6 @@ snapshots: html-tags@3.3.1: {} - html-to-image@1.10.8: {} - html-to-image@1.11.11: {} html-url-attributes@3.0.1: {} @@ -47447,37 +47399,7 @@ snapshots: util.promisify: 1.0.0 webpack: 4.47.0 - html-webpack-plugin@5.6.6(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12)): - dependencies: - '@types/html-minifier-terser': 6.1.0 - html-minifier-terser: 6.1.0 - lodash: 4.17.23 - pretty-error: 4.0.0 - tapable: 2.3.0 - optionalDependencies: - webpack: 5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12) - - html-webpack-plugin@5.6.6(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@5.1.4)): - dependencies: - '@types/html-minifier-terser': 6.1.0 - html-minifier-terser: 6.1.0 - lodash: 4.17.23 - pretty-error: 4.0.0 - tapable: 2.3.0 - optionalDependencies: - webpack: 5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@5.1.4) - - html-webpack-plugin@5.6.6(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1)): - dependencies: - '@types/html-minifier-terser': 6.1.0 - html-minifier-terser: 6.1.0 - lodash: 4.17.23 - pretty-error: 4.0.0 - tapable: 2.3.0 - optionalDependencies: - webpack: 5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) - - html-webpack-plugin@5.6.6(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))): + html-webpack-plugin@5.6.6(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12)): dependencies: '@types/html-minifier-terser': 6.1.0 html-minifier-terser: 6.1.0 @@ -47485,9 +47407,9 @@ snapshots: pretty-error: 4.0.0 tapable: 2.3.0 optionalDependencies: - webpack: 5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18)) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12) - html-webpack-plugin@5.6.6(webpack@5.103.0(webpack-cli@4.10.0)): + html-webpack-plugin@5.6.6(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))): dependencies: '@types/html-minifier-terser': 6.1.0 html-minifier-terser: 6.1.0 @@ -47495,9 +47417,9 @@ snapshots: pretty-error: 4.0.0 tapable: 2.3.0 optionalDependencies: - webpack: 5.103.0(webpack-cli@4.10.0) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18)) - html-webpack-plugin@5.6.6(webpack@5.103.0(webpack-cli@5.1.4)): + html-webpack-plugin@5.6.6(webpack@5.104.1): dependencies: '@types/html-minifier-terser': 6.1.0 html-minifier-terser: 6.1.0 @@ -47505,7 +47427,7 @@ snapshots: pretty-error: 4.0.0 tapable: 2.3.0 optionalDependencies: - webpack: 5.103.0(webpack-cli@5.1.4) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) htmlparser2@10.1.0: dependencies: @@ -48194,7 +48116,7 @@ snapshots: isexe@2.0.0: {} - isexe@3.1.2: {} + isexe@3.1.5: {} isobject@3.0.1: {} @@ -48365,7 +48287,7 @@ snapshots: optionalDependencies: '@pkgjs/parseargs': 0.11.0 - jackspeak@4.2.1: + jackspeak@4.2.3: dependencies: '@isaacs/cliui': 9.0.0 @@ -48978,10 +48900,7 @@ snapshots: pretty-format: 25.5.0 throat: 5.0.0 transitivePeerDependencies: - - bufferutil - - canvas - supports-color - - utf-8-validate jest-leak-detector@25.5.0: dependencies: @@ -49783,7 +49702,7 @@ snapshots: '@babel/register': 7.28.6(@babel/core@7.27.1) babel-core: 7.0.0-bridge.0(@babel/core@7.27.1) chalk: 4.1.2 - flow-parser: 0.299.0 + flow-parser: 0.301.0 graceful-fs: 4.2.11 micromatch: 4.0.8 neo-async: 2.6.2 @@ -49810,7 +49729,7 @@ snapshots: '@babel/register': 7.28.6(@babel/core@7.27.1) babel-core: 7.0.0-bridge.0(@babel/core@7.27.1) chalk: 4.1.2 - flow-parser: 0.299.0 + flow-parser: 0.301.0 graceful-fs: 4.2.11 micromatch: 4.0.8 neo-async: 2.6.2 @@ -50069,6 +49988,10 @@ snapshots: jwt-decode@4.0.0: {} + katex@0.16.28: + dependencies: + commander: 8.3.0 + keytar@7.9.0: dependencies: node-addon-api: 4.3.0 @@ -50422,7 +50345,7 @@ snapshots: lru-cache@10.4.3: {} - lru-cache@11.2.5: {} + lru-cache@11.2.6: {} lru-cache@4.1.5: dependencies: @@ -50531,7 +50454,7 @@ snapshots: mdurl: 1.0.1 uc.micro: 1.0.6 - markdown-it@14.1.0: + markdown-it@14.1.1: dependencies: argparse: 2.0.1 entities: 4.5.0 @@ -50684,6 +50607,18 @@ snapshots: transitivePeerDependencies: - supports-color + mdast-util-math@3.0.0: + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + devlop: 1.1.0 + longest-streak: 3.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + unist-util-remove-position: 5.0.0 + transitivePeerDependencies: + - supports-color + mdast-util-mdx-expression@2.0.1: dependencies: '@types/estree-jsx': 1.0.5 @@ -50988,6 +50923,16 @@ snapshots: micromark-util-combine-extensions: 2.0.1 micromark-util-types: 2.0.2 + micromark-extension-math@3.1.0: + dependencies: + '@types/katex': 0.16.8 + devlop: 1.1.0 + katex: 0.16.28 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + micromark-extension-mdx-expression@3.0.1: dependencies: '@types/estree': 1.0.8 @@ -51227,11 +51172,11 @@ snapshots: min-indent@1.0.1: {} - mini-css-extract-plugin@2.9.2(webpack@5.99.9): + mini-css-extract-plugin@2.9.2(webpack@5.104.1): dependencies: schema-utils: 4.3.3 tapable: 2.3.0 - webpack: 5.99.9(webpack-cli@4.10.0) + webpack: 5.105.2(webpack-cli@4.10.0) minim@0.23.8: dependencies: @@ -51241,9 +51186,9 @@ snapshots: minimalistic-crypto-utils@1.0.1: {} - minimatch@10.1.2: + minimatch@10.2.0: dependencies: - '@isaacs/brace-expansion': 5.0.1 + brace-expansion: 5.0.2 minimatch@3.0.3: dependencies: @@ -51484,6 +51429,12 @@ snapshots: type-fest: 4.41.0 typescript: 5.8.3 + motion-dom@11.18.1: + dependencies: + motion-utils: 11.18.1 + + motion-utils@11.18.1: {} + mousetrap@1.6.5: {} move-concurrently@1.0.1: @@ -51627,8 +51578,6 @@ snapshots: node-forge@0.10.0: {} - node-forge@1.3.3: {} - node-gyp-build@4.8.4: optional: true @@ -51691,15 +51640,15 @@ snapshots: util: 0.11.1 vm-browserify: 1.1.2 - node-loader@2.0.0(webpack@5.99.9): + node-loader@2.0.0(webpack@5.104.1): dependencies: loader-utils: 2.0.4 - webpack: 5.99.9(webpack-cli@5.1.4) + webpack: 5.105.2(webpack-cli@5.1.4) - node-loader@2.1.0(webpack@5.99.9): + node-loader@2.1.0(webpack@5.105.2): dependencies: loader-utils: 2.0.4 - webpack: 5.99.9(webpack-cli@4.10.0) + webpack: 5.105.2(webpack-cli@4.10.0) node-notifier@5.4.5: dependencies: @@ -52323,7 +52272,7 @@ snapshots: path-scurry@2.0.1: dependencies: - lru-cache: 11.2.5 + lru-cache: 11.2.6 minipass: 7.1.2 path-to-regexp@0.1.12: {} @@ -52464,6 +52413,15 @@ snapshots: dependencies: find-up: 3.0.0 + pkijs@3.3.3: + dependencies: + '@noble/hashes': 1.4.0 + asn1js: 3.0.7 + bytestreamjs: 2.0.1 + pvtsutils: 1.3.6 + pvutils: 1.1.5 + tslib: 2.8.1 + playwright-core@1.55.1: {} playwright@1.55.1: @@ -52698,25 +52656,25 @@ snapshots: semver: 7.7.4 webpack: 4.47.0 - postcss-loader@8.1.1(postcss@8.5.3)(typescript@5.8.3)(webpack@5.99.9): + postcss-loader@8.1.1(postcss@8.5.3)(typescript@5.8.3)(webpack@5.104.1): dependencies: cosmiconfig: 9.0.0(typescript@5.8.3) jiti: 1.21.7 postcss: 8.5.3 semver: 7.7.4 optionalDependencies: - webpack: 5.99.9(webpack-cli@6.0.1) + webpack: 5.105.2(webpack-cli@6.0.1) transitivePeerDependencies: - typescript - postcss-loader@8.1.1(postcss@8.5.4)(typescript@5.8.3)(webpack@5.99.9): + postcss-loader@8.1.1(postcss@8.5.4)(typescript@5.8.3)(webpack@5.104.1): dependencies: cosmiconfig: 9.0.0(typescript@5.8.3) jiti: 1.21.7 postcss: 8.5.4 semver: 7.7.4 optionalDependencies: - webpack: 5.99.9(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) transitivePeerDependencies: - typescript @@ -53161,7 +53119,7 @@ snapshots: prism-react-renderer@2.4.1(react@18.2.0): dependencies: - '@types/prismjs': 1.26.5 + '@types/prismjs': 1.26.6 clsx: 2.1.1 react: 18.2.0 @@ -53281,10 +53239,10 @@ snapshots: prosemirror-state: 1.4.3 w3c-keyname: 2.2.8 - prosemirror-markdown@1.13.2: + prosemirror-markdown@1.13.4: dependencies: '@types/markdown-it': 14.1.2 - markdown-it: 14.1.0 + markdown-it: 14.1.1 prosemirror-model: 1.25.4 prosemirror-model@1.25.4: @@ -53406,18 +53364,22 @@ snapshots: pure-rand@7.0.1: {} + pvtsutils@1.3.6: + dependencies: + tslib: 2.8.1 + + pvutils@1.1.5: {} + q@1.5.1: {} qified@0.6.0: dependencies: hookified: 1.15.1 - qs@6.14.1: + qs@6.14.2: dependencies: side-channel: 1.1.0 - qs@6.5.3: {} - query-string@4.3.4: dependencies: object-assign: 4.1.1 @@ -54429,6 +54391,8 @@ snapshots: redux@5.0.1: {} + reflect-metadata@0.2.2: {} + reflect.getprototypeof@1.0.10: dependencies: call-bind: 1.0.8 @@ -54509,6 +54473,16 @@ snapshots: dependencies: jsesc: 3.1.0 + rehype-katex@7.0.1: + dependencies: + '@types/hast': 3.0.4 + '@types/katex': 0.16.8 + hast-util-from-html-isomorphic: 2.0.0 + hast-util-to-text: 4.0.2 + katex: 0.16.28 + unist-util-visit-parents: 6.0.2 + vfile: 6.0.3 + rehype-raw@6.1.0: dependencies: '@types/hast': 2.3.10 @@ -54558,6 +54532,15 @@ snapshots: transitivePeerDependencies: - supports-color + remark-math@6.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-math: 3.0.0 + micromark-extension-math: 3.1.0 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + remark-mdx@1.6.22: dependencies: '@babel/core': 7.12.9 @@ -54681,7 +54664,7 @@ snapshots: mime-types: 2.1.35 oauth-sign: 0.9.0 performance-now: 2.1.0 - qs: 6.5.3 + qs: 6.14.2 safe-buffer: 5.2.1 tough-cookie: 2.5.0 tunnel-agent: 0.6.0 @@ -55027,20 +55010,20 @@ snapshots: dependencies: truncate-utf8-bytes: 1.0.2 - sass-loader@13.2.0(sass@1.89.0)(webpack@5.99.9): + sass-loader@13.2.0(sass@1.89.0)(webpack@5.104.1): dependencies: klona: 2.0.6 neo-async: 2.6.2 - webpack: 5.99.9(webpack-cli@5.1.4) + webpack: 5.105.2(webpack-cli@5.1.4) optionalDependencies: sass: 1.89.0 - sass-loader@16.0.5(sass@1.89.0)(webpack@5.99.9): + sass-loader@16.0.5(sass@1.89.0)(webpack@5.104.1): dependencies: neo-async: 2.6.2 optionalDependencies: sass: 1.89.0 - webpack: 5.99.9(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) sass@1.89.0: dependencies: @@ -55138,10 +55121,10 @@ snapshots: dependencies: node-forge: 0.10.0 - selfsigned@2.4.1: + selfsigned@5.5.0: dependencies: - '@types/node-forge': 1.3.14 - node-forge: 1.3.3 + '@peculiar/x509': 1.14.3 + pkijs: 3.3.3 semver-diff@2.1.0: dependencies: @@ -55467,18 +55450,18 @@ snapshots: async: 2.6.4 loader-utils: 1.4.2 - source-map-loader@4.0.1(webpack@5.99.9): + source-map-loader@4.0.1(webpack@5.104.1): dependencies: abab: 2.0.6 iconv-lite: 0.6.3 source-map-js: 1.2.1 - webpack: 5.99.9(webpack-cli@5.1.4) + webpack: 5.105.2(webpack-cli@5.1.4) - source-map-loader@5.0.0(webpack@5.99.9): + source-map-loader@5.0.0(webpack@5.105.2): dependencies: iconv-lite: 0.6.3 source-map-js: 1.2.1 - webpack: 5.99.9(webpack-cli@5.1.4) + webpack: 5.105.2(webpack-cli@5.1.4) source-map-resolve@0.6.0: dependencies: @@ -55943,43 +55926,33 @@ snapshots: schema-utils: 2.7.1 webpack: 4.47.0 - style-loader@1.3.0(webpack@5.99.9): + style-loader@1.3.0(webpack@5.105.2): dependencies: loader-utils: 2.0.4 schema-utils: 2.7.1 - webpack: 5.99.9(webpack-cli@5.1.4) - - style-loader@2.0.0(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1)): - dependencies: - loader-utils: 2.0.4 - schema-utils: 3.3.0 - webpack: 5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) + webpack: 5.105.2(webpack-cli@5.1.4) - style-loader@2.0.0(webpack@5.103.0(webpack-cli@4.10.0)): + style-loader@2.0.0(webpack@5.105.2): dependencies: loader-utils: 2.0.4 schema-utils: 3.3.0 - webpack: 5.103.0(webpack-cli@4.10.0) - - style-loader@3.3.4(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12)): - dependencies: - webpack: 5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) - style-loader@3.3.4(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@5.1.4)): + style-loader@3.3.4(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12)): dependencies: - webpack: 5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@5.1.4) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12) - style-loader@3.3.4(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))): + style-loader@3.3.4(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))): dependencies: - webpack: 5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18)) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18)) - style-loader@3.3.4(webpack@5.103.0(webpack-cli@5.1.4)): + style-loader@3.3.4(webpack@5.105.2): dependencies: - webpack: 5.103.0(webpack-cli@5.1.4) + webpack: 5.105.2(webpack-cli@5.1.4) - style-loader@4.0.0(webpack@5.99.9): + style-loader@4.0.0(webpack@5.105.2): dependencies: - webpack: 5.99.9(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) style-mod@4.1.3: {} @@ -56025,7 +55998,7 @@ snapshots: balanced-match: 2.0.0 colord: 2.9.3 cosmiconfig: 9.0.0(typescript@5.8.3) - css-functions-list: 3.2.3 + css-functions-list: 3.3.3 css-tree: 3.1.0 debug: 4.4.3(supports-color@8.1.1) fast-glob: 3.3.3 @@ -56126,10 +56099,10 @@ snapshots: svg-tags@1.0.0: {} - svg-url-loader@8.0.0(webpack@5.99.9): + svg-url-loader@8.0.0(webpack@5.105.2): dependencies: - file-loader: 6.2.0(webpack@5.99.9) - webpack: 5.99.9(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) + file-loader: 6.2.0(webpack@5.104.1) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) svg2ttf@4.3.0: dependencies: @@ -56318,17 +56291,17 @@ snapshots: - '@types/react' - debug - swc-loader@0.2.7(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@5.1.4)): + swc-loader@0.2.7(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))): dependencies: '@swc/core': 1.15.11(@swc/helpers@0.5.18) '@swc/counter': 0.1.3 - webpack: 5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@5.1.4) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18)) - swc-loader@0.2.7(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))): + swc-loader@0.2.7(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack@5.104.1): dependencies: '@swc/core': 1.15.11(@swc/helpers@0.5.18) '@swc/counter': 0.1.3 - webpack: 5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18)) + webpack: 5.105.2(webpack-cli@5.1.4) symbol-tree@3.2.4: {} @@ -56591,106 +56564,100 @@ snapshots: webpack: 4.47.0 webpack-sources: 1.4.3 - terser-webpack-plugin@5.3.10(webpack@5.99.9): + terser-webpack-plugin@5.3.10(webpack@5.104.1): dependencies: '@jridgewell/trace-mapping': 0.3.31 jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.2 terser: 5.46.0 - webpack: 5.99.9(webpack-cli@6.0.1) + webpack: 5.104.1(webpack-cli@6.0.1) - terser-webpack-plugin@5.3.14(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12)(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12)): + terser-webpack-plugin@5.3.14(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12)): dependencies: '@jridgewell/trace-mapping': 0.3.31 jest-worker: 27.5.1 schema-utils: 4.3.3 serialize-javascript: 6.0.2 terser: 5.46.0 - webpack: 5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12) optionalDependencies: '@swc/core': 1.15.11(@swc/helpers@0.5.18) esbuild: 0.25.12 - terser-webpack-plugin@5.3.14(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@5.1.4)): - dependencies: - '@jridgewell/trace-mapping': 0.3.31 - jest-worker: 27.5.1 - schema-utils: 4.3.3 - serialize-javascript: 6.0.2 - terser: 5.46.0 - webpack: 5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@5.1.4) - optionalDependencies: - '@swc/core': 1.15.11(@swc/helpers@0.5.18) - - terser-webpack-plugin@5.3.14(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1)): + terser-webpack-plugin@5.3.14(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))): dependencies: '@jridgewell/trace-mapping': 0.3.31 jest-worker: 27.5.1 schema-utils: 4.3.3 serialize-javascript: 6.0.2 terser: 5.46.0 - webpack: 5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18)) optionalDependencies: '@swc/core': 1.15.11(@swc/helpers@0.5.18) - terser-webpack-plugin@5.3.14(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))): + terser-webpack-plugin@5.3.14(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack@5.104.1): dependencies: '@jridgewell/trace-mapping': 0.3.31 jest-worker: 27.5.1 schema-utils: 4.3.3 serialize-javascript: 6.0.2 terser: 5.46.0 - webpack: 5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18)) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) optionalDependencies: '@swc/core': 1.15.11(@swc/helpers@0.5.18) - terser-webpack-plugin@5.3.14(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack@5.99.9): + terser-webpack-plugin@5.3.14(webpack@5.104.1): dependencies: '@jridgewell/trace-mapping': 0.3.31 jest-worker: 27.5.1 schema-utils: 4.3.3 serialize-javascript: 6.0.2 terser: 5.46.0 - webpack: 5.99.9(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) - optionalDependencies: - '@swc/core': 1.15.11(@swc/helpers@0.5.18) + webpack: 5.104.1(webpack-cli@6.0.1) - terser-webpack-plugin@5.3.14(webpack@5.103.0(webpack-cli@4.10.0)): + terser-webpack-plugin@5.3.16(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12)): dependencies: '@jridgewell/trace-mapping': 0.3.31 jest-worker: 27.5.1 schema-utils: 4.3.3 serialize-javascript: 6.0.2 terser: 5.46.0 - webpack: 5.103.0(webpack-cli@4.10.0) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12) + optionalDependencies: + '@swc/core': 1.15.11(@swc/helpers@0.5.18) + esbuild: 0.25.12 - terser-webpack-plugin@5.3.14(webpack@5.103.0(webpack-cli@5.1.4)): + terser-webpack-plugin@5.3.16(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))): dependencies: '@jridgewell/trace-mapping': 0.3.31 jest-worker: 27.5.1 schema-utils: 4.3.3 serialize-javascript: 6.0.2 terser: 5.46.0 - webpack: 5.103.0(webpack-cli@5.1.4) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18)) + optionalDependencies: + '@swc/core': 1.15.11(@swc/helpers@0.5.18) - terser-webpack-plugin@5.3.14(webpack@5.103.0): + terser-webpack-plugin@5.3.16(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack@5.104.1): dependencies: '@jridgewell/trace-mapping': 0.3.31 jest-worker: 27.5.1 schema-utils: 4.3.3 serialize-javascript: 6.0.2 terser: 5.46.0 - webpack: 5.103.0(webpack-cli@6.0.1) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) + optionalDependencies: + '@swc/core': 1.15.11(@swc/helpers@0.5.18) - terser-webpack-plugin@5.3.14(webpack@5.99.9): + terser-webpack-plugin@5.3.16(webpack@5.104.1): dependencies: '@jridgewell/trace-mapping': 0.3.31 jest-worker: 27.5.1 schema-utils: 4.3.3 serialize-javascript: 6.0.2 terser: 5.46.0 - webpack: 5.99.9(webpack-cli@5.1.4) + webpack: 5.104.1(webpack-cli@5.1.4) terser@4.8.1: dependencies: @@ -57009,35 +56976,25 @@ snapshots: loader-utils: 1.4.2 semver: 5.7.2 - ts-loader@9.4.1(typescript@5.8.3)(webpack@5.99.9): + ts-loader@9.4.1(typescript@5.8.3)(webpack@5.104.1): dependencies: chalk: 4.1.2 enhanced-resolve: 5.19.0 micromatch: 4.0.8 semver: 7.7.4 typescript: 5.8.3 - webpack: 5.99.9(webpack-cli@6.0.1) + webpack: 5.104.1(webpack-cli@6.0.1) - ts-loader@9.4.4(typescript@5.8.3)(webpack@5.99.9): + ts-loader@9.4.4(typescript@5.8.3)(webpack@5.104.1): dependencies: chalk: 4.1.2 enhanced-resolve: 5.19.0 micromatch: 4.0.8 semver: 7.7.4 typescript: 5.8.3 - webpack: 5.99.9(webpack-cli@5.1.4) - - ts-loader@9.5.0(typescript@5.8.3)(webpack@5.99.9): - dependencies: - chalk: 4.1.2 - enhanced-resolve: 5.19.0 - micromatch: 4.0.8 - semver: 7.7.4 - source-map: 0.7.6 - typescript: 5.8.3 - webpack: 5.99.9(webpack-cli@5.1.4) + webpack: 5.104.1(webpack-cli@5.1.4) - ts-loader@9.5.2(typescript@5.8.3)(webpack@5.103.0): + ts-loader@9.5.0(typescript@5.8.3)(webpack@5.104.1): dependencies: chalk: 4.1.2 enhanced-resolve: 5.19.0 @@ -57045,9 +57002,9 @@ snapshots: semver: 7.7.4 source-map: 0.7.6 typescript: 5.8.3 - webpack: 5.103.0(webpack-cli@6.0.1) + webpack: 5.105.2(webpack-cli@5.1.4) - ts-loader@9.5.2(typescript@5.8.3)(webpack@5.99.9): + ts-loader@9.5.2(typescript@5.8.3)(webpack@5.104.1): dependencies: chalk: 4.1.2 enhanced-resolve: 5.19.0 @@ -57055,9 +57012,9 @@ snapshots: semver: 7.7.4 source-map: 0.7.6 typescript: 5.8.3 - webpack: 5.99.9(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) - ts-loader@9.5.4(typescript@5.8.3)(webpack@5.103.0): + ts-loader@9.5.4(typescript@5.8.3)(webpack@5.104.1): dependencies: chalk: 4.1.2 enhanced-resolve: 5.19.0 @@ -57065,7 +57022,7 @@ snapshots: semver: 7.7.4 source-map: 0.7.6 typescript: 5.8.3 - webpack: 5.103.0(webpack-cli@6.0.1) + webpack: 5.104.1(webpack-cli@6.0.1) ts-mixer@6.0.4: {} @@ -57248,10 +57205,10 @@ snapshots: tslint-config-prettier@1.18.0: {} - tslint-react-hooks@2.2.2(tslint@6.1.3(typescript@4.1.3))(typescript@4.1.3): + tslint-react-hooks@2.2.2(tslint@6.1.3(typescript@4.2.4))(typescript@4.2.4): dependencies: - tslint: 6.1.3(typescript@4.1.3) - typescript: 4.1.3 + tslint: 6.1.3(typescript@4.2.4) + typescript: 4.2.4 tslint-react-hooks@2.2.2(tslint@6.1.3(typescript@4.9.4))(typescript@4.9.4): dependencies: @@ -57275,11 +57232,11 @@ snapshots: tsutils: 3.21.0(typescript@4.9.4) typescript: 4.9.4 - tslint-react@5.0.0(tslint@6.1.3(typescript@4.1.3))(typescript@4.1.3): + tslint-react@5.0.0(tslint@6.1.3(typescript@4.2.4))(typescript@4.2.4): dependencies: - tslint: 6.1.3(typescript@4.1.3) - tsutils: 3.21.0(typescript@4.1.3) - typescript: 4.1.3 + tslint: 6.1.3(typescript@4.2.4) + tsutils: 3.21.0(typescript@4.2.4) + typescript: 4.2.4 tslint-react@5.0.0(tslint@6.1.3(typescript@5.8.3))(typescript@5.8.3): dependencies: @@ -57304,7 +57261,7 @@ snapshots: tsutils: 2.29.0(typescript@5.8.3) typescript: 5.8.3 - tslint@6.1.3(typescript@4.1.3): + tslint@6.1.3(typescript@4.2.4): dependencies: '@babel/code-frame': 7.29.0 builtin-modules: 1.1.1 @@ -57318,8 +57275,8 @@ snapshots: resolve: 1.22.11 semver: 5.7.2 tslib: 1.14.1 - tsutils: 2.29.0(typescript@4.1.3) - typescript: 4.1.3 + tsutils: 2.29.0(typescript@4.2.4) + typescript: 4.2.4 tslint@6.1.3(typescript@4.9.4): dependencies: @@ -57355,10 +57312,10 @@ snapshots: tsutils: 2.29.0(typescript@5.8.3) typescript: 5.8.3 - tsutils@2.29.0(typescript@4.1.3): + tsutils@2.29.0(typescript@4.2.4): dependencies: tslib: 1.14.1 - typescript: 4.1.3 + typescript: 4.2.4 tsutils@2.29.0(typescript@4.9.4): dependencies: @@ -57375,10 +57332,10 @@ snapshots: tslib: 1.14.1 typescript: 3.9.10 - tsutils@3.21.0(typescript@4.1.3): + tsutils@3.21.0(typescript@4.2.4): dependencies: tslib: 1.14.1 - typescript: 4.1.3 + typescript: 4.2.4 tsutils@3.21.0(typescript@4.9.4): dependencies: @@ -57390,6 +57347,10 @@ snapshots: tslib: 1.14.1 typescript: 5.8.3 + tsyringe@4.10.0: + dependencies: + tslib: 1.14.1 + ttf2eot@2.0.0: dependencies: argparse: 1.0.10 @@ -57512,7 +57473,7 @@ snapshots: typed-rest-client@1.8.11: dependencies: - qs: 6.14.1 + qs: 6.14.2 tunnel: 0.0.6 underscore: 1.13.7 @@ -57528,7 +57489,7 @@ snapshots: typescript@3.9.10: {} - typescript@4.1.3: {} + typescript@4.2.4: {} typescript@4.9.4: {} @@ -57596,7 +57557,7 @@ snapshots: undici-types@6.21.0: {} - undici@7.20.0: {} + undici@7.21.0: {} unfetch@4.2.0: {} @@ -57655,7 +57616,7 @@ snapshots: union@0.5.0: dependencies: - qs: 6.14.1 + qs: 6.14.2 uniq@1.0.1: {} @@ -57691,6 +57652,11 @@ snapshots: unist-builder@2.0.3: {} + unist-util-find-after@5.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + unist-util-generated@1.1.6: {} unist-util-is@4.1.0: {} @@ -57721,6 +57687,11 @@ snapshots: dependencies: unist-util-visit: 2.0.3 + unist-util-remove-position@5.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-visit: 5.1.0 + unist-util-remove@2.1.0: dependencies: unist-util-is: 4.1.0 @@ -57905,14 +57876,14 @@ snapshots: optionalDependencies: file-loader: 6.2.0(webpack@4.47.0) - url-loader@4.1.1(file-loader@6.2.0(webpack@5.99.9))(webpack@4.47.0(webpack-cli@6.0.1)): + url-loader@4.1.1(file-loader@6.2.0(webpack@5.104.1))(webpack@4.47.0(webpack-cli@6.0.1)): dependencies: loader-utils: 2.0.4 mime-types: 2.1.35 schema-utils: 3.3.0 webpack: 4.47.0(webpack-cli@6.0.1) optionalDependencies: - file-loader: 6.2.0(webpack@5.99.9) + file-loader: 6.2.0(webpack@5.105.2) url-parse-lax@1.0.0: dependencies: @@ -57926,7 +57897,7 @@ snapshots: url@0.11.4: dependencies: punycode: 1.4.1 - qs: 6.14.1 + qs: 6.14.2 use-callback-ref@1.3.3(@types/react@18.2.0)(react@18.2.0): dependencies: @@ -58413,12 +58384,12 @@ snapshots: webidl-conversions@7.0.0: {} - webpack-cli@4.10.0(webpack-dev-server@5.2.1)(webpack@5.99.9): + webpack-cli@4.10.0(webpack-dev-server@5.2.3)(webpack@5.105.2): dependencies: '@discoveryjs/json-ext': 0.5.7 - '@webpack-cli/configtest': 1.2.0(webpack-cli@4.10.0)(webpack@5.99.9) + '@webpack-cli/configtest': 1.2.0(webpack-cli@4.10.0)(webpack@5.105.2) '@webpack-cli/info': 1.5.0(webpack-cli@4.10.0) - '@webpack-cli/serve': 1.7.0(webpack-cli@4.10.0)(webpack-dev-server@5.2.1) + '@webpack-cli/serve': 1.7.0(webpack-cli@4.10.0)(webpack-dev-server@5.2.3) colorette: 2.0.20 commander: 7.2.0 cross-spawn: 7.0.6 @@ -58426,15 +58397,15 @@ snapshots: import-local: 3.2.0 interpret: 2.2.0 rechoir: 0.7.1 - webpack: 5.99.9(webpack-cli@4.10.0) + webpack: 5.105.2(webpack-cli@4.10.0) webpack-merge: 5.10.0 optionalDependencies: - webpack-dev-server: 5.2.1(webpack-cli@4.10.0)(webpack@5.99.9) + webpack-dev-server: 5.2.3(webpack-cli@4.10.0)(webpack@5.105.2) - webpack-cli@4.10.0(webpack@5.99.9): + webpack-cli@4.10.0(webpack@5.105.2): dependencies: '@discoveryjs/json-ext': 0.5.7 - '@webpack-cli/configtest': 1.2.0(webpack-cli@4.10.0)(webpack@5.99.9) + '@webpack-cli/configtest': 1.2.0(webpack-cli@4.10.0)(webpack@5.105.2) '@webpack-cli/info': 1.5.0(webpack-cli@4.10.0) '@webpack-cli/serve': 1.7.0(webpack-cli@4.10.0) colorette: 2.0.20 @@ -58444,15 +58415,15 @@ snapshots: import-local: 3.2.0 interpret: 2.2.0 rechoir: 0.7.1 - webpack: 5.99.9(webpack-cli@4.10.0) + webpack: 5.105.2(webpack-cli@4.10.0) webpack-merge: 5.10.0 - webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.99.9): + webpack-cli@5.1.4(webpack-dev-server@5.2.3)(webpack@5.105.2): dependencies: '@discoveryjs/json-ext': 0.5.7 - '@webpack-cli/configtest': 2.1.1(webpack-cli@5.1.4)(webpack@5.99.9) - '@webpack-cli/info': 2.0.2(webpack-cli@5.1.4)(webpack@5.99.9) - '@webpack-cli/serve': 2.0.5(webpack-cli@5.1.4)(webpack-dev-server@5.2.1)(webpack@5.99.9) + '@webpack-cli/configtest': 2.1.1(webpack-cli@5.1.4)(webpack@5.105.2) + '@webpack-cli/info': 2.0.2(webpack-cli@5.1.4)(webpack@5.105.2) + '@webpack-cli/serve': 2.0.5(webpack-cli@5.1.4)(webpack-dev-server@5.2.3)(webpack@5.105.2) colorette: 2.0.20 commander: 10.0.1 cross-spawn: 7.0.6 @@ -58461,17 +58432,17 @@ snapshots: import-local: 3.2.0 interpret: 3.1.1 rechoir: 0.8.0 - webpack: 5.99.9(webpack-cli@5.1.4) + webpack: 5.105.2(webpack-cli@5.1.4) webpack-merge: 5.10.0 optionalDependencies: - webpack-dev-server: 5.2.1(webpack-cli@5.1.4)(webpack@5.99.9) + webpack-dev-server: 5.2.3(webpack-cli@5.1.4)(webpack@5.105.2) - webpack-cli@5.1.4(webpack@5.99.9): + webpack-cli@5.1.4(webpack@5.105.2): dependencies: '@discoveryjs/json-ext': 0.5.7 - '@webpack-cli/configtest': 2.1.1(webpack-cli@5.1.4)(webpack@5.99.9) - '@webpack-cli/info': 2.0.2(webpack-cli@5.1.4)(webpack@5.99.9) - '@webpack-cli/serve': 2.0.5(webpack-cli@5.1.4)(webpack@5.99.9) + '@webpack-cli/configtest': 2.1.1(webpack-cli@5.1.4)(webpack@5.105.2) + '@webpack-cli/info': 2.0.2(webpack-cli@5.1.4)(webpack@5.105.2) + '@webpack-cli/serve': 2.0.5(webpack-cli@5.1.4)(webpack@5.105.2) colorette: 2.0.20 commander: 10.0.1 cross-spawn: 7.0.6 @@ -58480,15 +58451,15 @@ snapshots: import-local: 3.2.0 interpret: 3.1.1 rechoir: 0.8.0 - webpack: 5.99.9(webpack-cli@5.1.4) + webpack: 5.105.2(webpack-cli@5.1.4) webpack-merge: 5.10.0 - webpack-cli@6.0.1(webpack-dev-server@5.2.1)(webpack@5.99.9): + webpack-cli@6.0.1(webpack-dev-server@5.2.3)(webpack@5.105.2): dependencies: '@discoveryjs/json-ext': 0.6.3 - '@webpack-cli/configtest': 3.0.1(webpack-cli@6.0.1)(webpack@5.99.9) - '@webpack-cli/info': 3.0.1(webpack-cli@6.0.1)(webpack@5.99.9) - '@webpack-cli/serve': 3.0.1(webpack-cli@6.0.1)(webpack-dev-server@5.2.1)(webpack@5.99.9) + '@webpack-cli/configtest': 3.0.1(webpack-cli@6.0.1)(webpack@5.105.2) + '@webpack-cli/info': 3.0.1(webpack-cli@6.0.1)(webpack@5.105.2) + '@webpack-cli/serve': 3.0.1(webpack-cli@6.0.1)(webpack-dev-server@5.2.3)(webpack@5.105.2) colorette: 2.0.20 commander: 12.1.0 cross-spawn: 7.0.6 @@ -58497,17 +58468,17 @@ snapshots: import-local: 3.2.0 interpret: 3.1.1 rechoir: 0.8.0 - webpack: 5.99.9(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) webpack-merge: 6.0.1 optionalDependencies: - webpack-dev-server: 5.2.1(webpack-cli@6.0.1)(webpack@5.99.9) + webpack-dev-server: 5.2.3(webpack-cli@6.0.1)(webpack@5.105.2) - webpack-cli@6.0.1(webpack@5.103.0): + webpack-cli@6.0.1(webpack@5.105.2): dependencies: '@discoveryjs/json-ext': 0.6.3 - '@webpack-cli/configtest': 3.0.1(webpack-cli@6.0.1)(webpack@5.103.0) - '@webpack-cli/info': 3.0.1(webpack-cli@6.0.1)(webpack@5.103.0) - '@webpack-cli/serve': 3.0.1(webpack-cli@6.0.1)(webpack@5.103.0) + '@webpack-cli/configtest': 3.0.1(webpack-cli@6.0.1)(webpack@5.105.2) + '@webpack-cli/info': 3.0.1(webpack-cli@6.0.1)(webpack@5.105.2) + '@webpack-cli/serve': 3.0.1(webpack-cli@6.0.1)(webpack@5.105.2) colorette: 2.0.20 commander: 12.1.0 cross-spawn: 7.0.6 @@ -58516,24 +58487,7 @@ snapshots: import-local: 3.2.0 interpret: 3.1.1 rechoir: 0.8.0 - webpack: 5.103.0(webpack-cli@6.0.1) - webpack-merge: 6.0.1 - - webpack-cli@6.0.1(webpack@5.99.9): - dependencies: - '@discoveryjs/json-ext': 0.6.3 - '@webpack-cli/configtest': 3.0.1(webpack-cli@6.0.1)(webpack@5.99.9) - '@webpack-cli/info': 3.0.1(webpack-cli@6.0.1)(webpack@5.99.9) - '@webpack-cli/serve': 3.0.1(webpack-cli@6.0.1)(webpack@5.99.9) - colorette: 2.0.20 - commander: 12.1.0 - cross-spawn: 7.0.6 - envinfo: 7.21.0 - fastest-levenshtein: 1.0.16 - import-local: 3.2.0 - interpret: 3.1.1 - rechoir: 0.8.0 - webpack: 5.99.9(webpack-cli@6.0.1) + webpack: 5.105.2(webpack-cli@6.0.1) webpack-merge: 6.0.1 webpack-dev-middleware@1.12.2(webpack@3.8.1): @@ -58572,17 +58526,7 @@ snapshots: webpack: 4.47.0 webpack-log: 2.0.0 - webpack-dev-middleware@4.3.0(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1)): - dependencies: - colorette: 1.4.0 - mem: 8.1.1 - memfs: 3.5.3 - mime-types: 2.1.35 - range-parser: 1.2.1 - schema-utils: 3.3.0 - webpack: 5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) - - webpack-dev-middleware@4.3.0(webpack@5.103.0(webpack-cli@4.10.0)): + webpack-dev-middleware@4.3.0(webpack@5.105.2): dependencies: colorette: 1.4.0 mem: 8.1.1 @@ -58590,19 +58534,9 @@ snapshots: mime-types: 2.1.35 range-parser: 1.2.1 schema-utils: 3.3.0 - webpack: 5.103.0(webpack-cli@4.10.0) - - webpack-dev-middleware@6.1.3(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12)): - dependencies: - colorette: 2.0.20 - memfs: 3.5.3 - mime-types: 2.1.35 - range-parser: 1.2.1 - schema-utils: 4.3.3 - optionalDependencies: - webpack: 5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) - webpack-dev-middleware@6.1.3(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@5.1.4)): + webpack-dev-middleware@6.1.3(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12)): dependencies: colorette: 2.0.20 memfs: 3.5.3 @@ -58610,9 +58544,9 @@ snapshots: range-parser: 1.2.1 schema-utils: 4.3.3 optionalDependencies: - webpack: 5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@5.1.4) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12) - webpack-dev-middleware@6.1.3(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))): + webpack-dev-middleware@6.1.3(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))): dependencies: colorette: 2.0.20 memfs: 3.5.3 @@ -58620,9 +58554,9 @@ snapshots: range-parser: 1.2.1 schema-utils: 4.3.3 optionalDependencies: - webpack: 5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18)) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18)) - webpack-dev-middleware@6.1.3(webpack@5.103.0(webpack-cli@5.1.4)): + webpack-dev-middleware@6.1.3(webpack@5.105.2): dependencies: colorette: 2.0.20 memfs: 3.5.3 @@ -58630,9 +58564,9 @@ snapshots: range-parser: 1.2.1 schema-utils: 4.3.3 optionalDependencies: - webpack: 5.103.0(webpack-cli@5.1.4) + webpack: 5.105.2(webpack-cli@5.1.4) - webpack-dev-middleware@7.4.5(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))): + webpack-dev-middleware@7.4.5(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))): dependencies: colorette: 2.0.20 memfs: 4.56.10 @@ -58641,10 +58575,10 @@ snapshots: range-parser: 1.2.1 schema-utils: 4.3.3 optionalDependencies: - webpack: 5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18)) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18)) optional: true - webpack-dev-middleware@7.4.5(webpack@5.103.0): + webpack-dev-middleware@7.4.5(webpack@5.105.2): dependencies: colorette: 2.0.20 memfs: 4.56.10 @@ -58653,19 +58587,7 @@ snapshots: range-parser: 1.2.1 schema-utils: 4.3.3 optionalDependencies: - webpack: 5.103.0(webpack-cli@6.0.1) - optional: true - - webpack-dev-middleware@7.4.5(webpack@5.99.9): - dependencies: - colorette: 2.0.20 - memfs: 4.56.10 - mime-types: 3.0.2 - on-finished: 2.4.1 - range-parser: 1.2.1 - schema-utils: 4.3.3 - optionalDependencies: - webpack: 5.99.9(webpack-cli@5.1.4) + webpack: 5.105.2(webpack-cli@5.1.4) webpack-dev-server@2.11.3(webpack@3.8.1): dependencies: @@ -58698,7 +58620,7 @@ snapshots: webpack-dev-middleware: 1.12.2(webpack@3.8.1) yargs: 6.6.0 - webpack-dev-server@5.2.1(webpack-cli@4.10.0)(webpack@5.99.9): + webpack-dev-server@5.2.3(webpack-cli@4.10.0)(webpack@5.104.1): dependencies: '@types/bonjour': 3.5.13 '@types/connect-history-api-fallback': 1.5.4 @@ -58722,15 +58644,15 @@ snapshots: open: 10.2.0 p-retry: 6.2.1 schema-utils: 4.3.3 - selfsigned: 2.4.1 + selfsigned: 5.5.0 serve-index: 1.9.2 sockjs: 0.3.24 spdy: 4.0.2 - webpack-dev-middleware: 7.4.5(webpack@5.99.9) + webpack-dev-middleware: 7.4.5(webpack@5.105.2) ws: 8.19.0 optionalDependencies: - webpack: 5.99.9(webpack-cli@4.10.0) - webpack-cli: 4.10.0(webpack-dev-server@5.2.1)(webpack@5.99.9) + webpack: 5.105.2(webpack-cli@4.10.0) + webpack-cli: 4.10.0(webpack-dev-server@5.2.3)(webpack@5.105.2) transitivePeerDependencies: - bufferutil - debug @@ -58738,46 +58660,7 @@ snapshots: - utf-8-validate optional: true - webpack-dev-server@5.2.1(webpack-cli@5.1.4)(webpack@5.99.9): - dependencies: - '@types/bonjour': 3.5.13 - '@types/connect-history-api-fallback': 1.5.4 - '@types/express': 4.17.25 - '@types/express-serve-static-core': 4.19.8 - '@types/serve-index': 1.9.4 - '@types/serve-static': 1.15.10 - '@types/sockjs': 0.3.36 - '@types/ws': 8.18.1 - ansi-html-community: 0.0.8 - bonjour-service: 1.3.0 - chokidar: 3.6.0 - colorette: 2.0.20 - compression: 1.8.1 - connect-history-api-fallback: 2.0.0 - express: 4.22.1 - graceful-fs: 4.2.11 - http-proxy-middleware: 2.0.9(@types/express@4.17.25) - ipaddr.js: 2.3.0 - launch-editor: 2.12.0 - open: 10.2.0 - p-retry: 6.2.1 - schema-utils: 4.3.3 - selfsigned: 2.4.1 - serve-index: 1.9.2 - sockjs: 0.3.24 - spdy: 4.0.2 - webpack-dev-middleware: 7.4.5(webpack@5.99.9) - ws: 8.19.0 - optionalDependencies: - webpack: 5.99.9(webpack-cli@5.1.4) - webpack-cli: 5.1.4(webpack-dev-server@5.2.1)(webpack@5.99.9) - transitivePeerDependencies: - - bufferutil - - debug - - supports-color - - utf-8-validate - - webpack-dev-server@5.2.1(webpack-cli@6.0.1)(webpack@5.99.9): + webpack-dev-server@5.2.3(webpack-cli@5.1.4)(webpack@5.105.2): dependencies: '@types/bonjour': 3.5.13 '@types/connect-history-api-fallback': 1.5.4 @@ -58801,22 +58684,22 @@ snapshots: open: 10.2.0 p-retry: 6.2.1 schema-utils: 4.3.3 - selfsigned: 2.4.1 + selfsigned: 5.5.0 serve-index: 1.9.2 sockjs: 0.3.24 spdy: 4.0.2 - webpack-dev-middleware: 7.4.5(webpack@5.99.9) + webpack-dev-middleware: 7.4.5(webpack@5.105.2) ws: 8.19.0 optionalDependencies: - webpack: 5.99.9(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) - webpack-cli: 6.0.1(webpack-dev-server@5.2.1)(webpack@5.99.9) + webpack: 5.105.2(webpack-cli@5.1.4) + webpack-cli: 5.1.4(webpack-dev-server@5.2.3)(webpack@5.105.2) transitivePeerDependencies: - bufferutil - debug - supports-color - utf-8-validate - webpack-dev-server@5.2.1(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))): + webpack-dev-server@5.2.3(webpack-cli@6.0.1)(webpack@5.105.2): dependencies: '@types/bonjour': 3.5.13 '@types/connect-history-api-fallback': 1.5.4 @@ -58840,22 +58723,22 @@ snapshots: open: 10.2.0 p-retry: 6.2.1 schema-utils: 4.3.3 - selfsigned: 2.4.1 + selfsigned: 5.5.0 serve-index: 1.9.2 sockjs: 0.3.24 spdy: 4.0.2 - webpack-dev-middleware: 7.4.5(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))) + webpack-dev-middleware: 7.4.5(webpack@5.105.2) ws: 8.19.0 optionalDependencies: - webpack: 5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18)) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1) + webpack-cli: 6.0.1(webpack-dev-server@5.2.3)(webpack@5.104.1) transitivePeerDependencies: - bufferutil - debug - supports-color - utf-8-validate - optional: true - webpack-dev-server@5.2.1(webpack@5.103.0): + webpack-dev-server@5.2.3(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))): dependencies: '@types/bonjour': 3.5.13 '@types/connect-history-api-fallback': 1.5.4 @@ -58879,14 +58762,14 @@ snapshots: open: 10.2.0 p-retry: 6.2.1 schema-utils: 4.3.3 - selfsigned: 2.4.1 + selfsigned: 5.5.0 serve-index: 1.9.2 sockjs: 0.3.24 spdy: 4.0.2 - webpack-dev-middleware: 7.4.5(webpack@5.103.0) + webpack-dev-middleware: 7.4.5(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))) ws: 8.19.0 optionalDependencies: - webpack: 5.103.0(webpack-cli@6.0.1) + webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18)) transitivePeerDependencies: - bufferutil - debug @@ -59037,7 +58920,7 @@ snapshots: watchpack: 1.7.5 webpack-sources: 1.4.3 optionalDependencies: - webpack-cli: 4.10.0(webpack-dev-server@5.2.1)(webpack@5.99.9) + webpack-cli: 4.10.0(webpack-dev-server@5.2.3)(webpack@5.104.1) webpack@4.47.0(webpack-cli@6.0.1): dependencies: @@ -59065,9 +58948,9 @@ snapshots: watchpack: 1.7.5 webpack-sources: 1.4.3 optionalDependencies: - webpack-cli: 6.0.1(webpack-dev-server@5.2.1)(webpack@5.99.9) + webpack-cli: 6.0.1(webpack-dev-server@5.2.3)(webpack@5.104.1) - webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18)): + webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18)): dependencies: '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.8 @@ -59080,7 +58963,7 @@ snapshots: browserslist: 4.28.1 chrome-trace-event: 1.0.4 enhanced-resolve: 5.19.0 - es-module-lexer: 1.7.0 + es-module-lexer: 2.0.0 eslint-scope: 5.1.1 events: 3.3.0 glob-to-regexp: 0.4.1 @@ -59091,7 +58974,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 4.3.3 tapable: 2.3.0 - terser-webpack-plugin: 5.3.14(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))) + terser-webpack-plugin: 5.3.16(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))) watchpack: 2.5.1 webpack-sources: 3.3.3 transitivePeerDependencies: @@ -59099,7 +58982,7 @@ snapshots: - esbuild - uglify-js - webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12): + webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12): dependencies: '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.8 @@ -59112,7 +58995,7 @@ snapshots: browserslist: 4.28.1 chrome-trace-event: 1.0.4 enhanced-resolve: 5.19.0 - es-module-lexer: 1.7.0 + es-module-lexer: 2.0.0 eslint-scope: 5.1.1 events: 3.3.0 glob-to-regexp: 0.4.1 @@ -59123,7 +59006,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 4.3.3 tapable: 2.3.0 - terser-webpack-plugin: 5.3.14(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12)(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12)) + terser-webpack-plugin: 5.3.16(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.25.12)) watchpack: 2.5.1 webpack-sources: 3.3.3 transitivePeerDependencies: @@ -59131,7 +59014,7 @@ snapshots: - esbuild - uglify-js - webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@5.1.4): + webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@5.1.4): dependencies: '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.8 @@ -59144,7 +59027,7 @@ snapshots: browserslist: 4.28.1 chrome-trace-event: 1.0.4 enhanced-resolve: 5.19.0 - es-module-lexer: 1.7.0 + es-module-lexer: 2.0.0 eslint-scope: 5.1.1 events: 3.3.0 glob-to-regexp: 0.4.1 @@ -59155,17 +59038,17 @@ snapshots: neo-async: 2.6.2 schema-utils: 4.3.3 tapable: 2.3.0 - terser-webpack-plugin: 5.3.14(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@5.1.4)) + terser-webpack-plugin: 5.3.16(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack@5.104.1) watchpack: 2.5.1 webpack-sources: 3.3.3 optionalDependencies: - webpack-cli: 5.1.4(webpack-dev-server@5.2.1)(webpack@5.99.9) + webpack-cli: 5.1.4(webpack@5.105.2) transitivePeerDependencies: - '@swc/core' - esbuild - uglify-js - webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1): + webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1): dependencies: '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.8 @@ -59178,7 +59061,7 @@ snapshots: browserslist: 4.28.1 chrome-trace-event: 1.0.4 enhanced-resolve: 5.19.0 - es-module-lexer: 1.7.0 + es-module-lexer: 2.0.0 eslint-scope: 5.1.1 events: 3.3.0 glob-to-regexp: 0.4.1 @@ -59189,17 +59072,17 @@ snapshots: neo-async: 2.6.2 schema-utils: 4.3.3 tapable: 2.3.0 - terser-webpack-plugin: 5.3.14(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack@5.103.0(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1)) + terser-webpack-plugin: 5.3.16(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack@5.104.1) watchpack: 2.5.1 webpack-sources: 3.3.3 optionalDependencies: - webpack-cli: 6.0.1(webpack-dev-server@5.2.1)(webpack@5.99.9) + webpack-cli: 6.0.1(webpack-dev-server@5.2.3)(webpack@5.105.2) transitivePeerDependencies: - '@swc/core' - esbuild - uglify-js - webpack@5.103.0(webpack-cli@4.10.0): + webpack@5.105.2(webpack-cli@4.10.0): dependencies: '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.8 @@ -59212,7 +59095,7 @@ snapshots: browserslist: 4.28.1 chrome-trace-event: 1.0.4 enhanced-resolve: 5.19.0 - es-module-lexer: 1.7.0 + es-module-lexer: 2.0.0 eslint-scope: 5.1.1 events: 3.3.0 glob-to-regexp: 0.4.1 @@ -59223,17 +59106,17 @@ snapshots: neo-async: 2.6.2 schema-utils: 4.3.3 tapable: 2.3.0 - terser-webpack-plugin: 5.3.14(webpack@5.103.0(webpack-cli@4.10.0)) + terser-webpack-plugin: 5.3.16(webpack@5.104.1) watchpack: 2.5.1 webpack-sources: 3.3.3 optionalDependencies: - webpack-cli: 4.10.0(webpack-dev-server@5.2.1)(webpack@5.99.9) + webpack-cli: 4.10.0(webpack-dev-server@5.2.3)(webpack@5.105.2) transitivePeerDependencies: - '@swc/core' - esbuild - uglify-js - webpack@5.103.0(webpack-cli@5.1.4): + webpack@5.105.2(webpack-cli@5.1.4): dependencies: '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.8 @@ -59246,7 +59129,7 @@ snapshots: browserslist: 4.28.1 chrome-trace-event: 1.0.4 enhanced-resolve: 5.19.0 - es-module-lexer: 1.7.0 + es-module-lexer: 2.0.0 eslint-scope: 5.1.1 events: 3.3.0 glob-to-regexp: 0.4.1 @@ -59257,17 +59140,17 @@ snapshots: neo-async: 2.6.2 schema-utils: 4.3.3 tapable: 2.3.0 - terser-webpack-plugin: 5.3.14(webpack@5.103.0(webpack-cli@5.1.4)) + terser-webpack-plugin: 5.3.16(webpack@5.104.1) watchpack: 2.5.1 webpack-sources: 3.3.3 optionalDependencies: - webpack-cli: 5.1.4(webpack-dev-server@5.2.1)(webpack@5.99.9) + webpack-cli: 5.1.4(webpack@5.105.2) transitivePeerDependencies: - '@swc/core' - esbuild - uglify-js - webpack@5.103.0(webpack-cli@6.0.1): + webpack@5.105.2(webpack-cli@6.0.1): dependencies: '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.8 @@ -59280,172 +59163,7 @@ snapshots: browserslist: 4.28.1 chrome-trace-event: 1.0.4 enhanced-resolve: 5.19.0 - es-module-lexer: 1.7.0 - eslint-scope: 5.1.1 - events: 3.3.0 - glob-to-regexp: 0.4.1 - graceful-fs: 4.2.11 - json-parse-even-better-errors: 2.3.1 - loader-runner: 4.3.1 - mime-types: 2.1.35 - neo-async: 2.6.2 - schema-utils: 4.3.3 - tapable: 2.3.0 - terser-webpack-plugin: 5.3.14(webpack@5.103.0) - watchpack: 2.5.1 - webpack-sources: 3.3.3 - optionalDependencies: - webpack-cli: 6.0.1(webpack@5.103.0) - transitivePeerDependencies: - - '@swc/core' - - esbuild - - uglify-js - - webpack@5.99.9(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@5.1.4): - dependencies: - '@types/eslint-scope': 3.7.7 - '@types/estree': 1.0.8 - '@types/json-schema': 7.0.15 - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/wasm-edit': 1.14.1 - '@webassemblyjs/wasm-parser': 1.14.1 - acorn: 8.15.0 - browserslist: 4.28.1 - chrome-trace-event: 1.0.4 - enhanced-resolve: 5.19.0 - es-module-lexer: 1.7.0 - eslint-scope: 5.1.1 - events: 3.3.0 - glob-to-regexp: 0.4.1 - graceful-fs: 4.2.11 - json-parse-even-better-errors: 2.3.1 - loader-runner: 4.3.1 - mime-types: 2.1.35 - neo-async: 2.6.2 - schema-utils: 4.3.3 - tapable: 2.3.0 - terser-webpack-plugin: 5.3.14(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack@5.99.9) - watchpack: 2.5.1 - webpack-sources: 3.3.3 - optionalDependencies: - webpack-cli: 5.1.4(webpack@5.99.9) - transitivePeerDependencies: - - '@swc/core' - - esbuild - - uglify-js - - webpack@5.99.9(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack-cli@6.0.1): - dependencies: - '@types/eslint-scope': 3.7.7 - '@types/estree': 1.0.8 - '@types/json-schema': 7.0.15 - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/wasm-edit': 1.14.1 - '@webassemblyjs/wasm-parser': 1.14.1 - acorn: 8.15.0 - browserslist: 4.28.1 - chrome-trace-event: 1.0.4 - enhanced-resolve: 5.19.0 - es-module-lexer: 1.7.0 - eslint-scope: 5.1.1 - events: 3.3.0 - glob-to-regexp: 0.4.1 - graceful-fs: 4.2.11 - json-parse-even-better-errors: 2.3.1 - loader-runner: 4.3.1 - mime-types: 2.1.35 - neo-async: 2.6.2 - schema-utils: 4.3.3 - tapable: 2.3.0 - terser-webpack-plugin: 5.3.14(@swc/core@1.15.11(@swc/helpers@0.5.18))(webpack@5.99.9) - watchpack: 2.5.1 - webpack-sources: 3.3.3 - optionalDependencies: - webpack-cli: 6.0.1(webpack-dev-server@5.2.1)(webpack@5.99.9) - transitivePeerDependencies: - - '@swc/core' - - esbuild - - uglify-js - - webpack@5.99.9(webpack-cli@4.10.0): - dependencies: - '@types/eslint-scope': 3.7.7 - '@types/estree': 1.0.8 - '@types/json-schema': 7.0.15 - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/wasm-edit': 1.14.1 - '@webassemblyjs/wasm-parser': 1.14.1 - acorn: 8.15.0 - browserslist: 4.28.1 - chrome-trace-event: 1.0.4 - enhanced-resolve: 5.19.0 - es-module-lexer: 1.7.0 - eslint-scope: 5.1.1 - events: 3.3.0 - glob-to-regexp: 0.4.1 - graceful-fs: 4.2.11 - json-parse-even-better-errors: 2.3.1 - loader-runner: 4.3.1 - mime-types: 2.1.35 - neo-async: 2.6.2 - schema-utils: 4.3.3 - tapable: 2.3.0 - terser-webpack-plugin: 5.3.14(webpack@5.99.9) - watchpack: 2.5.1 - webpack-sources: 3.3.3 - optionalDependencies: - webpack-cli: 4.10.0(webpack-dev-server@5.2.1)(webpack@5.99.9) - transitivePeerDependencies: - - '@swc/core' - - esbuild - - uglify-js - - webpack@5.99.9(webpack-cli@5.1.4): - dependencies: - '@types/eslint-scope': 3.7.7 - '@types/estree': 1.0.8 - '@types/json-schema': 7.0.15 - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/wasm-edit': 1.14.1 - '@webassemblyjs/wasm-parser': 1.14.1 - acorn: 8.15.0 - browserslist: 4.28.1 - chrome-trace-event: 1.0.4 - enhanced-resolve: 5.19.0 - es-module-lexer: 1.7.0 - eslint-scope: 5.1.1 - events: 3.3.0 - glob-to-regexp: 0.4.1 - graceful-fs: 4.2.11 - json-parse-even-better-errors: 2.3.1 - loader-runner: 4.3.1 - mime-types: 2.1.35 - neo-async: 2.6.2 - schema-utils: 4.3.3 - tapable: 2.3.0 - terser-webpack-plugin: 5.3.14(webpack@5.99.9) - watchpack: 2.5.1 - webpack-sources: 3.3.3 - optionalDependencies: - webpack-cli: 5.1.4(webpack@5.99.9) - transitivePeerDependencies: - - '@swc/core' - - esbuild - - uglify-js - - webpack@5.99.9(webpack-cli@6.0.1): - dependencies: - '@types/eslint-scope': 3.7.7 - '@types/estree': 1.0.8 - '@types/json-schema': 7.0.15 - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/wasm-edit': 1.14.1 - '@webassemblyjs/wasm-parser': 1.14.1 - acorn: 8.15.0 - browserslist: 4.28.1 - chrome-trace-event: 1.0.4 - enhanced-resolve: 5.19.0 - es-module-lexer: 1.7.0 + es-module-lexer: 2.0.0 eslint-scope: 5.1.1 events: 3.3.0 glob-to-regexp: 0.4.1 @@ -59456,11 +59174,11 @@ snapshots: neo-async: 2.6.2 schema-utils: 4.3.3 tapable: 2.3.0 - terser-webpack-plugin: 5.3.14(webpack@5.99.9) + terser-webpack-plugin: 5.3.16(webpack@5.104.1) watchpack: 2.5.1 webpack-sources: 3.3.3 optionalDependencies: - webpack-cli: 6.0.1(webpack@5.99.9) + webpack-cli: 6.0.1(webpack@5.105.2) transitivePeerDependencies: - '@swc/core' - esbuild @@ -59578,7 +59296,7 @@ snapshots: which@5.0.0: dependencies: - isexe: 3.1.2 + isexe: 3.1.5 wide-align@1.1.5: dependencies: diff --git a/workspaces/api-designer/api-designer-extension/package.json b/workspaces/api-designer/api-designer-extension/package.json index 656febc523e..7cf55d39eb9 100644 --- a/workspaces/api-designer/api-designer-extension/package.json +++ b/workspaces/api-designer/api-designer-extension/package.json @@ -105,7 +105,7 @@ "eslint": "9.27.0", "typescript": "5.8.3", "ts-loader": "9.4.4", - "webpack": "5.99.9", + "webpack": "5.104.1", "webpack-cli": "5.1.4", "@vscode/test-electron": "2.3.4", "rimraf": "5.0.5", @@ -123,7 +123,7 @@ "@types/xml2js": "0.4.12", "jsonix": "3.0.0", "lodash": "4.17.23", - "axios": "1.12.0", + "axios": "1.13.5", "@types/lodash": "4.14.199", "xstate": "4.38.3", "node-fetch": "2.6.7", diff --git a/workspaces/api-designer/api-designer-visualizer/package.json b/workspaces/api-designer/api-designer-visualizer/package.json index ea9a58b728b..f1a0c8cb822 100644 --- a/workspaces/api-designer/api-designer-visualizer/package.json +++ b/workspaces/api-designer/api-designer-visualizer/package.json @@ -43,9 +43,9 @@ "@storybook/cli": "7.6.10", "@storybook/react": "7.4.0", "@storybook/react-webpack5": "7.4.0", - "webpack": "5.99.9", + "webpack": "5.104.1", "webpack-cli": "5.1.4", - "webpack-dev-server": "5.2.1", + "webpack-dev-server": "5.2.3", "@babel/preset-typescript": "7.22.11", "@babel/plugin-syntax-flow": "7.22.5", "@types/lodash": "4.14.198", diff --git a/workspaces/ballerina/ballerina-core/package.json b/workspaces/ballerina/ballerina-core/package.json index d0b244499c1..6cdc7184063 100644 --- a/workspaces/ballerina/ballerina-core/package.json +++ b/workspaces/ballerina/ballerina-core/package.json @@ -31,7 +31,7 @@ }, "devDependencies": { "@types/node": "22.15.21", - "@types/vscode": "1.83.1", + "@types/vscode": "1.100.0", "@typescript-eslint/eslint-plugin": "8.32.1", "@typescript-eslint/parser": "8.32.1", "@types/react": "18.2.0", diff --git a/workspaces/ballerina/ballerina-core/src/interfaces/bi.ts b/workspaces/ballerina/ballerina-core/src/interfaces/bi.ts index e1670d8e31c..d2d8f2462c9 100644 --- a/workspaces/ballerina/ballerina-core/src/interfaces/bi.ts +++ b/workspaces/ballerina/ballerina-core/src/interfaces/bi.ts @@ -153,7 +153,10 @@ export type FormFieldInputType = "TEXT" | "ENUM" | "DM_JOIN_CLAUSE_RHS_EXPRESSION" | "RECORD_MAP_EXPRESSION" | - "PROMPT"; + "PROMPT" | + "SQL_QUERY" | + "CLAUSE_EXPRESSION" | + "SLIDER"; export interface BaseType { fieldType: FormFieldInputType; @@ -465,8 +468,10 @@ export type FieldScope = "Global" | "Local" | "Object"; export type NodeKind = | "ACTION_OR_EXPRESSION" + | "AGENTS" | "AGENT" | "AGENT_CALL" + | "AGENT_RUN" | "ASSIGN" | "AUTOMATION" | "BODY" @@ -480,6 +485,7 @@ export type NodeKind = | "CONTINUE" | "DATA_MAPPER_CALL" | "DATA_MAPPER_DEFINITION" + | "DATA_MAPPER_CREATION" | "DRAFT" | "ELSE" | "EMPTY" @@ -492,6 +498,7 @@ export type NodeKind = | "FUNCTION" | "FUNCTION_CALL" | "FUNCTION_DEFINITION" + | "FUNCTION_CREATION" | "IF" | "INCLUDED_FIELD" | "LOCK" diff --git a/workspaces/ballerina/ballerina-core/src/interfaces/common.ts b/workspaces/ballerina/ballerina-core/src/interfaces/common.ts index dff221f99f2..68b6a2d1c5e 100644 --- a/workspaces/ballerina/ballerina-core/src/interfaces/common.ts +++ b/workspaces/ballerina/ballerina-core/src/interfaces/common.ts @@ -2,6 +2,7 @@ import { STNode } from "@wso2/syntax-tree"; import { FlowNode, RecordTypeField } from "./bi"; +import { MACHINE_VIEW } from ".."; /** * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. @@ -35,12 +36,17 @@ export enum SubPanelView { UNDEFINED = undefined, } -export enum DataMapperDisplayMode { +export enum EditorDisplayMode { NONE = "none", POPUP = "popup", VIEW = "view", } +export interface EditorConfig { + view: MACHINE_VIEW; + displayMode: EditorDisplayMode; +} + export interface DocumentIdentifier { uri: string; } diff --git a/workspaces/ballerina/ballerina-core/src/interfaces/constants.ts b/workspaces/ballerina/ballerina-core/src/interfaces/constants.ts index 41ed5834e5d..a0b7cf6ff8c 100644 --- a/workspaces/ballerina/ballerina-core/src/interfaces/constants.ts +++ b/workspaces/ballerina/ballerina-core/src/interfaces/constants.ts @@ -48,7 +48,9 @@ export const BI_COMMANDS = { ADD_DATA_MAPPER: 'BI.project-explorer.add-data-mapper', BI_EDIT_TEST_FUNCTION: 'BI.test.edit.function', BI_ADD_TEST_FUNCTION: 'BI.test.add.function', + BI_ADD_AI_EVALUATION: 'BI.test.add.ai.evaluation', BI_EDIT_TEST_FUNCTION_DEF: 'BI.test.edit.function.def', + BI_DELETE_TEST_FUNCTION: 'BI.test.delete.function', ADD_NATURAL_FUNCTION: 'BI.project-explorer.add-natural-function', TOGGLE_TRACE_LOGS: 'BI.toggle.trace.logs', DEVANT_PUSH_TO_CLOUD: 'BI.devant.push.cloud', diff --git a/workspaces/ballerina/ballerina-core/src/interfaces/extended-lang-client.ts b/workspaces/ballerina/ballerina-core/src/interfaces/extended-lang-client.ts index 4cd2cfe64c1..618125eb4a1 100644 --- a/workspaces/ballerina/ballerina-core/src/interfaces/extended-lang-client.ts +++ b/workspaces/ballerina/ballerina-core/src/interfaces/extended-lang-client.ts @@ -29,7 +29,7 @@ import { SqFlow } from "../rpc-types/sequence-diagram/interfaces"; import { FieldType, FunctionModel, ListenerModel, ServiceClassModel, ServiceInitModel, ServiceModel } from "./service"; import { CDModel } from "./component-diagram"; import { DMModel, ExpandedDMModel, IntermediateClause, Mapping, VisualizableField, FnMetadata, ResultClauseType, IOType } from "./data-mapper"; -import { DataMapperMetadata, SCOPE } from "../state-machine-types"; +import { ArtifactData, DataMapperMetadata, SCOPE } from "../state-machine-types"; import { ToolParameters } from "../rpc-types/ai-agent/interfaces"; export interface DidOpenParams { @@ -836,6 +836,7 @@ export interface BIFlowModelRequest { startLine?: LinePosition; endLine?: LinePosition; forceAssign?: boolean; + useFileSchema?: boolean; } export interface BISuggestedFlowModelRequest extends BIFlowModelRequest { @@ -855,6 +856,7 @@ export interface BISourceCodeRequest { isConnector?: boolean; isFunctionNodeUpdate?: boolean; isHelperPaneChange?: boolean; + artifactData?: ArtifactData; } export type BISourceCodeResponse = { @@ -968,6 +970,7 @@ export type BIGetEnclosedFunctionRequest = { filePath: string; position: LinePosition; findClass?: boolean; + useFileSchema?: boolean; } export type BIGetEnclosedFunctionResponse = { @@ -1058,6 +1061,7 @@ export interface BICopilotContextResponse { export interface BIDesignModelRequest { projectPath?: string; + useFileSchema?: boolean; } export type BIDesignModelResponse = { @@ -1308,6 +1312,7 @@ export interface ListenerModelRequest { packageName: string; moduleName: string; version: string; + type?: string; }; filePath: string; } @@ -1508,6 +1513,7 @@ export interface GetGraphqlTypeResponse { export interface GetTypesRequest { filePath: string; + useFileSchema?: boolean; } export interface GetTypeRequest { diff --git a/workspaces/ballerina/ballerina-core/src/rpc-types/agent-chat/index.ts b/workspaces/ballerina/ballerina-core/src/rpc-types/agent-chat/index.ts index cafce784a40..b46c7372b21 100644 --- a/workspaces/ballerina/ballerina-core/src/rpc-types/agent-chat/index.ts +++ b/workspaces/ballerina/ballerina-core/src/rpc-types/agent-chat/index.ts @@ -16,16 +16,17 @@ * under the License. */ -import { ChatReqMessage, ChatRespMessage, TraceInput, TraceStatus, ChatHistoryResponse, AgentStatusResponse, ClearChatResponse } from "./interfaces"; +import { ChatReqMessage, ChatRespMessage, TraceInput, TraceStatus, ChatHistoryResponse, AgentStatusResponse, ClearChatResponse, ExecutionStep, SessionInput } from "./interfaces"; export interface AgentChatAPI { getChatMessage: (params: ChatReqMessage) => Promise; abortChatRequest: () => void; getTracingStatus: () => Promise; showTraceView: (params: TraceInput) => Promise; + showSessionOverview: (params: SessionInput) => Promise; getChatHistory: () => Promise; clearChatHistory: () => Promise; getAgentStatus: () => Promise; } -export type { ChatReqMessage, ChatRespMessage, TraceInput, TraceStatus, ChatHistoryResponse, AgentStatusResponse, ClearChatResponse }; +export type { ChatReqMessage, ChatRespMessage, TraceInput, TraceStatus, ChatHistoryResponse, AgentStatusResponse, ClearChatResponse, ExecutionStep, SessionInput }; diff --git a/workspaces/ballerina/ballerina-core/src/rpc-types/agent-chat/interfaces.ts b/workspaces/ballerina/ballerina-core/src/rpc-types/agent-chat/interfaces.ts index c6880ffae53..ca6143f8fda 100644 --- a/workspaces/ballerina/ballerina-core/src/rpc-types/agent-chat/interfaces.ts +++ b/workspaces/ballerina/ballerina-core/src/rpc-types/agent-chat/interfaces.ts @@ -22,6 +22,19 @@ export interface ChatReqMessage { export interface ChatRespMessage { message: string; + traceId?: string; + executionSteps?: ExecutionStep[]; +} + +export interface ExecutionStep { + spanId: string; + operationType: 'invoke' | 'chat' | 'tool' | 'other'; + name: string; + fullName: string; + duration: number; + startTime?: string; + endTime?: string; + hasError?: boolean; } export interface TraceStatus { @@ -29,7 +42,10 @@ export interface TraceStatus { } export interface TraceInput { - message: string; + message?: string; + traceId?: string; + focusSpanId?: string; + sessionId?: string; } export interface ChatHistoryMessage { @@ -37,6 +53,7 @@ export interface ChatHistoryMessage { text: string; isUser: boolean; traceId?: string; + executionSteps?: ExecutionStep[]; } export interface ChatHistoryResponse { @@ -51,3 +68,7 @@ export interface AgentStatusResponse { export interface ClearChatResponse { newSessionId: string; } + +export interface SessionInput { + sessionId?: string; +} diff --git a/workspaces/ballerina/ballerina-core/src/rpc-types/agent-chat/rpc-type.ts b/workspaces/ballerina/ballerina-core/src/rpc-types/agent-chat/rpc-type.ts index 932beb1c1a3..b3f92098658 100644 --- a/workspaces/ballerina/ballerina-core/src/rpc-types/agent-chat/rpc-type.ts +++ b/workspaces/ballerina/ballerina-core/src/rpc-types/agent-chat/rpc-type.ts @@ -17,7 +17,7 @@ * * THIS FILE INCLUDES AUTO GENERATED CODE */ -import { ChatReqMessage, ChatRespMessage, TraceInput, TraceStatus, ChatHistoryResponse, AgentStatusResponse, ClearChatResponse } from "./interfaces"; +import { ChatReqMessage, ChatRespMessage, TraceInput, TraceStatus, ChatHistoryResponse, AgentStatusResponse, ClearChatResponse, SessionInput } from "./interfaces"; import { RequestType, NotificationType } from "vscode-messenger-common"; const _preFix = "agent-chat"; @@ -25,6 +25,7 @@ export const getChatMessage: RequestType = { me export const abortChatRequest: NotificationType = { method: `${_preFix}/abortChatRequest` }; export const getTracingStatus: RequestType = { method: `${_preFix}/getTracingStatus` }; export const showTraceView: NotificationType = { method: `${_preFix}/showTraceView` }; +export const showSessionOverview: NotificationType = { method: `${_preFix}/showSessionOverview` }; export const getChatHistory: RequestType = { method: `${_preFix}/getChatHistory` }; export const clearChatHistory: RequestType = { method: `${_preFix}/clearChatHistory` }; export const getAgentStatus: RequestType = { method: `${_preFix}/getAgentStatus` }; diff --git a/workspaces/ballerina/ballerina-core/src/rpc-types/ai-panel/index.ts b/workspaces/ballerina/ballerina-core/src/rpc-types/ai-panel/index.ts index 3235186fc43..db39742c0b4 100644 --- a/workspaces/ballerina/ballerina-core/src/rpc-types/ai-panel/index.ts +++ b/workspaces/ballerina/ballerina-core/src/rpc-types/ai-panel/index.ts @@ -39,6 +39,8 @@ import { TaskDeclineRequest, ConnectorSpecRequest, ConnectorSpecCancelRequest, + ConfigurationProvideRequest, + ConfigurationCancelRequest, UIChatMessage, CheckpointInfo, AbortAIGenerationRequest, @@ -93,6 +95,8 @@ export interface AIPanelAPI { declineTask: (params: TaskDeclineRequest) => Promise; provideConnectorSpec: (params: ConnectorSpecRequest) => Promise; cancelConnectorSpec: (params: ConnectorSpecCancelRequest) => Promise; + provideConfiguration: (params: ConfigurationProvideRequest) => Promise; + cancelConfiguration: (params: ConfigurationCancelRequest) => Promise; // ================================== // Chat State Management // ================================== diff --git a/workspaces/ballerina/ballerina-core/src/rpc-types/ai-panel/interfaces.ts b/workspaces/ballerina/ballerina-core/src/rpc-types/ai-panel/interfaces.ts index 85f647e0fce..f82730c9259 100644 --- a/workspaces/ballerina/ballerina-core/src/rpc-types/ai-panel/interfaces.ts +++ b/workspaces/ballerina/ballerina-core/src/rpc-types/ai-panel/interfaces.ts @@ -306,7 +306,7 @@ export interface GenerateAgentCodeRequest { codeContext?: CodeContext; } -export type LibraryMode = "CORE" | "HEALTHCARE"; +export type LibraryMode = "CORE" | "HEALTHCARE" | "ALL"; export interface CopilotAllLibrariesRequest { mode: LibraryMode; @@ -321,13 +321,20 @@ export interface CopilotCompactLibrariesResponse { export interface CopilotFilterLibrariesRequest { libNames: string[]; - mode: LibraryMode; } export interface CopilotFilterLibrariesResponse { libraries: any[]; } +export interface CopilotSearchLibrariesBySearchRequest { + keywords: string[]; +} + +export interface CopilotSearchLibrariesBySearchResponse { + libraries: MinifiedLibrary[]; +} + // ================================== // Doc Generation Related Interfaces // ================================== @@ -377,8 +384,9 @@ export interface SemanticDiffRequest { // Numeric enum values from the API export enum ChangeTypeEnum { ADDITION = 0, - MODIFICATION = 1, - DELETION = 2 + DELETION = 1, + MODIFICATION = 2, + } export type ChangeType = "ADDITION" | "MODIFICATION" | "DELETION"; @@ -429,6 +437,16 @@ export interface ConnectorSpecCancelRequest { comment?: string; } +export interface ConfigurationProvideRequest { + requestId: string; + configValues: Record; +} + +export interface ConfigurationCancelRequest { + requestId: string; + comment?: string; +} + export type ErrorCode = { code: number; message: string; diff --git a/workspaces/ballerina/ballerina-core/src/rpc-types/ai-panel/rpc-type.ts b/workspaces/ballerina/ballerina-core/src/rpc-types/ai-panel/rpc-type.ts index 6742364ca36..9cadd3e9462 100644 --- a/workspaces/ballerina/ballerina-core/src/rpc-types/ai-panel/rpc-type.ts +++ b/workspaces/ballerina/ballerina-core/src/rpc-types/ai-panel/rpc-type.ts @@ -41,6 +41,8 @@ import { TaskDeclineRequest, ConnectorSpecRequest, ConnectorSpecCancelRequest, + ConfigurationProvideRequest, + ConfigurationCancelRequest, UIChatMessage, CheckpointInfo, AbortAIGenerationRequest, @@ -85,6 +87,8 @@ export const approveTask: RequestType = { method: `${_ export const declineTask: RequestType = { method: `${_preFix}/declineTask` }; export const provideConnectorSpec: RequestType = { method: `${_preFix}/provideConnectorSpec` }; export const cancelConnectorSpec: RequestType = { method: `${_preFix}/cancelConnectorSpec` }; +export const provideConfiguration: RequestType = { method: `${_preFix}/provideConfiguration` }; +export const cancelConfiguration: RequestType = { method: `${_preFix}/cancelConfiguration` }; export const getChatMessages: NotificationType = { method: `${_preFix}/getChatMessages` }; export const getCheckpoints: NotificationType = { method: `${_preFix}/getCheckpoints` }; export const restoreCheckpoint: RequestType = { method: `${_preFix}/restoreCheckpoint` }; diff --git a/workspaces/ballerina/ballerina-core/src/rpc-types/bi-diagram/index.ts b/workspaces/ballerina/ballerina-core/src/rpc-types/bi-diagram/index.ts index 4e452c463ae..89f86b680ba 100644 --- a/workspaces/ballerina/ballerina-core/src/rpc-types/bi-diagram/index.ts +++ b/workspaces/ballerina/ballerina-core/src/rpc-types/bi-diagram/index.ts @@ -121,7 +121,9 @@ import { GeneratedClientSaveResponse, AddProjectToWorkspaceRequest, DeleteProjectRequest, - OpenReadmeRequest + OpenReadmeRequest, + ValidateProjectFormRequest, + ValidateProjectFormResponse } from "./interfaces"; export interface BIDiagramAPI { @@ -130,6 +132,7 @@ export interface BIDiagramAPI { deleteFlowNode: (params: BISourceCodeRequest) => Promise; deleteByComponentInfo: (params: BIDeleteByComponentInfoRequest) => Promise; getAvailableNodes: (params: BIAvailableNodesRequest) => Promise; + getAvailableAgents: (params: BIAvailableNodesRequest) => Promise; getAvailableModelProviders: (params: BIAvailableNodesRequest) => Promise; getAvailableVectorStores: (params: BIAvailableNodesRequest) => Promise; getAvailableEmbeddingProviders: (params: BIAvailableNodesRequest) => Promise; @@ -140,6 +143,7 @@ export interface BIDiagramAPI { getNodeTemplate: (params: BINodeTemplateRequest) => Promise; getAiSuggestions: (params: BIAiSuggestionsRequest) => Promise; createProject: (params: ProjectRequest) => void; + validateProjectPath: (params: ValidateProjectFormRequest) => Promise; deleteProject: (params: DeleteProjectRequest) => void; addProjectToWorkspace: (params: AddProjectToWorkspaceRequest) => void; getWorkspaces: () => Promise; diff --git a/workspaces/ballerina/ballerina-core/src/rpc-types/bi-diagram/interfaces.ts b/workspaces/ballerina/ballerina-core/src/rpc-types/bi-diagram/interfaces.ts index 104f7b71d08..2a81c68bfe5 100644 --- a/workspaces/ballerina/ballerina-core/src/rpc-types/bi-diagram/interfaces.ts +++ b/workspaces/ballerina/ballerina-core/src/rpc-types/bi-diagram/interfaces.ts @@ -199,3 +199,20 @@ export interface GeneratedClientSaveResponse { export interface DeleteProjectRequest { projectPath: string; } + +export interface ValidateProjectFormRequest { + projectPath: string; + projectName: string; + createDirectory: boolean; +} + +export interface ValidateProjectFormResponse { + isValid: boolean; + errorMessage?: string; + errorField?: ValidateProjectFormErrorField; +} + +export enum ValidateProjectFormErrorField { + PATH = 'path', + NAME = 'name' +} diff --git a/workspaces/ballerina/ballerina-core/src/rpc-types/bi-diagram/rpc-type.ts b/workspaces/ballerina/ballerina-core/src/rpc-types/bi-diagram/rpc-type.ts index 1da53727308..b16443a2094 100644 --- a/workspaces/ballerina/ballerina-core/src/rpc-types/bi-diagram/rpc-type.ts +++ b/workspaces/ballerina/ballerina-core/src/rpc-types/bi-diagram/rpc-type.ts @@ -123,7 +123,9 @@ import { GeneratedClientSaveResponse, AddProjectToWorkspaceRequest, DeleteProjectRequest, - OpenReadmeRequest + OpenReadmeRequest, + ValidateProjectFormRequest, + ValidateProjectFormResponse } from "./interfaces"; import { RequestType, NotificationType } from "vscode-messenger-common"; @@ -133,6 +135,7 @@ export const getSourceCode: RequestType = { method: `${_preFix}/deleteFlowNode` }; export const deleteByComponentInfo: RequestType = { method: `${_preFix}/deleteByComponentInfo` }; export const getAvailableNodes: RequestType = { method: `${_preFix}/getAvailableNodes` }; +export const getAvailableAgents: RequestType = { method: `${_preFix}/getAvailableAgents` }; export const getAvailableModelProviders: RequestType = { method: `${_preFix}/getAvailableModelProviders` }; export const getAvailableVectorStores: RequestType = { method: `${_preFix}/getAvailableVectorStores` }; export const getAvailableEmbeddingProviders: RequestType = { method: `${_preFix}/getAvailableEmbeddingProviders` }; @@ -143,6 +146,7 @@ export const getEnclosedFunction: RequestType = { method: `${_preFix}/getNodeTemplate` }; export const getAiSuggestions: RequestType = { method: `${_preFix}/getAiSuggestions` }; export const createProject: NotificationType = { method: `${_preFix}/createProject` }; +export const validateProjectPath: RequestType = { method: `${_preFix}/validateProjectPath` }; export const deleteProject: NotificationType = { method: `${_preFix}/deleteProject` }; export const addProjectToWorkspace: NotificationType = { method: `${_preFix}/addProjectToWorkspace` }; export const getWorkspaces: RequestType = { method: `${_preFix}/getWorkspaces` }; diff --git a/workspaces/ballerina/ballerina-core/src/rpc-types/test-manager/index.ts b/workspaces/ballerina/ballerina-core/src/rpc-types/test-manager/index.ts index 041654b7922..3d1363d4d94 100644 --- a/workspaces/ballerina/ballerina-core/src/rpc-types/test-manager/index.ts +++ b/workspaces/ballerina/ballerina-core/src/rpc-types/test-manager/index.ts @@ -18,9 +18,11 @@ import { GetTestFunctionRequest, GetTestFunctionResponse, AddOrUpdateTestFunctionRequest } from "../../interfaces/extended-lang-client"; import { SourceUpdateResponse } from "../service-designer/interfaces"; +import { GetEvalsetsRequest, GetEvalsetsResponse } from "./rpc-type"; -export interface TestManagerServiceAPI { +export interface TestManagerServiceAPI { updateTestFunction: (params: AddOrUpdateTestFunctionRequest) => Promise; addTestFunction: (params: AddOrUpdateTestFunctionRequest) => Promise; getTestFunction: (params: GetTestFunctionRequest) => Promise; + getEvalsets: (params: GetEvalsetsRequest) => Promise; } diff --git a/workspaces/ballerina/ballerina-core/src/rpc-types/test-manager/rpc-type.ts b/workspaces/ballerina/ballerina-core/src/rpc-types/test-manager/rpc-type.ts index 2b2b93031b3..606be83b1c2 100644 --- a/workspaces/ballerina/ballerina-core/src/rpc-types/test-manager/rpc-type.ts +++ b/workspaces/ballerina/ballerina-core/src/rpc-types/test-manager/rpc-type.ts @@ -20,9 +20,28 @@ import { RequestType } from "vscode-messenger-common"; import { SourceUpdateResponse } from "../service-designer/interfaces"; const _preFix = "test-manager"; -export const getTestFunction: RequestType = +export const getTestFunction: RequestType = { method: `${_preFix}/getTestFunction` }; -export const addTestFunction: RequestType = +export const addTestFunction: RequestType = { method: `${_preFix}/addTestFunction` }; -export const updateTestFunction: RequestType = +export const updateTestFunction: RequestType = { method: `${_preFix}/updateTestFunction` }; + +export interface EvalsetItem { + id: string; + name: string; + filePath: string; + threadCount: number; + description?: string; +} + +export interface GetEvalsetsRequest { + projectPath?: string; +} + +export interface GetEvalsetsResponse { + evalsets: EvalsetItem[]; +} + +export const getEvalsets: RequestType = +{ method: `${_preFix}/getEvalsets` }; diff --git a/workspaces/ballerina/ballerina-core/src/rpc-types/visualizer/index.ts b/workspaces/ballerina/ballerina-core/src/rpc-types/visualizer/index.ts index cbfefe9d229..529f9571b1f 100644 --- a/workspaces/ballerina/ballerina-core/src/rpc-types/visualizer/index.ts +++ b/workspaces/ballerina/ballerina-core/src/rpc-types/visualizer/index.ts @@ -19,7 +19,7 @@ import { HistoryEntry } from "../../history"; import { ProjectStructureArtifactResponse, UpdatedArtifactsResponse } from "../../interfaces/bi"; import { ColorThemeKind } from "../../state-machine-types"; -import { AddToUndoStackRequest, JoinProjectPathRequest, JoinProjectPathResponse, OpenViewRequest, UndoRedoStateResponse } from "./interfaces"; +import { AddToUndoStackRequest, HandleApprovalPopupCloseRequest, JoinProjectPathRequest, JoinProjectPathResponse, OpenViewRequest, ReopenApprovalViewRequest, UndoRedoStateResponse, SaveEvalThreadRequest, SaveEvalThreadResponse } from "./interfaces"; export interface VisualizerAPI { openView: (params: OpenViewRequest) => void; @@ -37,4 +37,7 @@ export interface VisualizerAPI { getThemeKind: () => Promise; updateCurrentArtifactLocation: (params: UpdatedArtifactsResponse) => Promise; reviewAccepted: () => void; + handleApprovalPopupClose: (params: HandleApprovalPopupCloseRequest) => void; + reopenApprovalView: (params: ReopenApprovalViewRequest) => void; + saveEvalThread: (params: SaveEvalThreadRequest) => Promise; } diff --git a/workspaces/ballerina/ballerina-core/src/rpc-types/visualizer/interfaces.ts b/workspaces/ballerina/ballerina-core/src/rpc-types/visualizer/interfaces.ts index dd0301a1fec..8f5a2e52bba 100644 --- a/workspaces/ballerina/ballerina-core/src/rpc-types/visualizer/interfaces.ts +++ b/workspaces/ballerina/ballerina-core/src/rpc-types/visualizer/interfaces.ts @@ -17,7 +17,7 @@ */ import { CodeData } from "../../interfaces/bi"; -import { EVENT_TYPE, PopupVisualizerLocation, VisualizerLocation } from "../../state-machine-types"; +import { EVENT_TYPE, EvalSet, PopupVisualizerLocation, VisualizerLocation } from "../../state-machine-types"; export interface UpdateUndoRedoMangerRequest { filePath: string; @@ -59,3 +59,21 @@ export interface JoinProjectPathResponse { filePath: string; projectPath: string; } + +export interface HandleApprovalPopupCloseRequest { + requestId: string; +} + +export interface ReopenApprovalViewRequest { + requestId: string; +} + +export interface SaveEvalThreadRequest { + filePath: string; + updatedEvalSet: EvalSet; +} + +export interface SaveEvalThreadResponse { + success: boolean; + error?: string; +} diff --git a/workspaces/ballerina/ballerina-core/src/rpc-types/visualizer/rpc-type.ts b/workspaces/ballerina/ballerina-core/src/rpc-types/visualizer/rpc-type.ts index ba0722f647e..696f97d3f5a 100644 --- a/workspaces/ballerina/ballerina-core/src/rpc-types/visualizer/rpc-type.ts +++ b/workspaces/ballerina/ballerina-core/src/rpc-types/visualizer/rpc-type.ts @@ -19,8 +19,8 @@ */ import { HistoryEntry } from "../../history"; import { ProjectStructureArtifactResponse, UpdatedArtifactsResponse } from "../../interfaces/bi"; -import { ColorThemeKind } from "../../state-machine-types"; -import { AddToUndoStackRequest, JoinProjectPathRequest, JoinProjectPathResponse, OpenViewRequest, UndoRedoStateResponse } from "./interfaces"; +import { ColorThemeKind, EvalSet } from "../../state-machine-types"; +import { AddToUndoStackRequest, HandleApprovalPopupCloseRequest, JoinProjectPathRequest, JoinProjectPathResponse, OpenViewRequest, ReopenApprovalViewRequest, UndoRedoStateResponse, SaveEvalThreadRequest, SaveEvalThreadResponse } from "./interfaces"; import { NotificationType, RequestType } from "vscode-messenger-common"; const _preFix = "visualizer"; @@ -40,3 +40,6 @@ export const getThemeKind: RequestType = { method: `${_pre export const updateCurrentArtifactLocation: RequestType = { method: `${_preFix}/updateCurrentArtifactLocation` }; export const reviewAccepted: NotificationType = { method: `${_preFix}/reviewAccepted` }; export const refreshReviewMode: NotificationType = { method: `${_preFix}/refreshReviewMode` }; +export const handleApprovalPopupClose: NotificationType = { method: `${_preFix}/handleApprovalPopupClose` }; +export const reopenApprovalView: NotificationType = { method: `${_preFix}/reopenApprovalView` }; +export const saveEvalThread: RequestType = { method: `${_preFix}/saveEvalThread` }; diff --git a/workspaces/ballerina/ballerina-core/src/state-machine-types.ts b/workspaces/ballerina/ballerina-core/src/state-machine-types.ts index 465de5ecf14..de8db4f6184 100644 --- a/workspaces/ballerina/ballerina-core/src/state-machine-types.ts +++ b/workspaces/ballerina/ballerina-core/src/state-machine-types.ts @@ -90,6 +90,7 @@ export enum MACHINE_VIEW { BIFunctionForm = "Add Function SKIP", BINPFunctionForm = "Add Natural Function SKIP", BITestFunctionForm = "Add Test Function SKIP", + BIAIEvaluationForm = "AI Evaluation SKIP", BIServiceWizard = "Service Wizard SKIP", BIServiceConfigView = "Service Config View", BIListenerConfigView = "Listener Config View", @@ -101,7 +102,9 @@ export enum MACHINE_VIEW { ResolveMissingDependencies = "Resolve Missing Dependencies", ServiceFunctionForm = "Service Function Form", BISamplesView = "BI Samples View", - ReviewMode = "Review Mode SKIP" + ReviewMode = "Review Mode SKIP", + EvalsetViewer = "Evalset Viewer SKIP", + ConfigurationCollector = "Configuration Collector" } export interface MachineEvent { @@ -141,6 +144,7 @@ export interface VisualizerLocation { isGraphql?: boolean; rootDiagramId?: string; metadata?: VisualizerMetadata; + agentMetadata?: AgentMetadata; scope?: SCOPE; projectStructure?: ProjectStructureResponse; org?: string; @@ -150,6 +154,7 @@ export interface VisualizerLocation { dataMapperMetadata?: DataMapperMetadata; artifactInfo?: ArtifactInfo; reviewData?: ReviewModeData; + evalsetData?: EvalsetData; } export interface ArtifactInfo { @@ -164,12 +169,36 @@ export interface ArtifactData { identifier?: string; } +export interface ConfigurationCollectorMetadata { + requestId: string; + variables: Array<{ + name: string; + description: string; + type?: "string" | "int"; + }>; + existingValues?: Record; + message: string; + isTestConfig?: boolean; +} + +export interface AgentMetadata { + configurationCollector?: ConfigurationCollectorMetadata; +} + +export interface ApprovalOverlayState { + show: boolean; + message?: string; +} + export interface VisualizerMetadata { haveLS?: boolean; isBISupported?: boolean; recordFilePath?: string; enableSequenceDiagram?: boolean; // Enable sequence diagram view target?: LinePosition; + featureSupport?: { + aiEvaluation?: boolean; + }; } export interface DataMapperMetadata { @@ -192,6 +221,88 @@ export interface ReviewModeData { onReject?: string; } +// --- Evalset Trace Types --- +export type EvalRole = 'system' | 'user' | 'assistant' | 'function'; + +export interface EvalChatUserMessage { + role: 'user'; + content: string | any; + name?: string; +} + +export interface EvalChatSystemMessage { + role: 'system'; + content: string | any; + name?: string; +} + +export interface EvalChatAssistantMessage { + role: 'assistant'; + content?: string | null; + name?: string; + toolCalls?: EvalFunctionCall[]; +} + +export interface EvalChatFunctionMessage { + role: 'function'; + content?: string | null; + name: string; + id?: string; +} + +export type EvalChatMessage = EvalChatUserMessage | EvalChatSystemMessage | EvalChatAssistantMessage | EvalChatFunctionMessage; + +export interface EvalFunctionCall { + name: string; + arguments?: { [key: string]: any }; + id?: string; +} + +export interface EvalToolSchema { + name: string; + description: string; + parametersSchema?: { [key: string]: any }; +} + +export interface EvalIteration { + history: EvalChatMessage[]; + output: EvalChatAssistantMessage | EvalChatFunctionMessage | any; + startTime: string; + endTime: string; +} + +export interface EvalsetTrace { + id: string; + userMessage: EvalChatUserMessage; + iterations: EvalIteration[]; + output: EvalChatAssistantMessage | any; + tools: EvalToolSchema[]; + toolCalls?: EvalFunctionCall[]; + startTime: string; + endTime: string; +} + +export interface EvalThread { + id: string; + name: string; + traces: EvalsetTrace[]; + created_on: string; +} + +export interface EvalSet { + id: string; + name?: string; + description?: string; + threads: EvalThread[]; + created_on: string; +} + +export interface EvalsetData { + filePath: string; + content: EvalSet; + threadId?: string; +} + export interface PopupVisualizerLocation extends VisualizerLocation { recentIdentifier?: string; artifactType?: DIRECTORY_MAP; @@ -229,6 +340,7 @@ export type ChatNotify = | TaskApprovalRequest | GeneratedSourcesEvent | ConnectorGenerationNotification + | ConfigurationCollectionEvent | CodeReviewActions | PlanUpdated; @@ -283,12 +395,14 @@ export interface ToolCall { type: "tool_call"; toolName: string; toolInput?: any; + toolCallId?: string; } export interface ToolResult { type: "tool_result"; toolName: string; toolOutput?: any; + toolCallId?: string; } export interface EvalsToolResult { @@ -347,6 +461,24 @@ export interface ConnectorGenerationNotification { message: string; } +export interface ConfigurationCollectionEvent { + type: "configuration_collection_event"; + requestId: string; + stage: "creating_file" | "collecting" | "done" | "skipped" | "error"; + variables?: Array<{ + name: string; + description: string; + type?: "string" | "int"; + }>; + existingValues?: Record; + message: string; + isTestConfig?: boolean; + error?: { + message: string; + code: string; + }; +} + export interface CodeReviewActions { type: "review_actions"; } @@ -379,6 +511,7 @@ export const popupStateChanged: NotificationType = { met export const getPopupVisualizerState: RequestType = { method: 'getPopupVisualizerState' }; export const breakpointChanged: NotificationType = { method: 'breakpointChanged' }; +export const approvalOverlayState: NotificationType = { method: 'approvalOverlayState' }; // ------------------> AI Related state types <----------------------- export type AIMachineStateValue = @@ -567,7 +700,7 @@ export enum TaskTypes { export interface Task { description: string; status: TaskStatus; - type : TaskTypes; + type: TaskTypes; } export interface Plan { diff --git a/workspaces/ballerina/ballerina-extension/CHANGELOG.md b/workspaces/ballerina/ballerina-extension/CHANGELOG.md index 4ceccac0d1f..90b9d90c25b 100644 --- a/workspaces/ballerina/ballerina-extension/CHANGELOG.md +++ b/workspaces/ballerina/ballerina-extension/CHANGELOG.md @@ -4,6 +4,28 @@ All notable changes to the **Ballerina** extension will be documented in this fi The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this project adheres to [Semantic Versioning](https://semver.org/). +## [5.8.0](https://github.com/wso2/vscode-extensions/compare/ballerina-5.7.3...ballerina-5.8.0) - 2026-02-14 + +### Added + +- **Event Integration** — Introduced CDC for PostgreSQL support. +- **FTP Integration** — Added support for deprecated FTP functions. +- **Expression Editor** — Added SQL support for expression editing. + +### Changed + +- **Project Creation** — Refactored form layout and validation. +- **Service Management** — Improved Try-it flow and multiple Ballerina version detection; sorted HTTP resources in service designer and artifact views. +- **Form Validation** — Ensured form validation runs before language server diagnostics. + +### Fixed + +- **Installation** — Added warning for conflicting Ballerina installations. +- **UI Components** — Fixed resource configuration response reset, record config helper overflow, and Boolean/enum editor selection. +- **Type Editor** — Fixed recursive type creation issue. +- **Expression Editor** — Fixed completions for method access. +- **Security** — Updated dependencies to address vulnerabilities (CVE-2026-25128, CVE-2025-50537, CVE-2025-13465, CVE-2026-25547). + ## [5.7.3](https://github.com/wso2/vscode-extensions/compare/ballerina-5.7.2...ballerina-5.7.3) - 2026-01-23 ### Fixed diff --git a/workspaces/ballerina/ballerina-extension/package.json b/workspaces/ballerina/ballerina-extension/package.json index cfe432cccea..4488343a492 100644 --- a/workspaces/ballerina/ballerina-extension/package.json +++ b/workspaces/ballerina/ballerina-extension/package.json @@ -2,7 +2,7 @@ "name": "ballerina", "displayName": "Ballerina", "description": "Ballerina Language support, debugging, graphical visualization, AI-based data-mapping and many more.", - "version": "5.7.4", + "version": "5.8.0", "publisher": "wso2", "icon": "resources/images/ballerina.png", "homepage": "https://wso2.com/ballerina/vscode/docs", @@ -15,7 +15,7 @@ "theme": "light" }, "engines": { - "vscode": "1.83.1" + "vscode": "^1.100.0" }, "categories": [ "Programming Languages", @@ -24,7 +24,6 @@ "Snippets" ], "activationEvents": [ - "onStartupFinished", "onLanguage:ballerina", "workspaceContains:**/Ballerina.toml", "onNotebook:ballerina-notebook", @@ -589,7 +588,7 @@ { "command": "BI.test.edit.function", "title": "View test flow", - "icon": "$(distro-design-view)", + "icon": "$(type-hierarchy)", "category": "BI" }, { @@ -600,11 +599,23 @@ }, { "command": "BI.test.add.function", - "title": "Add test case", + "title": "Add New Test", "icon": "$(add)", "category": "BI", "enablement": "isSupportedProject" }, + { + "command": "BI.test.add.ai.evaluation", + "title": "Add AI Evaluation", + "category": "BI", + "enablement": "isSupportedProject" + }, + { + "command": "BI.test.delete.function", + "title": "Delete test function", + "icon": "$(trash)", + "category": "BI" + }, { "command": "BI.view.typeDiagram", "title": "Type Diagram", @@ -723,27 +734,58 @@ }, { "command": "ballerina.enableTracing", - "title": "Enable Tracing (Experimental)", + "title": "Enable Tracing", "category": "Ballerina", "enablement": "isSupportedProject" }, { "command": "ballerina.disableTracing", - "title": "Disable Tracing (Experimental)", + "title": "Disable Tracing", "category": "Ballerina", "icon": "$(circle-slash)", "enablement": "isSupportedProject" }, { "command": "ballerina.clearTraces", - "title": "Clear Traces (Experimental)", + "title": "Clear Traces", "category": "Ballerina", "icon": "$(clear-all)", "hidden": true, "enablement": "isSupportedProject" + }, + { + "command": "ballerina.createNewEvalset", + "title": "Create New Evalset", + "category": "Ballerina", + "icon": "$(add)" + }, + { + "command": "ballerina.createNewThread", + "title": "Add Thread", + "category": "Ballerina", + "icon": "$(add)" + }, + { + "command": "ballerina.deleteEvalset", + "title": "Delete Evalset", + "category": "Ballerina", + "icon": "$(trash)" + }, + { + "command": "ballerina.deleteThread", + "title": "Delete Thread", + "category": "Ballerina", + "icon": "$(trash)" } ], "views": { + "test": [ + { + "id": "ballerina-evalsets", + "name": "Evalsets", + "when": "isBIProject || isBallerinaProject" + } + ], "ballerina-traceView": [ { "id": "ballerina-traceView", @@ -777,6 +819,11 @@ "view": "testing", "contents": "[Add Unit Test](command:BI.test.add.function)", "when": "isBIProject || isBallerinaProject" + }, + { + "view": "testing", + "contents": "[Add AI Evaluation](command:BI.test.add.ai.evaluation)", + "when": "isBIProject || isBallerinaProject" } ], "viewsContainers": { @@ -794,6 +841,13 @@ } ] }, + "submenus": [ + { + "id": "BI.test.add.submenu", + "label": "Add Test", + "icon": "$(add)" + } + ], "menus": { "testing/item/context": [ { @@ -807,9 +861,9 @@ "when": "testId not in testGroups" }, { - "command": "BI.test.add.function", + "command": "BI.test.delete.function", "group": "inline", - "when": "testId in testGroups" + "when": "testId not in testGroups" } ], "view/title": [ @@ -819,7 +873,7 @@ "group": "navigation" }, { - "command": "BI.test.add.function", + "submenu": "BI.test.add.submenu", "when": "(isBIProject || isBallerinaProject) && view == workbench.view.testing", "group": "navigation" }, @@ -834,6 +888,38 @@ "when": "view == ballerina-traceView && ballerina.tracingEnabled && !ballerina.tracesEmpty", "group": "navigation", "title": "Clear Traces" + }, + { + "command": "ballerina.createNewEvalset", + "when": "view == ballerina-evalsets", + "group": "navigation" + } + ], + "view/item/context": [ + { + "command": "ballerina.createNewThread", + "when": "view == ballerina-evalsets && viewItem == evalsetFile", + "group": "inline" + }, + { + "command": "ballerina.deleteEvalset", + "when": "view == ballerina-evalsets && viewItem == evalsetFile", + "group": "inline" + }, + { + "command": "ballerina.deleteThread", + "when": "view == ballerina-evalsets && viewItem == evalsetThread", + "group": "inline" + } + ], + "BI.test.add.submenu": [ + { + "command": "BI.test.add.function", + "group": "1@1" + }, + { + "command": "BI.test.add.ai.evaluation", + "group": "1@2" } ], "editor/title": [ @@ -951,6 +1037,10 @@ "command": "BI.test.edit.function", "when": "false" }, + { + "command": "BI.test.delete.function", + "when": "false" + }, { "command": "BI.project-explorer.delete", "when": "false" @@ -1201,7 +1291,7 @@ "test": "pnpm run test-compile && node ./out/test/runTest.js", "test:ai": "pnpm run test-compile && node ./out/test/runAiTest.js", "test:libs-integration": "pnpm run test-compile && node ./out/test/runLibsIntegrationTest.js", - "e2e-test-setup": "npx extest get-vscode -c 1.83.1 && npx extest get-chromedriver -c 1.83.1 && npx extest install-vsix -f $(ls vsix/*.vsix)", + "e2e-test-setup": "npx extest get-vscode -c 1.100.0 && npx extest get-chromedriver -c 1.100.0 && npx extest install-vsix -f $(ls vsix/*.vsix)", "preui-test": "node -e \"const fs = require('fs'); if (fs.existsSync('test-resou')) { fs.unlinkSync('test-resou'); }\"", "e2e-test": "pnpm run test-compile && npx extest run-tests 'out/ui-test/*.test.js' --mocha_config ui-test/.mocharc.js -o ui-test/settings.json", "test-coverage": "cross-env COVER_CONFIG=html pnpm run test", @@ -1268,10 +1358,10 @@ "@types/mocha": "10.0.3", "@types/node": "18.18.7", "@types/tcp-port-used": "1.0.3", - "@types/vscode": "1.83.1", + "@types/vscode": "1.100.0", "@types/vscode-notebook-renderer": "1.72.2", "adm-zip": "0.5.16", - "axios": "1.12.0", + "axios": "1.13.5", "chai": "4.3.10", "copyfiles": "2.4.1", "cross-env": "7.0.3", @@ -1292,7 +1382,7 @@ "typescript": "5.8.3", "vscode-debugadapter-testsupport": "1.51.0", "vscode-extension-tester": "5.10.0", - "webpack": "5.99.9", + "webpack": "5.104.1", "webpack-cli": "6.0.1", "yarn": "1.22.19" }, diff --git a/workspaces/ballerina/ballerina-extension/src/RPCLayer.ts b/workspaces/ballerina/ballerina-extension/src/RPCLayer.ts index a43b3b1cfeb..8528bf94c3f 100644 --- a/workspaces/ballerina/ballerina-extension/src/RPCLayer.ts +++ b/workspaces/ballerina/ballerina-extension/src/RPCLayer.ts @@ -19,7 +19,7 @@ import { WebviewView, WebviewPanel, window } from 'vscode'; import { Messenger } from 'vscode-messenger'; import { StateMachine } from './stateMachine'; -import { stateChanged, getVisualizerLocation, VisualizerLocation, projectContentUpdated, aiStateChanged, sendAIStateEvent, popupStateChanged, getPopupVisualizerState, PopupVisualizerLocation, breakpointChanged, AIMachineEventType, ArtifactData, onArtifactUpdatedNotification, onArtifactUpdatedRequest, currentThemeChanged, AIMachineSendableEvent, checkpointCaptured, CheckpointCapturedPayload, promptUpdated } from '@wso2/ballerina-core'; +import { stateChanged, getVisualizerLocation, VisualizerLocation, projectContentUpdated, aiStateChanged, sendAIStateEvent, popupStateChanged, getPopupVisualizerState, PopupVisualizerLocation, breakpointChanged, AIMachineEventType, ArtifactData, onArtifactUpdatedNotification, onArtifactUpdatedRequest, currentThemeChanged, AIMachineSendableEvent, checkpointCaptured, CheckpointCapturedPayload, promptUpdated, approvalOverlayState, ApprovalOverlayState } from '@wso2/ballerina-core'; import { VisualizerWebview } from './views/visualizer/webview'; import { registerVisualizerRpcHandlers } from './rpc-managers/visualizer/rpc-handler'; import { registerLangClientRpcHandlers } from './rpc-managers/lang-client/rpc-handler'; @@ -143,14 +143,17 @@ async function getContext(): Promise { haveLS: StateMachine.langClient() && true, recordFilePath: context.projectPath ? path.join(context.projectPath, "types.bal") : undefined, enableSequenceDiagram: extension.ballerinaExtInstance.enableSequenceDiagramView(), - target: context.metadata?.target + target: context.metadata?.target, + featureSupport: context.metadata?.featureSupport }, scope: context.scope, org: context.org, package: context.package, dataMapperMetadata: context.dataMapperMetadata, artifactInfo: context.artifactInfo, - reviewData: context.reviewData + reviewData: context.reviewData, + agentMetadata: context.agentMetadata, + evalsetData: context.evalsetData }); }); } @@ -164,6 +167,7 @@ async function getPopupContext(): Promise { recentIdentifier: context.recentIdentifier, identifier: context.identifier, metadata: context.metadata, + agentMetadata: context.agentMetadata, dataMapperMetadata: context.dataMapperMetadata }); }); @@ -193,3 +197,7 @@ export function notifyBreakpointChange() { export function notifyCheckpointCaptured(payload: CheckpointCapturedPayload) { RPCLayer._messenger.sendNotification(checkpointCaptured, { type: 'webview', webviewType: AiPanelWebview.viewType }, payload); } + +export function notifyApprovalOverlayState(state: ApprovalOverlayState) { + RPCLayer._messenger.sendNotification(approvalOverlayState, { type: 'webview', webviewType: AiPanelWebview.viewType }, state); +} diff --git a/workspaces/ballerina/ballerina-extension/src/core/extended-language-client.ts b/workspaces/ballerina/ballerina-extension/src/core/extended-language-client.ts index 6838b76d00f..d1f9514532f 100644 --- a/workspaces/ballerina/ballerina-extension/src/core/extended-language-client.ts +++ b/workspaces/ballerina/ballerina-extension/src/core/extended-language-client.ts @@ -227,7 +227,6 @@ import { DeleteConfigVariableRequestV2, DeleteConfigVariableResponseV2, ResourceReturnTypesRequest, - ResourceReturnTypesResponse, JsonToTypeRequest, JsonToTypeResponse, McpToolsRequest, @@ -283,7 +282,9 @@ import { PersistClientGenerateRequest, PersistClientGenerateResponse, WSDLApiClientGenerationRequest, - WSDLApiClientGenerationResponse + WSDLApiClientGenerationResponse, + CopilotSearchLibrariesBySearchRequest, + CopilotSearchLibrariesBySearchResponse } from "@wso2/ballerina-core"; import { BallerinaExtension } from "./index"; import { debug, handlePullModuleProgress } from "../utils"; @@ -353,6 +354,7 @@ enum EXTENDED_APIS { BI_VERIFY_TYPE_DELETE = 'typesManager/verifyTypeDelete', BI_DELETE_TYPE = 'typesManager/deleteType', BI_AVAILABLE_NODES = 'flowDesignService/getAvailableNodes', + BI_AVAILABLE_AGENTS = 'flowDesignService/getAvailableAgents', BI_AVAILABLE_MODEL_PROVIDERS = 'flowDesignService/getAvailableModelProviders', BI_AVAILABLE_VECTOR_STORES = 'flowDesignService/getAvailableVectorStores', BI_AVAILABLE_EMBEDDING_PROVIDERS = 'flowDesignService/getAvailableEmbeddingProviders', @@ -475,6 +477,7 @@ enum EXTENDED_APIS { PUBLISH_ARTIFACTS = 'designModelService/publishArtifacts', COPILOT_ALL_LIBRARIES = 'copilotLibraryManager/getLibrariesList', COPILOT_FILTER_LIBRARIES = 'copilotLibraryManager/getFilteredLibraries', + COPILOT_SEARCH_LIBRARIES = 'copilotLibraryManager/getLibrariesBySearch', GET_MIGRATION_TOOLS = 'projectService/getMigrationTools', TIBCO_TO_BI = 'projectService/importTibco', MULE_TO_BI = 'projectService/importMule', @@ -1089,6 +1092,10 @@ export class ExtendedLangClient extends LanguageClient implements ExtendedLangCl return this.sendRequest(EXTENDED_APIS.BI_AVAILABLE_NODES, params); } + async getAvailableAgents(params: BIAvailableNodesRequest): Promise { + return this.sendRequest(EXTENDED_APIS.BI_AVAILABLE_AGENTS, params); + } + async getAvailableModelProviders(params: BIAvailableNodesRequest): Promise { return this.sendRequest(EXTENDED_APIS.BI_AVAILABLE_MODEL_PROVIDERS, params); } @@ -1430,6 +1437,10 @@ export class ExtendedLangClient extends LanguageClient implements ExtendedLangCl return this.sendRequest(EXTENDED_APIS.COPILOT_FILTER_LIBRARIES, params); } + async getCopilotLibrariesBySearch(params: CopilotSearchLibrariesBySearchRequest): Promise { + return this.sendRequest(EXTENDED_APIS.COPILOT_SEARCH_LIBRARIES, params); + } + async getMigrationTools(): Promise { return this.sendRequest(EXTENDED_APIS.GET_MIGRATION_TOOLS); } diff --git a/workspaces/ballerina/ballerina-extension/src/core/extension.ts b/workspaces/ballerina/ballerina-extension/src/core/extension.ts index e63257c23b4..a9f8a7e0860 100644 --- a/workspaces/ballerina/ballerina-extension/src/core/extension.ts +++ b/workspaces/ballerina/ballerina-extension/src/core/extension.ts @@ -487,6 +487,9 @@ export class BallerinaExtension { debug(`[INIT] Auto-detected Ballerina Home: ${this.ballerinaHome}`); debug(`[INIT] Is old Ballerina distribution: ${isOldBallerinaDist}`); debug(`[INIT] Is Ballerina not found: ${isBallerinaNotFound}`); + + // Check for multiple Ballerina installations in PATH + this.checkMultipleBallerinaInstallations(); } catch (error) { debug(`[INIT] Error auto-detecting Ballerina home: ${error}`); throw error; @@ -2281,6 +2284,84 @@ export class BallerinaExtension { return result; } + /** + * Check if multiple Ballerina installations exist in the system PATH. + * Logs a warning if different installations are detected, as this can cause + * unpredictable behavior when different versions are used for different actions. + */ + private checkMultipleBallerinaInstallations(): void { + debug("[MULTI_BAL_CHECK] Checking for multiple Ballerina installations in PATH..."); + + const MULTIPLE_INSTALLATIONS_WARNING = 'Multiple Ballerina installations detected. This may cause unpredictable behavior.'; + const RESOLUTION_ADVICE = 'Consider removing duplicate installations or adjusting your PATH to avoid version conflicts.'; + + try { + let ballerinaPathsOutput = ''; + const execOptions = { + encoding: 'utf8' as const, + timeout: 10000, + env: { ...process.env }, + shell: isWindows() ? undefined : '/bin/sh' + }; + + const command = isWindows() + ? 'where bal' + : 'which -a bal 2>/dev/null || command -v bal 2>/dev/null || type -ap bal 2>/dev/null'; + + try { + ballerinaPathsOutput = execSync(command, execOptions).toString(); + debug(`[MULTI_BAL_CHECK] '${command}' output: ${ballerinaPathsOutput}`); + } catch (error) { + debug(`[MULTI_BAL_CHECK] Command to find bal executables failed: ${error}`); + return; + } + + // Parse the output to get unique paths + const paths = ballerinaPathsOutput + .split(/\r?\n/) + .map(p => p.trim()) + .filter(p => p.length > 0); + + debug(`[MULTI_BAL_CHECK] Found ${paths.length} Ballerina path(s): ${JSON.stringify(paths)}`); + + if (paths.length >= 2) { + // Get unique parent directories to identify different installations + const installationDirs = new Set(); + for (const balPath of paths) { + installationDirs.add(path.dirname(path.resolve(balPath))); + } + + if (installationDirs.size >= 2) { + const pathsList = Array.from(installationDirs).map((p, i) => `${i + 1}. ${p}`); + + // Log warnings + log(`[WARNING] ${MULTIPLE_INSTALLATIONS_WARNING}`); + log(`[WARNING] Detected Ballerina paths:`); + pathsList.forEach(p => log(`[WARNING] ${p}`)); + log(`[WARNING] ${RESOLUTION_ADVICE}`); + + // Show popup notification to user + const viewDetails = 'View Details'; + window.showWarningMessage(MULTIPLE_INSTALLATIONS_WARNING, viewDetails).then((selection) => { + if (selection === viewDetails) { + const detailMessage = `Detected Ballerina installations:\n${pathsList.join('\n')}\n\n${RESOLUTION_ADVICE}`; + window.showWarningMessage(detailMessage, { modal: true }); + } + }); + } else { + debug(`[MULTI_BAL_CHECK] Multiple paths found but they point to the same installation directory`); + } + } else if (paths.length === 1) { + debug(`[MULTI_BAL_CHECK] Single Ballerina installation found: ${paths[0]}`); + } else { + debug(`[MULTI_BAL_CHECK] No Ballerina paths found in PATH`); + } + } catch (error) { + // No need to throw. This is a non-critical check. + debug(`[MULTI_BAL_CHECK] Error checking for multiple installations: ${error}`); + } + } + public overrideBallerinaHome(): boolean { return workspace.getConfiguration().get(OVERRIDE_BALLERINA_HOME); } diff --git a/workspaces/ballerina/ballerina-extension/src/features/ai/agent/AgentExecutor.ts b/workspaces/ballerina/ballerina-extension/src/features/ai/agent/AgentExecutor.ts index ce60265145b..d330e6ce1cf 100644 --- a/workspaces/ballerina/ballerina-extension/src/features/ai/agent/AgentExecutor.ts +++ b/workspaces/ballerina/ballerina-extension/src/features/ai/agent/AgentExecutor.ts @@ -17,23 +17,35 @@ */ import { AICommandExecutor, AICommandConfig, AIExecutionResult } from '../executors/base/AICommandExecutor'; -import { Command, GenerateAgentCodeRequest, ProjectSource, EVENT_TYPE, MACHINE_VIEW, refreshReviewMode, ExecutionContext } from '@wso2/ballerina-core'; +import { Command, GenerateAgentCodeRequest, ProjectSource, MACHINE_VIEW, refreshReviewMode, ExecutionContext } from '@wso2/ballerina-core'; import { ModelMessage, stepCountIs, streamText, TextStreamPart } from 'ai'; import { getAnthropicClient, getProviderCacheControl, ANTHROPIC_SONNET_4 } from '../utils/ai-client'; import { populateHistoryForAgent, getErrorMessage } from '../utils/ai-utils'; import { sendAgentDidOpenForFreshProjects } from '../utils/project/ls-schema-notifications'; import { getSystemPrompt, getUserPrompt } from './prompts'; -import { GenerationType, getAllLibraries } from '../utils/libs/libraries'; +import { GenerationType } from '../utils/libs/libraries'; import { createToolRegistry } from './tool-registry'; import { getProjectSource, cleanupTempProject } from '../utils/project/temp-project'; import { StreamContext } from './stream-handlers/stream-context'; import { checkCompilationErrors } from './tools/diagnostics-utils'; import { updateAndSaveChat } from '../utils/events'; import { chatStateStorage } from '../../../views/ai-panel/chatStateStorage'; -import { openView } from '../../../stateMachine'; import { RPCLayer } from '../../../RPCLayer'; import { VisualizerWebview } from '../../../views/visualizer/webview'; import * as path from 'path'; +import { approvalViewManager } from '../state/ApprovalViewManager'; +import { + sendTelemetryEvent, + sendTelemetryException, + TM_EVENT_BALLERINA_AI_GENERATION_COMPLETED, + TM_EVENT_BALLERINA_AI_GENERATION_ABORTED, + TM_EVENT_BALLERINA_AI_GENERATION_FAILED, + CMP_BALLERINA_AI_GENERATION +} from "../../telemetry"; +import { extension } from "../../../BalExtensionContext"; +import { getProjectMetrics } from "../../telemetry/common/project-metrics"; +import { getHashedProjectId } from "../../telemetry/common/project-id"; +import { workspace } from 'vscode'; /** * Determines which packages have been affected by analyzing modified files @@ -70,7 +82,7 @@ function determineAffectedPackages( for (const project of projects) { if (project.packagePath === "") { // Root package in workspace (edge case) - if (!modifiedFile.includes('/') || + if (!modifiedFile.includes('/') || !projects.some(p => p.packagePath && modifiedFile.startsWith(p.packagePath + '/'))) { // Root package is at the temp project path directly affectedPackages.add(tempProjectPath); @@ -80,7 +92,7 @@ function determineAffectedPackages( } } else { // Package with a specific path in workspace - if (modifiedFile.startsWith(project.packagePath + '/') || + if (modifiedFile.startsWith(project.packagePath + '/') || modifiedFile === project.packagePath) { // Map to temp package path: tempProjectPath + relative package path const tempPackagePath = path.join(tempProjectPath, project.packagePath); @@ -136,6 +148,8 @@ export class AgentExecutor extends AICommandExecutor { const tempProjectPath = this.config.executionContext.tempProjectPath!; const params = this.config.params; // Access params from config const modifiedFiles: string[] = []; + const generationStartTime = Date.now(); + const projectId = await getHashedProjectId(this.config.executionContext.projectPath); try { // 1. Get project sources from temp directory @@ -181,19 +195,12 @@ export class AgentExecutor extends AICommandExecutor { }, ]; - // Get libraries for library provider tool - const allLibraries = await getAllLibraries(GenerationType.CODE_GENERATION); - const libraryDescriptions = allLibraries.length > 0 - ? allLibraries.map((lib) => `- ${lib.name}: ${lib.description}`).join("\n") - : "- No libraries available"; - // Create tools const tools = createToolRegistry({ eventHandler: this.config.eventHandler, tempProjectPath, modifiedFiles, projects, - libraryDescriptions, generationType: GenerationType.CODE_GENERATION, workspaceId: this.config.executionContext.projectPath, generationId: this.config.generationId, @@ -201,7 +208,7 @@ export class AgentExecutor extends AICommandExecutor { }); // Stream LLM response - const { fullStream, response } = streamText({ + const { fullStream, response, usage } = streamText({ model: await getAnthropicClient(ANTHROPIC_SONNET_4), maxOutputTokens: 8192, temperature: 0, @@ -223,7 +230,10 @@ export class AgentExecutor extends AICommandExecutor { messageId: this.config.generationId, userMessageContent, response, + usage, ctx: this.config.executionContext, + generationStartTime, + projectId, }; // Process stream events - NATIVE V6 PATTERN @@ -279,6 +289,21 @@ Generation stopped by user. The last in-progress task was not saved. Files have chatStateStorage.declineAllReviews(workspaceId, threadId); } + // Send telemetry for generation abort + const abortTime = Date.now(); + sendTelemetryEvent( + extension.ballerinaExtInstance, + TM_EVENT_BALLERINA_AI_GENERATION_ABORTED, + CMP_BALLERINA_AI_GENERATION, + { + 'message.id': this.config.generationId, + 'project.id': projectId, + 'generation.start_time': generationStartTime.toString(), + 'generation.abort_time': abortTime.toString(), + 'generation.modified_files_count': modifiedFiles.length.toString(), + } + ); + // Note: Abort event is sent by base class handleExecutionError() } @@ -373,6 +398,25 @@ Generation stopped by user. The last in-progress task was not saved. Files have }); } + // Send telemetry for generation failed + const errorTime = Date.now(); + sendTelemetryException( + extension.ballerinaExtInstance, + error, + CMP_BALLERINA_AI_GENERATION, + { + 'event.name': TM_EVENT_BALLERINA_AI_GENERATION_FAILED, + 'message.id': context.messageId, + 'project.id': context.projectId, + 'error.message': getErrorMessage(error), + 'error.type': error.name || 'Unknown', + 'error.code': (error as any)?.code || 'N/A', + 'generation.start_time': context.generationStartTime.toString(), + 'generation.error_time': errorTime.toString(), + 'generation.duration_ms': (errorTime - context.generationStartTime).toString(), + } + ); + context.eventHandler({ type: "error", content: getErrorMessage(error) @@ -394,6 +438,37 @@ Generation stopped by user. The last in-progress task was not saved. Files have diagnostics: finalDiagnostics.diagnostics }); + // Send telemetry for generation completion + const generationEndTime = Date.now(); + const isPlanModeEnabled = workspace.getConfiguration('ballerina.ai').get('planMode', false); + const finalProjectMetrics = await getProjectMetrics(tempProjectPath); + + // Get token usage from streamText result + const tokenUsage = await context.usage; + const inputTokens = tokenUsage.inputTokens || 0; + const outputTokens = tokenUsage.outputTokens || 0; + const totalTokens = tokenUsage.totalTokens || 0; + + // Send telemetry for generation complete + sendTelemetryEvent( + extension.ballerinaExtInstance, + TM_EVENT_BALLERINA_AI_GENERATION_COMPLETED, + CMP_BALLERINA_AI_GENERATION, + { + 'message.id': context.messageId, + 'project.id': context.projectId, + 'generation.modified_files_count': context.modifiedFiles.length.toString(), + 'generation.start_time': context.generationStartTime.toString(), + 'generation.end_time': generationEndTime.toString(), + 'plan_mode': isPlanModeEnabled.toString(), + 'project.files_after': finalProjectMetrics.fileCount.toString(), + 'project.lines_after': finalProjectMetrics.lineCount.toString(), + 'tokens.input': inputTokens.toString(), + 'tokens.output': outputTokens.toString(), + 'tokens.total': totalTokens.toString(), + } + ); + // Update chat state storage await this.updateChatState(context, assistantMessages, tempProjectPath); @@ -456,9 +531,8 @@ Generation stopped by user. The last in-progress task was not saved. Files have affectedPackagePaths: affectedPackagePaths, }); - // Automatically open review mode - openView(EVENT_TYPE.OPEN_VIEW, { view: MACHINE_VIEW.ReviewMode }); - console.log("[AgentExecutor] Automatically opened review mode"); + // Open ReviewMode + approvalViewManager.openView(MACHINE_VIEW.ReviewMode); // Notify ReviewMode component to refresh its data setTimeout(() => { diff --git a/workspaces/ballerina/ballerina-extension/src/features/ai/agent/index.ts b/workspaces/ballerina/ballerina-extension/src/features/ai/agent/index.ts index a4178bce660..94222509d10 100644 --- a/workspaces/ballerina/ballerina-extension/src/features/ai/agent/index.ts +++ b/workspaces/ballerina/ballerina-extension/src/features/ai/agent/index.ts @@ -21,6 +21,14 @@ import { chatStateStorage } from '../../../views/ai-panel/chatStateStorage'; import { AICommandConfig } from "../executors/base/AICommandExecutor"; import { createWebviewEventHandler } from "../utils/events"; import { AgentExecutor } from './AgentExecutor'; +import { + sendTelemetryEvent, + TM_EVENT_BALLERINA_AI_GENERATION_SUBMITTED, + CMP_BALLERINA_AI_GENERATION +} from "../../telemetry"; +import { extension } from "../../../BalExtensionContext"; +import { getProjectMetrics } from "../../telemetry/common/project-metrics"; +import { getHashedProjectId } from "../../telemetry/common/project-id"; // ================================== // Agent Generation Functions @@ -83,6 +91,29 @@ export async function generateAgent(params: GenerateAgentCodeRequest): Promise 0).toString(), + 'chat.has_history': (chatHistory.length > 0).toString(), + 'chat.history_length': chatHistory.length.toString(), + } + ); + await new AgentExecutor(config).run(); return true; diff --git a/workspaces/ballerina/ballerina-extension/src/features/ai/agent/np/prompts.ts b/workspaces/ballerina/ballerina-extension/src/features/ai/agent/np/prompts.ts index 5a74ec2e419..f241e52f691 100644 --- a/workspaces/ballerina/ballerina-extension/src/features/ai/agent/np/prompts.ts +++ b/workspaces/ballerina/ballerina-extension/src/features/ai/agent/np/prompts.ts @@ -14,6 +14,8 @@ // specific language governing permissions and limitations // under the License. +import { CONFIG_COLLECTOR_TOOL } from "../tools/config-collector"; + export const REQUIREMENTS_DOCUMENT_KEY: string = "user_requirements_file"; export function getRequirementAnalysisCodeGenPrefix(requirementAnalysisDocument: string) { @@ -93,6 +95,12 @@ You are an expert test automation engineer specializing in generating test artif 2. Create Ballerina test module with: - Network client configurations (if required, e.g., HTTP, GraphQL, WebSocket, etc.) + - Setup test configuration (if main code uses it): + * If main code uses configuration values (API keys, tokens, passwords), use ${CONFIG_COLLECTOR_TOOL} + * Set mode: "collect", isTestConfig: true + * Tell user: "Setting up test configuration based on main configuration" + * The tool will automatically handle reading from main config and saving to tests/Config.toml + * Example: { mode: "collect", variables: [{ name: "API_KEY", description: "Stripe API key", type: "string" }], isTestConfig: true } - Test data factories - Reusable validation functions diff --git a/workspaces/ballerina/ballerina-extension/src/features/ai/agent/prompts.ts b/workspaces/ballerina/ballerina-extension/src/features/ai/agent/prompts.ts index af8bb6f8bf0..45321533fcc 100644 --- a/workspaces/ballerina/ballerina-extension/src/features/ai/agent/prompts.ts +++ b/workspaces/ballerina/ballerina-extension/src/features/ai/agent/prompts.ts @@ -15,10 +15,12 @@ // under the License. import { DIAGNOSTICS_TOOL_NAME } from "./tools/diagnostics"; -import { LIBRARY_PROVIDER_TOOL } from "../utils/libs/libraries"; +import { LIBRARY_GET_TOOL } from "./tools/library-get"; +import { LIBRARY_SEARCH_TOOL } from "./tools/library-search"; import { TASK_WRITE_TOOL_NAME } from "./tools/task-writer"; import { FILE_BATCH_EDIT_TOOL_NAME, FILE_SINGLE_EDIT_TOOL_NAME, FILE_WRITE_TOOL_NAME } from "./tools/text-editor"; import { CONNECTOR_GENERATOR_TOOL } from "./tools/connector-generator"; +import { CONFIG_COLLECTOR_TOOL } from "./tools/config-collector"; import { getLanglibInstructions } from "../utils/libs/langlibs"; import { formatCodebaseStructure, formatCodeContext } from "./utils"; import { GenerateAgentCodeRequest, OperationType, ProjectSource } from "@wso2/ballerina-core"; @@ -92,8 +94,9 @@ This plan will be visible to the user and the execution will be guided on the ta - Mark task as in_progress using ${TASK_WRITE_TOOL_NAME} and immediately start implementation in parallel (single message with multiple tool calls) - Implement the task completely (write the Ballerina code) - When implementing external API integrations: - - First check ${LIBRARY_PROVIDER_TOOL} for known services (Stripe, GitHub, etc.) - - If NOT available, call ${CONNECTOR_GENERATOR_TOOL} to generate connector from OpenAPI spec + - First use ${LIBRARY_SEARCH_TOOL} with relevant keywords to discover available libraries + - Then use ${LIBRARY_GET_TOOL} to fetch full details for the discovered libraries + - If NO suitable library is found, call ${CONNECTOR_GENERATOR_TOOL} to generate connector from OpenAPI spec - Before marking the task as completed, use the ${DIAGNOSTICS_TOOL_NAME} tool to check for compilation errors and fix them. Introduce a a new subtask if needed to fix errors. - Mark task as completed using ${TASK_WRITE_TOOL_NAME} (send ALL tasks) - The tool will wait for TASK COMPLETION APPROVAL from the user @@ -113,8 +116,8 @@ In the tags, you will see if Edit mode is enabled. When its en ### Step 1: Create High-Level Design Create a very high-level and concise design plan for the given user requirement. Avoid using ${TASK_WRITE_TOOL_NAME} tool in this mode. -### Step 2: Identify nescessary libraries -Identify the libraries required to implement the user requirement. Use the ${LIBRARY_PROVIDER_TOOL} tool to get the information about the libraries. +### Step 2: Identify necessary libraries +Identify the libraries required to implement the user requirement. Use ${LIBRARY_SEARCH_TOOL} to discover relevant libraries, then use ${LIBRARY_GET_TOOL} to fetch their full details. ### Step 3: Write the code Write/modify the Ballerina code to implement the user requirement. Use the ${FILE_BATCH_EDIT_TOOL_NAME}, ${FILE_SINGLE_EDIT_TOOL_NAME}, ${FILE_WRITE_TOOL_NAME} tools to write/modify the code. @@ -131,8 +134,8 @@ Once the code is written and validated, provide a very concise summary of the ov When generating Ballerina code strictly follow these syntax and structure guidelines: ## Library Usage and Importing libraries -- Only use the libraries received from user query or the ${LIBRARY_PROVIDER_TOOL} tool or langlibs. -- Examine the library API documentation provided by the ${LIBRARY_PROVIDER_TOOL} carefully. Strictly follow the type definitions, function signatures, and all the other details provided when writing the code. +- Only use the libraries received from user query or discovered via ${LIBRARY_SEARCH_TOOL} and fetched via ${LIBRARY_GET_TOOL}, or langlibs. +- Examine the library API documentation provided by ${LIBRARY_GET_TOOL} carefully. Strictly follow the type definitions, function signatures, and all the other details provided when writing the code. - Each .bal file must include its own import statements for any external library references. - Do not import default langlibs (lang.string, lang.boolean, lang.float, lang.decimal, lang.int, lang.map). - For packages with dots in names, use aliases: \`import org/package.one as one;\` @@ -150,6 +153,11 @@ ${getLanglibInstructions()} ## Code Structure - Define required configurables for the query. Use only string, int, decimal, boolean types in configurable variables. +- For sensitive configuration values (API keys, tokens, passwords), use ${CONFIG_COLLECTOR_TOOL} in COLLECT mode. Variable names are converted to lowercase without underscores in Config.toml. You MUST use the exact Config.toml names in your Ballerina configurables to avoid runtime errors. +- When generating tests that need configuration values: + - Use COLLECT mode with isTestConfig: true + - The tool will automatically read existing values from Config.toml (if exists), ask user to reuse or modify for testing, and save to tests/Config.toml + - Example: { mode: "collect", variables: [...], isTestConfig: true } - Initialize any necessary clients with the correct configuration based on the retrieved libraries at the module level (before any function or service declarations). - Implement the main function OR service to address the query requirements. @@ -179,7 +187,7 @@ ${getLanglibInstructions()} )} tools. The complete existing source code will be provided in the section of the user prompt. - When making replacements inside an existing file, provide the **exact old string** and the **exact new string** with all newlines, spaces, and indentation, being mindful to replace nearby occurrences together to minimize the number of tool calls. - Do NOT create a new markdown file to document each change or summarize your work unless specifically requested by the user. -- Do not add/modify toml files (Config.toml/Ballerina.toml/Dependencies.toml) as you don't have access to those files. +- Do not manually add/modify toml files (Ballerina.toml/Dependencies.toml). For Config.toml configuration management, use ${CONFIG_COLLECTOR_TOOL}. - Prefer modifying existing bal files over creating new files unless explicitly asked to create a new file in the query. ${getNPSuffix(projects, op)} diff --git a/workspaces/ballerina/ballerina-extension/src/features/ai/agent/stream-handlers/stream-context.ts b/workspaces/ballerina/ballerina-extension/src/features/ai/agent/stream-handlers/stream-context.ts index d78bd5d737d..21b2e74abff 100644 --- a/workspaces/ballerina/ballerina-extension/src/features/ai/agent/stream-handlers/stream-context.ts +++ b/workspaces/ballerina/ballerina-extension/src/features/ai/agent/stream-handlers/stream-context.ts @@ -38,6 +38,13 @@ export interface StreamContext { // Response promise (for message history and abort/finish handling) response: StreamTextResult['response']; + // Token usage promise (for telemetry) + usage: StreamTextResult['usage']; + // Execution context (for workspace integration) ctx: ExecutionContext; + + // Telemetry tracking + generationStartTime: number; + projectId: string; } diff --git a/workspaces/ballerina/ballerina-extension/src/features/ai/agent/tool-registry.ts b/workspaces/ballerina/ballerina-extension/src/features/ai/agent/tool-registry.ts index 9de1be76dd7..003b2a3ce37 100644 --- a/workspaces/ballerina/ballerina-extension/src/features/ai/agent/tool-registry.ts +++ b/workspaces/ballerina/ballerina-extension/src/features/ai/agent/tool-registry.ts @@ -35,17 +35,18 @@ import { FILE_SINGLE_EDIT_TOOL_NAME, FILE_WRITE_TOOL_NAME } from './tools/text-editor'; -import { getLibraryProviderTool } from './tools/library-provider'; -import { LIBRARY_PROVIDER_TOOL, GenerationType } from '../utils/libs/libraries'; +import { getLibraryGetTool, LIBRARY_GET_TOOL } from './tools/library-get'; +import { GenerationType } from '../utils/libs/libraries'; import { getHealthcareLibraryProviderTool, HEALTHCARE_LIBRARY_PROVIDER_TOOL } from './tools/healthcare-library'; import { createConnectorGeneratorTool, CONNECTOR_GENERATOR_TOOL } from './tools/connector-generator'; +import { LIBRARY_SEARCH_TOOL, getLibrarySearchTool } from './tools/library-search'; +import { createConfigCollectorTool, CONFIG_COLLECTOR_TOOL } from './tools/config-collector'; export interface ToolRegistryOptions { eventHandler: CopilotEventHandler; tempProjectPath: string; modifiedFiles: string[]; projects: ProjectSource[]; - libraryDescriptions: string; generationType: GenerationType; workspaceId: string; generationId: string; @@ -53,7 +54,7 @@ export interface ToolRegistryOptions { } export function createToolRegistry(opts: ToolRegistryOptions) { - const { eventHandler, tempProjectPath, modifiedFiles, projects, libraryDescriptions, generationType, workspaceId, generationId, threadId } = opts; + const { eventHandler, tempProjectPath, modifiedFiles, projects, generationType, workspaceId, generationId, threadId } = opts; return { [TASK_WRITE_TOOL_NAME]: createTaskWriteTool( eventHandler, @@ -63,13 +64,14 @@ export function createToolRegistry(opts: ToolRegistryOptions) { generationId, threadId || 'default' ), - [LIBRARY_PROVIDER_TOOL]: getLibraryProviderTool( - libraryDescriptions, + [LIBRARY_GET_TOOL]: getLibraryGetTool( generationType, eventHandler ), + [LIBRARY_SEARCH_TOOL]: getLibrarySearchTool( + eventHandler + ), [HEALTHCARE_LIBRARY_PROVIDER_TOOL]: getHealthcareLibraryProviderTool( - libraryDescriptions, eventHandler ), [CONNECTOR_GENERATOR_TOOL]: createConnectorGeneratorTool( @@ -78,6 +80,14 @@ export function createToolRegistry(opts: ToolRegistryOptions) { projects[0].projectName, modifiedFiles ), + [CONFIG_COLLECTOR_TOOL]: createConfigCollectorTool( + eventHandler, + { + tempPath: tempProjectPath, + workspacePath: workspaceId + }, + modifiedFiles + ), [FILE_WRITE_TOOL_NAME]: createWriteTool( createWriteExecute(eventHandler, tempProjectPath, modifiedFiles) ), diff --git a/workspaces/ballerina/ballerina-extension/src/features/ai/agent/tools/config-collector.ts b/workspaces/ballerina/ballerina-extension/src/features/ai/agent/tools/config-collector.ts new file mode 100644 index 00000000000..062ee98273a --- /dev/null +++ b/workspaces/ballerina/ballerina-extension/src/features/ai/agent/tools/config-collector.ts @@ -0,0 +1,602 @@ +// Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com/) All Rights Reserved. + +// WSO2 LLC. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +import { tool } from "ai"; +import * as crypto from "crypto"; +import * as fs from "fs"; +import * as path from "path"; +import { z } from "zod"; +import { CopilotEventHandler } from "../../utils/events"; +import { approvalManager } from "../../state/ApprovalManager"; +import { + ConfigVariable, + createConfigWithPlaceholders, + getAllConfigStatus, + validateVariableName, + writeConfigValuesToConfig, + createStatusMetadata, + readExistingConfigValues, +} from "../../../../utils/toml-utils"; + +export const CONFIG_COLLECTOR_TOOL = "ConfigCollector"; + +// Constants for config file paths +const CONFIG_FILE_PATH = "Config.toml"; +const TEST_CONFIG_FILE_PATH = "tests/Config.toml"; + +const ConfigVariableSchema = z.object({ + name: z.string().describe("Variable name (e.g., API_KEY)"), + description: z.string().describe("Human-readable description"), + type: z.enum(["string", "int"]).optional().describe("Data type: string (default) or int"), +}); + +const ConfigCollectorSchema = z.object({ + mode: z.enum(["create", "create_and_collect", "collect", "check"]).describe("Operation mode"), + filePath: z.string().optional().describe("Path to config file (for check mode)"), + variables: z.array(ConfigVariableSchema).optional().describe("Configuration variables"), + variableNames: z.array(z.string()).optional().describe("Variable names for check mode"), + isTestConfig: z.boolean().optional().describe("Set to true when collecting configuration for tests. Tool will automatically read from Config.toml and write to tests/Config.toml"), +}); + +interface ConfigCollectorInput { + mode: "create" | "create_and_collect" | "collect" | "check"; + filePath?: string; + variables?: ConfigVariable[]; + variableNames?: string[]; + isTestConfig?: boolean; +} + +export interface ConfigCollectorResult { + success: boolean; + message: string; + status?: Record; + error?: string; + errorCode?: string; +} + +export interface ConfigCollectorPaths { + tempPath: string; + workspacePath: string; +} + +// Helper functions +function getConfigPath(basePath: string, isTestConfig?: boolean): string { + return isTestConfig + ? path.join(basePath, "tests", "Config.toml") + : path.join(basePath, "Config.toml"); +} + +function getConfigFileName(isTestConfig?: boolean): string { + return isTestConfig ? TEST_CONFIG_FILE_PATH : CONFIG_FILE_PATH; +} + +function validateConfigVariables( + variables: ConfigVariable[] +): ConfigCollectorResult | null { + for (const variable of variables) { + if (!validateVariableName(variable.name)) { + return createErrorResult( + "INVALID_VARIABLE_NAME", + `Invalid variable name: ${variable.name}. Use uppercase with underscores (e.g., API_KEY)` + ); + } + } + return null; // Valid +} + +function createErrorResult(errorCode: string, message: string): ConfigCollectorResult { + return { + success: false, + message, + error: message, + errorCode, + }; +} + +export function createConfigCollectorTool( + eventHandler: CopilotEventHandler, + paths: ConfigCollectorPaths, + modifiedFiles?: string[] +) { + return tool({ + description: ` +Manages configuration values in Config.toml for Ballerina integrations securely. Use this tool when user requirements involve API keys, passwords, database credentials, or other sensitive configuration. + +IMPORTANT: Before calling COLLECT or CREATE_AND_COLLECT modes, briefly tell the user what configuration values you need and why. + +Operation Modes: +1. CREATE: Create Config.toml with placeholder variables only + - If file already exists, returns current variable status (same as check mode) instead of overwriting + - Use when you need to set up config structure before collecting configuration values + - Example: { mode: "create", variables: [{ name: "API_KEY", description: "Stripe API key", type: "string" }] } + +2. CREATE_AND_COLLECT: Create config AND immediately request configuration values (most efficient) + - If file already exists, skips create and goes straight to collect + - Use for new integrations that need configuration values right away + - Tell user first what you need + - Example: { mode: "create_and_collect", variables: [{ name: "API_KEY", description: "Stripe API key", type: "string" }] } + +3. COLLECT: Request configuration values from user + - Creates Config.toml if it doesn't exist + - Pre-populates existing values for easy editing + - Use when Config.toml already exists and needs configuration values + - Tell user first what you need + - Example: { mode: "collect", variables: [{ name: "API_KEY", description: "Stripe API key", type: "string" }] } + +4. CHECK: Check which configuration values are filled/missing + - Returns status metadata only, NEVER actual configuration values + - Example: { mode: "check", variableNames: ["API_KEY", "DB_PASSWORD"], filePath: "Config.toml" } + - Returns: { success: true, status: { API_KEY: "filled", DB_PASSWORD: "missing" } } + +5. COLLECT with isTestConfig: Request configuration values for test Config.toml + - Use when generating tests that need configuration values + - Set isTestConfig: true + - Tool automatically: + * Reads existing configuration from Config.toml (if exists) + * Writes to tests/Config.toml + * Creates tests/ directory if needed + - UI behavior depends on what's in main config: + * If placeholders found: Shows "Configuration values needed" + * If actual values found: Shows "Found existing values. You can reuse or update them for testing." + * If mixed: Shows "Complete the remaining configuration values" + - Works even if main Config.toml doesn't exist (shows empty form) + - Example: { mode: "collect", variables: [{ name: "API_KEY", description: "Stripe API key", type: "string" }], isTestConfig: true } + +IMPORTANT: When generating tests that use configurables, ALWAYS use isTestConfig: true. +This ensures tests have their own Config.toml in the tests/ directory. + +VARIABLE NAMING (CRITICAL): +Variable names are converted: API_KEY → apikey, DB_HOST → dbhost (lowercase, no underscores). +You MUST use identical names in Config.toml and Ballerina code. + +Correct: + Tool: { name: "DB_HOST" } + Config.toml: dbhost = "localhost" + Code: configurable string dbhost = ?; + +Incorrect (DO NOT DO): + Tool: { name: "DB_HOST" } + Config.toml: dbhost = "localhost" + Code: configurable string dbHost = ?; // WRONG - mismatch causes runtime error + +SECURITY: +- You NEVER see actual configuration values +- Tool returns only status: { API_KEY: "filled" } +- NEVER hardcode configuration values in code`, + inputSchema: ConfigCollectorSchema, + execute: async (input) => { + return await ConfigCollectorTool( + input as ConfigCollectorInput, + eventHandler, + paths, + modifiedFiles + ); + }, + }); +} + +/** + * Analyze existing configuration values to determine their status and appropriate UI message + */ +function analyzeExistingConfig( + existingValues: Record, + variableNames: string[] +): { + hasActualValues: boolean; + hasPlaceholders: boolean; + filledCount: number; + message: string; +} { + let filledCount = 0; + let placeholderCount = 0; + + for (const name of variableNames) { + const value = existingValues[name]; + if (value && !value.startsWith('${')) { + filledCount++; + } else { + placeholderCount++; + } + } + + let message = ""; + if (filledCount === 0) { + message = "Configuration values needed"; + } else if (placeholderCount === 0) { + message = "Found existing values. You can reuse or update them."; + } else { + message = "Complete the remaining configuration values"; + } + + return { + hasActualValues: filledCount > 0, + hasPlaceholders: placeholderCount > 0, + filledCount, + message + }; +} + +export async function ConfigCollectorTool( + input: ConfigCollectorInput, + eventHandler: CopilotEventHandler, + paths: ConfigCollectorPaths, + modifiedFiles?: string[] +): Promise { + if (!eventHandler) { + return createErrorResult("INVALID_INPUT", "Event handler is required"); + } + + const requestId = crypto.randomUUID(); + + try { + switch (input.mode) { + case "create": + return await handleCreateMode( + input.variables, + paths, + eventHandler, + requestId, + input.isTestConfig, + modifiedFiles + ); + + case "create_and_collect": + return await handleCreateAndCollectMode( + input.variables, + paths, + eventHandler, + requestId, + input.isTestConfig, + modifiedFiles + ); + + case "collect": + return await handleCollectMode( + input.variables, + paths, + eventHandler, + requestId, + input.isTestConfig, + modifiedFiles + ); + + case "check": + return await handleCheckMode( + input.variableNames, + input.filePath, + paths, + input.isTestConfig + ); + + default: + // TypeScript should prevent this with discriminated unions + return createErrorResult("INVALID_MODE", `Unknown mode: ${(input as any).mode}`); + } + } catch (error: any) { + return handleError(error, requestId, eventHandler); + } +} + +async function handleCreateMode( + variables: ConfigVariable[], + paths: ConfigCollectorPaths, + eventHandler: CopilotEventHandler, + requestId: string, + isTestConfig?: boolean, + modifiedFiles?: string[] +): Promise { + // Validate variable names + const validationError = validateConfigVariables(variables); + if (validationError) { return validationError; } + + const configPath = getConfigPath(paths.tempPath, isTestConfig); + const configFileName = getConfigFileName(isTestConfig); + + // If file already exists, delegate to check mode to inform the agent of current status + if (fs.existsSync(configPath)) { + console.log(`[ConfigCollector] CREATE mode - ${configFileName} already exists, delegating to check mode`); + const variableNames = variables.map((v) => v.name); + const checkResult = await handleCheckMode(variableNames, undefined, paths, isTestConfig); + return { + ...checkResult, + message: `${configFileName} already exists. ${checkResult.message}. Use collect mode to update values.`, + }; + } + + console.log(`[ConfigCollector] CREATE mode - Creating ${configFileName} with placeholders`); + + eventHandler({ + type: "configuration_collection_event", + requestId, + stage: "creating_file", + message: isTestConfig + ? "Creating configuration file for tests..." + : "Creating configuration file...", + isTestConfig, + }); + + createConfigWithPlaceholders(configPath, variables, false); + + if (modifiedFiles && !modifiedFiles.includes(configFileName)) { + modifiedFiles.push(configFileName); + } + + eventHandler({ + type: "configuration_collection_event", + requestId, + stage: "done", + message: isTestConfig + ? "Configuration file for tests created" + : "Configuration file created", + isTestConfig, + }); + + return { + success: true, + message: `Created ${configFileName} with ${variables.length} placeholder variable(s). Use collect mode to request configuration values from user.`, + }; +} + +async function handleCreateAndCollectMode( + variables: ConfigVariable[], + paths: ConfigCollectorPaths, + eventHandler: CopilotEventHandler, + requestId: string, + isTestConfig?: boolean, + modifiedFiles?: string[] +): Promise { + const configPath = getConfigPath(paths.tempPath, isTestConfig); + + // If file already exists, skip create and go straight to collect + if (!fs.existsSync(configPath)) { + const createResult = await handleCreateMode( + variables, + paths, + eventHandler, + requestId, + isTestConfig, + modifiedFiles + ); + if (!createResult.success) { + return createResult; + } + } + + return await handleCollectMode( + variables, + paths, + eventHandler, + requestId, + isTestConfig, + modifiedFiles + ); +} + +async function handleCollectMode( + variables: ConfigVariable[], + paths: ConfigCollectorPaths, + eventHandler: CopilotEventHandler, + requestId: string, + isTestConfig?: boolean, + modifiedFiles?: string[] +): Promise { + // Validate variable names + const validationError = validateConfigVariables(variables); + if (validationError) { return validationError; } + + // Determine paths based on isTestConfig flag + const configPath = getConfigPath(paths.tempPath, isTestConfig); + + // Priority: tests/Config.toml → Config.toml → empty + const mainConfigPath = path.join(paths.tempPath, "Config.toml"); + const sourceConfigPath = isTestConfig + ? (fs.existsSync(configPath) ? configPath : mainConfigPath) + : configPath; + + // Capture whether the test config already existed + const testConfigPreExisted = isTestConfig && fs.existsSync(configPath); + + // Create config file if it doesn't exist + if (!fs.existsSync(configPath)) { + console.log(`[ConfigCollector] Creating ${getConfigFileName(isTestConfig)}`); + + // Emit creating_file stage + eventHandler({ + type: "configuration_collection_event", + requestId, + stage: "creating_file", + message: isTestConfig + ? "Setting up tests/Config.toml..." + : "Setting up Config.toml...", + isTestConfig, + }); + + createConfigWithPlaceholders(configPath, variables, false); + + // Track modified file + if (modifiedFiles) { + const configFileName = getConfigFileName(isTestConfig); + if (!modifiedFiles.includes(configFileName)) { + modifiedFiles.push(configFileName); + } + } + } + + // Read existing configuration values from source config (if they exist) + const existingValues = readExistingConfigValues( + sourceConfigPath, + variables.map(v => v.name) + ); + + // Analyze existing values to determine appropriate messaging + const analysis = analyzeExistingConfig( + existingValues, + variables.map(v => v.name) + ); + + console.log(`[ConfigCollector] ${isTestConfig ? 'Test' : 'Main'} configuration: ${analysis.filledCount} filled`); + + // Determine the message to show to user + const userMessage = isTestConfig + ? (analysis.hasActualValues + ? (testConfigPreExisted + ? "Found existing test values. You can update them." + : "Found values from main config. You can reuse or update them for testing.") + : "Test configuration values needed") + : (analysis.hasActualValues + ? "Update configuration values" + : "Configuration values needed"); + + // Request configuration values from user via ApprovalManager + // This returns ACTUAL values (not exposed to agent) + const userResponse = await approvalManager.requestConfiguration( + requestId, + variables, + existingValues, + eventHandler, + isTestConfig, + userMessage + ); + + if (!userResponse.provided) { + // User cancelled + const configFileName = getConfigFileName(isTestConfig); + eventHandler({ + type: "configuration_collection_event", + requestId, + stage: "skipped", + message: `Configuration collection skipped${userResponse.comment ? ": " + userResponse.comment : ""}`, + isTestConfig, + }); + + return { + success: false, + message: `User cancelled configuration collection${userResponse.comment ? ": " + userResponse.comment : ""}. ${configFileName} has placeholder values. You can ask user to provide values later using collect mode.`, + error: `User cancelled${userResponse.comment ? ": " + userResponse.comment : ""}`, + errorCode: "USER_CANCELLED", + }; + } + + // Write actual configuration values to determined config path + writeConfigValuesToConfig(configPath, userResponse.configValues!, variables); + + // Track modified file for syncing to workspace + if (modifiedFiles) { + const configFileName = getConfigFileName(isTestConfig); + if (!modifiedFiles.includes(configFileName)) { + modifiedFiles.push(configFileName); + } + } + + // Convert to status metadata (filled/missing) - NEVER return actual values to agent + const statusMetadata = createStatusMetadata(userResponse.configValues!); + + // Clear values from memory + userResponse.configValues = undefined; + + // Success - configuration values were collected and written + const configFileName = getConfigFileName(isTestConfig); + eventHandler({ + type: "configuration_collection_event", + requestId, + stage: "done", + message: isTestConfig + ? "Test configuration saved to tests/Config.toml" + : "Configuration saved to Config.toml", + isTestConfig, + }); + + return { + success: true, + message: `Successfully collected ${variables.length} configuration value(s) and saved to ${configFileName}${userResponse.comment ? ". User note: " + userResponse.comment : ""}`, + status: statusMetadata, + }; +} + +async function handleCheckMode( + variableNames: string[], + filePath: string | undefined, + paths: ConfigCollectorPaths, + isTestConfig?: boolean +): Promise { + let configPath: string; + let configFileName: string; + if (filePath) { + configPath = path.join(paths.tempPath, filePath); + configFileName = path.basename(filePath); + } else { + configPath = getConfigPath(paths.tempPath, isTestConfig); + configFileName = getConfigFileName(isTestConfig); + } + + if (!fs.existsSync(configPath)) { + return { + success: false, + message: `${configFileName} not found. Use create or collect mode to create it.`, + error: "FILE_NOT_FOUND", + errorCode: "FILE_NOT_FOUND", + }; + } + + // Read all variables from the file + const status = getAllConfigStatus(configPath); + + // Any requested variable names not found in file → mark as missing + for (const name of variableNames) { + if (!(name in status)) { + status[name] = "missing"; + } + } + + const filledCount = Object.values(status).filter((s) => s === "filled").length; + const missingCount = Object.values(status).filter((s) => s === "missing").length; + const totalCount = filledCount + missingCount; + + return { + success: true, + message: `${configFileName} has ${totalCount} variable(s): ${filledCount} filled, ${missingCount} with placeholder`, + status, + }; +} + +function handleError( + error: any, + requestId: string, + eventHandler: CopilotEventHandler +): ConfigCollectorResult { + const message = (error && typeof error.message === "string" && error.message) || String(error) || "Unknown error"; + const code = (error && error.code) || "UNKNOWN_ERROR"; + + console.error("[ConfigCollector] Error:", error); + + eventHandler({ + type: "configuration_collection_event", + requestId, + stage: "error", + message: `Error: ${message}`, + error: { + message, + code, + }, + }); + + return { + success: false, + message: `Failed to manage configuration: ${message}`, + error: message, + errorCode: code, + }; +} diff --git a/workspaces/ballerina/ballerina-extension/src/features/ai/agent/tools/connector-generator.ts b/workspaces/ballerina/ballerina-extension/src/features/ai/agent/tools/connector-generator.ts index c87a4f64a11..87c5721d891 100644 --- a/workspaces/ballerina/ballerina-extension/src/features/ai/agent/tools/connector-generator.ts +++ b/workspaces/ballerina/ballerina-extension/src/features/ai/agent/tools/connector-generator.ts @@ -32,9 +32,10 @@ import { import { CopilotEventHandler } from "../../utils/events"; import { langClient } from "../../activator"; import { applyTextEdits } from "../utils"; -import { LIBRARY_PROVIDER_TOOL } from "../../utils/libs/libraries"; +import { LIBRARY_GET_TOOL } from "./library-get"; import { approvalManager } from '../../state/ApprovalManager'; import { sendAiSchemaDidOpen } from "../../utils/project/ls-schema-notifications"; +import { LIBRARY_SEARCH_TOOL } from "./library-search"; export const CONNECTOR_GENERATOR_TOOL = "ConnectorGeneratorTool"; @@ -43,14 +44,19 @@ const SpecFetcherInputSchema = z.object({ serviceDescription: z.string().optional().describe("Optional description of what the service is for"), }); + + export function createConnectorGeneratorTool(eventHandler: CopilotEventHandler, tempProjectPath: string, projectName?: string, modifiedFiles?: string[]) { return tool({ + // TODO: Since LIBRARY_SEARCH_TOOL and LIBRARY_GET_TOOL workflow changed, verify this tool's use case ordering aligns with agent behavior description: ` -Generates a connector for an external service by deriving the service contract from user-provided specifications. Use this tool only when the service contract is unclear or missing, and the target service is not a well-established platform with an existing SDK or connector +Generates a connector for an external service by deriving the service contract from user-provided OpenAPI specifications. Use this tool when: -1. The target service is custom, internal, or niche, and unlikely to be covered by existing libraries. -2. When the ${LIBRARY_PROVIDER_TOOL} does not have a connector for the target service. +1. Target service is custom, internal, or niche +2. User request is ambiguous and needs a SaaS connector +3. User explicitly requests to create a SaaS connector +4. After searching with ${LIBRARY_SEARCH_TOOL}, no suitable connector is found The tool will: 1. Request OpenAPI spec from user (supports JSON and YAML formats) diff --git a/workspaces/ballerina/ballerina-extension/src/features/ai/agent/tools/healthcare-library.ts b/workspaces/ballerina/ballerina-extension/src/features/ai/agent/tools/healthcare-library.ts index 1f6047caee3..61cb3c7aa1b 100644 --- a/workspaces/ballerina/ballerina-extension/src/features/ai/agent/tools/healthcare-library.ts +++ b/workspaces/ballerina/ballerina-extension/src/features/ai/agent/tools/healthcare-library.ts @@ -15,7 +15,8 @@ // under the License. import { generateObject, ModelMessage, tool } from "ai"; -import { GenerationType, getAllLibraries, LIBRARY_PROVIDER_TOOL } from "../../utils/libs/libraries"; +import { GenerationType, getAllLibraries } from "../../utils/libs/libraries"; +import { LIBRARY_GET_TOOL } from "./library-get"; import { jsonSchema } from "ai"; import { Library } from "../../utils/libs/library-types"; import { selectRequiredFunctions } from "../../utils/libs/function-registry"; @@ -95,14 +96,13 @@ export async function HealthcareLibraryProviderTool( //TODO: Improve this description export function getHealthcareLibraryProviderTool( - _libraryDescriptions: string, eventHandler: CopilotEventHandler ) { return tool({ description: `Fetches detailed information about healthcare-specific Ballerina libraries along with their API documentation, including services, clients, functions, and filtered type definitions. ** NOTE: -1. This Tool only has knowledge on healthcare libraries, you want general libraries, use ${LIBRARY_PROVIDER_TOOL} to retrieve those. +1. This Tool only has knowledge on healthcare libraries, you want general libraries, use ${LIBRARY_GET_TOOL} to retrieve those. This tool is specifically designed for healthcare integration use cases (FHIR, HL7v2, etc.) and provides: 1. **Automatically includes mandatory healthcare libraries** (FHIR R4, HL7v2 commons, etc.) even if not explicitly requested @@ -163,8 +163,8 @@ export async function getRelevantLibrariesAndFunctions( return relevantTrimmedFuncs; } -export async function getSelectedLibraries(prompt: string, generationType: GenerationType): Promise { - const allLibraries = await getAllLibraries(generationType); +export async function getSelectedLibraries(prompt: string, libraryType: GenerationType): Promise { + const allLibraries = await getAllLibraries(libraryType); if (allLibraries.length === 0) { return []; } diff --git a/workspaces/ballerina/ballerina-extension/src/features/ai/agent/tools/library-provider.ts b/workspaces/ballerina/ballerina-extension/src/features/ai/agent/tools/library-get.ts similarity index 63% rename from workspaces/ballerina/ballerina-extension/src/features/ai/agent/tools/library-provider.ts rename to workspaces/ballerina/ballerina-extension/src/features/ai/agent/tools/library-get.ts index 49b85d1da8e..ad80cc2a92d 100644 --- a/workspaces/ballerina/ballerina-extension/src/features/ai/agent/tools/library-provider.ts +++ b/workspaces/ballerina/ballerina-extension/src/features/ai/agent/tools/library-get.ts @@ -1,4 +1,4 @@ -// Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com/) All Rights Reserved. +// Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com/) All Rights Reserved. // WSO2 LLC. licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except @@ -20,16 +20,18 @@ import { jsonSchema } from "ai"; import { Library } from "../../utils/libs/library-types"; import { selectRequiredFunctions } from "../../utils/libs/function-registry"; import { CopilotEventHandler } from "../../utils/events"; -import { LIBRARY_PROVIDER_TOOL } from "../../utils/libs/libraries"; + +export const LIBRARY_GET_TOOL = "LibraryGetTool"; /** - * Emits tool_result event for library provider with filtering + * Emits tool_result event for library get with filtering */ function emitLibraryToolResult( eventHandler: CopilotEventHandler, toolName: string, libraries: Library[], - requestedLibraryNames: string[] + requestedLibraryNames: string[], + toolCallId: string ): void { const libraryNames = libraries.map(lib => lib.name); const filteredNames = libraryNames.filter(name => requestedLibraryNames.includes(name)); @@ -37,11 +39,12 @@ function emitLibraryToolResult( eventHandler({ type: "tool_result", toolName, - toolOutput: filteredNames + toolOutput: filteredNames, + toolCallId }); } -const LibraryProviderToolSchema = jsonSchema<{ +const LibraryGetToolSchema = jsonSchema<{ libraryNames: string[]; userPrompt: string; }>({ @@ -60,46 +63,48 @@ const LibraryProviderToolSchema = jsonSchema<{ required: ["libraryNames", "userPrompt"], }); -export async function LibraryProviderTool( +export async function LibraryGetTool( params: { libraryNames: string[]; userPrompt: string }, generationType: GenerationType, - eventHandler: CopilotEventHandler + eventHandler: CopilotEventHandler, + toolCallId: string ): Promise { try { - // Emit tool_call event + // Emit tool_call event with ID from AI SDK eventHandler({ type: "tool_call", - toolName: LIBRARY_PROVIDER_TOOL, + toolName: LIBRARY_GET_TOOL, + toolCallId }); const startTime = Date.now(); const libraries = await selectRequiredFunctions(params.userPrompt, params.libraryNames, generationType); console.log( - `[LibraryProviderTool] Fetched ${libraries.length} libraries: ${libraries + `[LibraryGetTool] Fetched ${libraries.length} libraries: ${libraries .map((lib) => lib.name) .join(", ")}, took ${(Date.now() - startTime) / 1000}s` ); - // Emit tool_result event with filtered library names - emitLibraryToolResult(eventHandler, LIBRARY_PROVIDER_TOOL, libraries, params.libraryNames); + // Emit tool_result event with filtered library names and ID + emitLibraryToolResult(eventHandler, LIBRARY_GET_TOOL, libraries, params.libraryNames, toolCallId); return libraries; } catch (error) { - console.error(`[LibraryProviderTool] Error fetching libraries: ${error}`); + console.error(`[LibraryGetTool] Error fetching libraries: ${error}`); - // Emit error result + // Emit error result with same ID eventHandler({ type: "tool_result", - toolName: LIBRARY_PROVIDER_TOOL, - toolOutput: [] + toolName: LIBRARY_GET_TOOL, + toolOutput: [], + toolCallId }); return []; } } -export function getLibraryProviderTool( - libraryDescriptions: string, +export function getLibraryGetTool( generationType: GenerationType, eventHandler: CopilotEventHandler ) { @@ -107,34 +112,33 @@ export function getLibraryProviderTool( description: `Fetches detailed information about Ballerina libraries along with their API documentation, including services, clients, functions, and types. This tool analyzes a user query and returns **only the relevant** services, clients, functions, and types from the selected Ballerina libraries based on the provided user prompt. -Available libraries: - -${libraryDescriptions} - - Before calling this tool: -- Review all library names and their descriptions. -- Analyze the user query provided in the user message to identify the relevant Ballerina libraries which can be utilized to fulfill the query. -- Select the minimal set of libraries that can fulfill the query based on their descriptions. +- First use LibrarySearchTool to discover available libraries based on keywords +- Review the library names and descriptions returned from the search +- Analyze the user query to identify the relevant Ballerina libraries which can be utilized to fulfill the query +- Select the minimal set of libraries that can fulfill the query based on their descriptions # Example **Query**: Write an integration to read GitHub issues, summarize them, and post the summary to a Slack channel. -**Tool Call**: Call with libraryNames: ["ballerinax/github", "ballerinax/slack", "ballerinax/azure.openai.chat"] - +**Step 1**: Call LibrarySearchTool with keywords: ["GitHub", "Slack", "OpenAI"] +**Step 2**: Call this tool with libraryNames: ["ballerinax/github", "ballerinax/slack", "ballerinax/azure.openai.chat"] Tool Response: Tool responds with the following information about the requested libraries: name, description, type definitions (records, objects, enums, type aliases), clients (if any), functions and services (if any). `, - inputSchema: LibraryProviderToolSchema, - execute: async (input: { libraryNames: string[]; userPrompt: string }) => { + inputSchema: LibraryGetToolSchema, + execute: async (input: { libraryNames: string[]; userPrompt: string }, context?: { toolCallId?: string }) => { + // Extract toolCallId from AI SDK context + const toolCallId = context?.toolCallId || `fallback-${Date.now()}`; + console.log( - `[LibraryProviderTool] Called with ${input.libraryNames.length} libraries: ${input.libraryNames.join( + `[LibraryGetTool] Called with ${input.libraryNames.length} libraries: ${input.libraryNames.join( ", " - )} and prompt: ${input.userPrompt}` + )} and prompt: ${input.userPrompt} [toolCallId: ${toolCallId}]` ); - return await LibraryProviderTool(input, generationType, eventHandler); + return await LibraryGetTool(input, generationType, eventHandler, toolCallId); }, }); } diff --git a/workspaces/ballerina/ballerina-extension/src/features/ai/agent/tools/library-search.ts b/workspaces/ballerina/ballerina-extension/src/features/ai/agent/tools/library-search.ts new file mode 100644 index 00000000000..e47a3b00672 --- /dev/null +++ b/workspaces/ballerina/ballerina-extension/src/features/ai/agent/tools/library-search.ts @@ -0,0 +1,210 @@ +// Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com/) All Rights Reserved. + +// WSO2 LLC. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +import { tool, jsonSchema } from "ai"; +import { CopilotEventHandler } from "../../utils/events"; +import { langClient } from "../../activator"; +import { CopilotSearchLibrariesBySearchRequest, CopilotSearchLibrariesBySearchResponse, MinifiedLibrary } from "@wso2/ballerina-core"; + +export const LIBRARY_SEARCH_TOOL = "LibrarySearchTool"; + +// Maximum number of keywords allowed for library search +const MAX_SEARCH_KEYWORDS = 10; + +const LibrarySearchToolSchema = jsonSchema<{ + keywords: string[]; + searchDescription?: string; +}>({ + type: "object", + properties: { + keywords: { + type: "array", + items: { type: "string" }, + description: `Array of search keywords to find relevant Ballerina libraries. Keywords are weighted by order - first keyword has highest weight, subsequent keywords have decreasing weight. Maximum ${MAX_SEARCH_KEYWORDS} keywords allowed. Examples: ["GitHub", "API", "integration"], ["Stripe", "payment", "gateway"], ["HTTP", "REST", "service"]`, + minItems: 1, + maxItems: MAX_SEARCH_KEYWORDS, + }, + searchDescription: { + type: "string", + description: "Optional user-friendly description of what libraries are being searched for (e.g., 'payment processing libraries', 'GitHub API connectors', 'email sending services'). This will be shown to the user during the search to provide context about what is being looked for.", + }, + }, + required: ["keywords"], +}); + +function emitLibrarySearchResult( + eventHandler: CopilotEventHandler, + toolName: string, + libraries: MinifiedLibrary[], + toolCallId: string, + searchDescription?: string +): void { + const libraryNames = libraries.map(lib => lib.name); + eventHandler({ + type: "tool_result", + toolName, + toolOutput: { + libraries: libraryNames, + searchDescription + }, + toolCallId + }); +} + +export async function LibrarySearchTool( + params: { keywords: string[]; searchDescription?: string }, + eventHandler: CopilotEventHandler, + toolCallId: string +): Promise { + try { + // Emit tool_call event with ID and description + eventHandler({ + type: "tool_call", + toolName: LIBRARY_SEARCH_TOOL, + toolInput: { + keywords: params.keywords, + searchDescription: params.searchDescription + }, + toolCallId + }); + + const startTime = Date.now(); + + // Validate keyword count + const keywords = params.keywords.slice(0, MAX_SEARCH_KEYWORDS); + if (keywords.length === 0) { + console.warn(`[LibrarySearchTool] No keywords provided`); + return { libraries: [] }; + } + + const request: CopilotSearchLibrariesBySearchRequest = { + keywords + }; + + const response: CopilotSearchLibrariesBySearchResponse = + await langClient.getCopilotLibrariesBySearch(request); + + const libraryNames = response.libraries.map(lib => lib.name); + console.log( + `[LibrarySearchTool] Searched with keywords: [${keywords.join(", ")}], found ${response.libraries.length} libraries: ${libraryNames.join( + ", " + )}, took ${(Date.now() - startTime) / 1000}s` + ); + + // Emit tool_result event with same ID and description + emitLibrarySearchResult(eventHandler, LIBRARY_SEARCH_TOOL, response.libraries, toolCallId, params.searchDescription); + + return { libraries: response.libraries }; + } catch (error) { + console.error(`[LibrarySearchTool] Error searching libraries: ${error}`); + + // Emit error result with same ID and description + eventHandler({ + type: "tool_result", + toolName: LIBRARY_SEARCH_TOOL, + toolOutput: { + libraries: [], + searchDescription: params.searchDescription + }, + toolCallId + }); + + return { libraries: [] }; + } +} + +export function getLibrarySearchTool( + eventHandler: CopilotEventHandler +) { + return tool({ + description: `Searches for Ballerina libraries from Ballerina Central based on weighted keywords. + +**Purpose:** +This tool discovers relevant Ballerina libraries using keyword-based search. It searches against library names, descriptions, and function names. Keywords are weighted by order - the first keyword has the highest weight, with decreasing weight for subsequent keywords. + +**Scope - ALL Ballerina Libraries:** +- **ballerina/*** - Standard/core libraries (e.g., ballerina/http, ballerina/io, ballerina/sql) +- **ballerinax/*** - Extended/connector packages (e.g., ballerinax/stripe, ballerinax/aws.s3, ballerinax/github) +- **xlibb/*** - C library bindings (e.g., xlibb/docreader) +- Other organization packages available in Ballerina Central + +**Keyword Guidelines:** +- Provide 1-${MAX_SEARCH_KEYWORDS} keywords ordered by importance +- First keyword = most important (highest weight in search) +- Subsequent keywords = less important (decreasing weight) +- Use specific terms (e.g., "Stripe", "GitHub", "PostgreSQL") before generic ones (e.g., "payment", "API", "database") + +**When to use this tool:** +- To discover which libraries are available for a specific use case or integration +- Before calling LibraryProviderTool to retrieve full library details +- When the user query mentions integrations, services, connectors, or specific functionality +- Whenever you need to find relevant libraries but don't know the exact library names + +**Important - Two-Step Workflow:** +1. First, call THIS tool (LibrarySearchTool) with weighted keywords to discover relevant libraries +2. Review the returned library names and descriptions +3. Select the most appropriate libraries (typically 1-5 libraries) +4. Then, call LibraryProviderTool with the selected library names to get detailed API documentation (functions, types, clients, services, etc.) + +**Example Workflows:** + +Example 1 - Stripe Integration: +User query: "I need to integrate with Stripe payment gateway" +Keywords: ["Stripe", "payment", "gateway"] // "Stripe" has highest weight +Call LibrarySearchTool with keywords: ["Stripe", "payment", "gateway"] +→ Returns: [ + { name: "ballerinax/stripe", description: "Connects to Stripe API for payment processing" } + ] +Then call LibraryProviderTool with libraryNames: ["ballerinax/stripe"] + +Example 2 - GitHub API: +User query: "Create a GitHub integration to list issues" +Keywords: ["GitHub", "API", "issues"] // "GitHub" has highest weight +Call LibrarySearchTool with keywords: ["GitHub", "API", "issues"] +→ Returns: [ + { name: "ballerinax/github", description: "GitHub API connector for repository management" } + ] +Then call LibraryProviderTool with libraryNames: ["ballerinax/github"] + +Example 3 - HTTP Service: +User query: "Create a REST API" +Keywords: ["HTTP", "REST", "API"] // "HTTP" has highest weight +Call LibrarySearchTool with keywords: ["HTTP", "REST", "API"] +→ Returns: [ + { name: "ballerina/http", description: "HTTP client and server implementation" } + ] +Then call LibraryProviderTool with libraryNames: ["ballerina/http"] + +**Tool Response Format:** +Returns an array of library objects, each containing name and description: +[ + { name: "ballerinax/stripe", description: "Stripe payment connector for processing payments..." }, + { name: "ballerinax/aws.s3", description: "AWS S3 connector for object storage operations..." }, + { name: "ballerina/http", description: "HTTP client and server implementation..." } +] +`, + inputSchema: LibrarySearchToolSchema, + execute: async (input: { keywords: string[]; searchDescription?: string }, context?: { toolCallId?: string }) => { + // Extract toolCallId from AI SDK context + const toolCallId = context?.toolCallId || `fallback-${Date.now()}`; + + console.log( + `[LibrarySearchTool] Called with keywords: [${input.keywords.join(", ")}] [toolCallId: ${toolCallId}] [description: ${input.searchDescription || 'none'}]` + ); + return await LibrarySearchTool(input, eventHandler, toolCallId); + }, + }); +} diff --git a/workspaces/ballerina/ballerina-extension/src/features/ai/state/ApprovalManager.ts b/workspaces/ballerina/ballerina-extension/src/features/ai/state/ApprovalManager.ts index c61dcf4d2f5..aadec4204e8 100644 --- a/workspaces/ballerina/ballerina-extension/src/features/ai/state/ApprovalManager.ts +++ b/workspaces/ballerina/ballerina-extension/src/features/ai/state/ApprovalManager.ts @@ -16,8 +16,11 @@ * under the License. */ -import { Task } from '@wso2/ballerina-core/lib/state-machine-types'; -import { CopilotEventHandler } from '../utils/events'; +import { Task, MACHINE_VIEW } from "@wso2/ballerina-core/lib/state-machine-types"; +import { CopilotEventHandler } from "../utils/events"; +import { ConfigVariable } from "../../../utils/toml-utils"; +import { StateMachine } from "../../../stateMachine"; +import { approvalViewManager } from './ApprovalViewManager'; /** * Plan approval response @@ -45,6 +48,15 @@ export interface ConnectorSpecResponse { comment?: string; } +/** + * Configuration response containing actual values (converted to metadata before exposing to agent) + */ +export interface ConfigurationResponse { + provided: boolean; + configValues?: Record; + comment?: string; +} + /** * Generic promise resolver for approval requests */ @@ -67,6 +79,7 @@ export class ApprovalManager { private planApprovals = new Map>(); private taskApprovals = new Map>(); private connectorSpecs = new Map>(); + private configurationRequests = new Map>(); // Default timeout for abandoned approvals (30 minutes) private readonly DEFAULT_TIMEOUT_MS = 30 * 60 * 1000; @@ -98,7 +111,7 @@ export class ApprovalManager { requestPlanApproval( requestId: string, tasks: Task[], - eventHandler: CopilotEventHandler + eventHandler: CopilotEventHandler, ): Promise { console.log(`[ApprovalManager] Requesting plan approval: ${requestId}`); @@ -108,7 +121,7 @@ export class ApprovalManager { requestId: requestId, approvalType: "plan", tasks: tasks, - message: "Please review the implementation plan" + message: "Please review the implementation plan", }); // Create promise that will be resolved by resolvePlanApproval() @@ -168,7 +181,7 @@ export class ApprovalManager { requestId: string, taskDescription: string, tasks: Task[], - eventHandler: CopilotEventHandler + eventHandler: CopilotEventHandler, ): Promise { console.log(`[ApprovalManager] Requesting task approval: ${requestId}`); @@ -179,7 +192,7 @@ export class ApprovalManager { approvalType: "completion", tasks: tasks, taskDescription: taskDescription, - message: `Please verify the completed work for: ${taskDescription}` + message: `Please verify the completed work for: ${taskDescription}`, }); // Create promise that will be resolved by resolveTaskApproval() @@ -205,7 +218,7 @@ export class ApprovalManager { requestId: string, approved: boolean, comment?: string, - approvedTaskDescription?: string + approvedTaskDescription?: string, ): void { const resolver = this.taskApprovals.get(requestId); if (!resolver) { @@ -239,10 +252,7 @@ export class ApprovalManager { * @param eventHandler - Event handler to emit spec request * @returns Promise that resolves when user provides/cancels spec */ - requestConnectorSpec( - requestId: string, - eventHandler: CopilotEventHandler - ): Promise { + requestConnectorSpec(requestId: string, eventHandler: CopilotEventHandler): Promise { console.log(`[ApprovalManager] Requesting connector spec: ${requestId}`); // Emit event to frontend @@ -250,7 +260,7 @@ export class ApprovalManager { type: "connector_generation_notification", requestId: requestId, stage: "requesting_input", - message: "Please provide the OpenAPI specification" + message: "Please provide the OpenAPI specification", }); // Create promise that will be resolved by resolveConnectorSpec() @@ -272,12 +282,7 @@ export class ApprovalManager { * @param spec - The OpenAPI spec (if provided) * @param comment - Optional comment from user */ - resolveConnectorSpec( - requestId: string, - provided: boolean, - spec?: any, - comment?: string - ): void { + resolveConnectorSpec(requestId: string, provided: boolean, spec?: any, comment?: string): void { const resolver = this.connectorSpecs.get(requestId); if (!resolver) { console.warn(`[ApprovalManager] No pending connector spec request for: ${requestId}`); @@ -298,6 +303,107 @@ export class ApprovalManager { this.connectorSpecs.delete(requestId); } + // ============================================ + // Configuration Collection + // ============================================ + + /** + * Request configuration values from user + * Returns actual configuration values to tool (tool converts to metadata for agent) + * Opens a popup in the BI Visualizer for user input + * + * @param isTestConfig - Flag to indicate this is for test configuration (affects UI messaging) + * @param message - Custom message from configuration collector (includes smart analysis for test mode) + */ + requestConfiguration( + requestId: string, + variables: ConfigVariable[], + existingValues: Record, + eventHandler: CopilotEventHandler, + isTestConfig?: boolean, + message?: string + ): Promise { + console.log(`[ApprovalManager] Requesting ${isTestConfig ? 'test ' : ''}configuration: ${requestId}`); + + // Use provided message or generate default + const displayMessage = message || `Please provide ${variables.length} configuration value(s)`; + + // Emit collecting stage to AI Panel + eventHandler({ + type: "configuration_collection_event", + requestId, + stage: "collecting", + variables, + existingValues, + message: displayMessage, + isTestConfig, + }); + + const { projectPath } = StateMachine.context(); + + // Open configuration collector view + approvalViewManager.openApprovalViewPopup( + requestId, + 'configuration', + { + view: MACHINE_VIEW.ConfigurationCollector, + projectPath, + agentMetadata: { + configurationCollector: { + requestId, + variables, + existingValues, + message: displayMessage, + isTestConfig, + }, + }, + } + ); + + // Create promise that will be resolved by resolveConfiguration() + return new Promise((resolve, reject) => { + const timeoutId = setTimeout(() => { + this.configurationRequests.delete(requestId); + reject(new Error(`Configuration request timeout for request ${requestId}`)); + }, this.DEFAULT_TIMEOUT_MS); + + this.configurationRequests.set(requestId, { resolve, reject, timeoutId }); + }); + } + + /** + * Resolve configuration request (called by RPC method when user responds) + * Contains actual configuration values - tool will convert to metadata for agent + */ + resolveConfiguration( + requestId: string, + provided: boolean, + configValues?: Record, + comment?: string, + ): void { + const resolver = this.configurationRequests.get(requestId); + if (!resolver) { + console.warn(`[ApprovalManager] No pending configuration request for: ${requestId}`); + return; + } + + console.log(`[ApprovalManager] Resolving configuration request: ${requestId}, provided: ${provided}`); + + // Clear timeout + if (resolver.timeoutId) { + clearTimeout(resolver.timeoutId); + } + + // Resolve promise with actual configuration values (tool will sanitize before returning to agent) + resolver.resolve({ provided, configValues, comment }); + + // Cleanup + this.configurationRequests.delete(requestId); + + // Cleanup view and clear state machine metadata + approvalViewManager.cleanupView(requestId, true); + } + // ============================================ // Cleanup // ============================================ @@ -310,6 +416,9 @@ export class ApprovalManager { cancelAllPending(reason: string): void { console.log(`[ApprovalManager] Cancelling all pending approvals: ${reason}`); + // Cleanup all approval views + approvalViewManager.cleanupAllViews(); + const error = new Error(reason); // Cancel plan approvals @@ -338,16 +447,26 @@ export class ApprovalManager { resolver.reject(error); } this.connectorSpecs.clear(); + + // Cancel configuration requests + for (const [requestId, resolver] of this.configurationRequests.entries()) { + if (resolver.timeoutId) { + clearTimeout(resolver.timeoutId); + } + resolver.reject(error); + } + this.configurationRequests.clear(); } /** * Get count of pending approvals (useful for debugging) */ - getPendingCount(): { plans: number; tasks: number; connectorSpecs: number } { + getPendingCount(): { plans: number; tasks: number; connectorSpecs: number; configurations: number } { return { plans: this.planApprovals.size, tasks: this.taskApprovals.size, - connectorSpecs: this.connectorSpecs.size + connectorSpecs: this.connectorSpecs.size, + configurations: this.configurationRequests.size, }; } } diff --git a/workspaces/ballerina/ballerina-extension/src/features/ai/state/ApprovalViewManager.ts b/workspaces/ballerina/ballerina-extension/src/features/ai/state/ApprovalViewManager.ts new file mode 100644 index 00000000000..f88f14010f5 --- /dev/null +++ b/workspaces/ballerina/ballerina-extension/src/features/ai/state/ApprovalViewManager.ts @@ -0,0 +1,336 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { MACHINE_VIEW, EVENT_TYPE, VisualizerLocation, PopupVisualizerLocation, AgentMetadata } from '@wso2/ballerina-core'; +import { AiPanelWebview } from '../../../views/ai-panel/webview'; +import { VisualizerWebview } from '../../../views/visualizer/webview'; +import { openView as openMainView, StateMachine } from '../../../stateMachine'; +import { openPopupView, StateMachinePopup } from '../../../stateMachinePopup'; +import { notifyApprovalOverlayState } from '../../../RPCLayer'; + +export type ApprovalType = 'configuration' | 'task' | 'plan' | 'connector_spec'; + +interface OpenedApprovalView { + requestId: string; + viewType: 'popup' | 'main' | 'inline'; + approvalType: ApprovalType; + machineView: MACHINE_VIEW | null; + isAutoOpened: boolean; + hadExistingVisualizer: boolean; + timestamp: number; + isClosed?: boolean; + projectPath?: string; + agentMetadata?: AgentMetadata; +} + +/** + * Centralized manager for approval view lifecycles. + * Handles opening, tracking, and cleanup of approval views with chat overlay coordination. + */ +export class ApprovalViewManager { + private static instance: ApprovalViewManager; + private openedViews = new Map(); + + private constructor() {} + + static getInstance(): ApprovalViewManager { + if (!this.instance) { + this.instance = new ApprovalViewManager(); + } + return this.instance; + } + + /** + * Register an inline approval shown in chat without opening a separate view. + */ + registerInlineApproval( + requestId: string, + approvalType: ApprovalType + ): void { + console.log(`[ApprovalViewManager] Registering inline ${approvalType} approval:`, requestId); + + this.openedViews.set(requestId, { + requestId, + viewType: 'inline', + approvalType, + machineView: null, + isAutoOpened: true, + hadExistingVisualizer: false, + timestamp: Date.now() + }); + } + + /** + * Open an approval view as popup (or main view if no visualizer exists). + */ + openApprovalViewPopup( + requestId: string, + approvalType: ApprovalType, + viewLocation: VisualizerLocation | PopupVisualizerLocation + ): void { + const isAutoOpened = true; + const machineView = viewLocation.view!; + const projectPath = viewLocation.projectPath; + const agentMetadata = 'agentMetadata' in viewLocation ? viewLocation.agentMetadata : undefined; + + const { viewType, hadExistingVisualizer } = this._openApprovalViewPopup( + machineView, + projectPath, + agentMetadata + ); + + console.log(`[ApprovalViewManager] Opening ${approvalType} view:`, { + requestId, + machineView, + viewType, + isAutoOpened, + hadExistingVisualizer + }); + + this.openedViews.set(requestId, { + requestId, + viewType, + approvalType, + machineView, + isAutoOpened, + hadExistingVisualizer, + timestamp: Date.now(), + projectPath, + agentMetadata + }); + + const overlayMessage = this.getOverlayMessage(approvalType); + this.sendChatOverlayNotification(true, overlayMessage); + } + + private sendChatOverlayNotification(show: boolean, message?: string): void { + try { + notifyApprovalOverlayState({ show, message }); + console.log(`[ApprovalViewManager] Chat overlay ${show ? 'enabled' : 'disabled'}`, message ? `with message: ${message}` : ''); + } catch (error) { + console.error('[ApprovalViewManager] Failed to send chat overlay notification:', error); + } + } + + private getOverlayMessage(approvalType: ApprovalType): string { + const messages: Record = { + 'configuration': 'Waiting for configuration...', + 'task': 'Waiting for task approval...', + 'plan': 'Waiting for plan approval...', + 'connector_spec': 'Waiting for connector spec approval...' + }; + return messages[approvalType]; + } + + getView(requestId: string): OpenedApprovalView | undefined { + return this.openedViews.get(requestId); + } + + /** + * Check if there are any active approval views requiring chat overlay. + */ + hasActiveApprovals(): boolean { + return Array.from(this.openedViews.values()).some(view => !view.isClosed); + } + + /** + * Handle popup close by user. Preserves metadata for reopening and manages navigation. + */ + handlePopupClosed(requestId: string): void { + const view = this.openedViews.get(requestId); + if (!view) { return; } + + console.log(`[ApprovalViewManager] Popup closed by user:`, { + requestId, + hadExistingVisualizer: view.hadExistingVisualizer + }); + + view.isClosed = true; + + if (!this.hasActiveApprovals()) { + this.sendChatOverlayNotification(false); + } + + if (!view.hadExistingVisualizer) { + const ctx = StateMachine.context(); + openMainView(EVENT_TYPE.OPEN_VIEW, { + view: MACHINE_VIEW.PackageOverview, + projectPath: ctx.projectPath + }); + } + } + + cleanupView(requestId: string, clearMetadata: boolean = true): void { + const view = this.openedViews.get(requestId); + if (!view) { return; } + + console.log(`[ApprovalViewManager] Cleaning up ${view.approvalType} view:`, requestId); + + if (clearMetadata) { + this.clearViewMetadata(view); + } + + this.openedViews.delete(requestId); + this.sendChatOverlayNotification(false); + } + + cleanupAllViews(): void { + console.log('[ApprovalViewManager] Cleaning up all approval views'); + + const allViews = Array.from(this.openedViews.values()); + + for (const view of allViews) { + this.clearViewMetadata(view); + } + + this.openedViews.clear(); + this.sendChatOverlayNotification(false); + } + + private clearViewMetadata(view: OpenedApprovalView): void { + console.log(`[ApprovalViewManager] Clearing metadata for ${view.approvalType}:`, view.requestId); + + if (view.viewType === 'inline') { + return; + } + + if (view.viewType === 'popup') { + const ctx = StateMachinePopup.context(); + + if (ctx.view === view.machineView) { + StateMachinePopup.sendEvent(EVENT_TYPE.CLOSE_VIEW, { + view: null, + agentMetadata: undefined + }); + } + } else if (view.viewType === 'main') { + const ctx = StateMachine.context(); + + if (ctx.view === view.machineView) { + openMainView(EVENT_TYPE.OPEN_VIEW, { + view: MACHINE_VIEW.PackageOverview, + projectPath: ctx.projectPath + }); + } + } + } + + onVisualizerClosed(): void { + if (!this.hasActiveApprovals()) { + return; + } + + console.log('[ApprovalViewManager] VisualizerWebview closed, marking all views as closed'); + + for (const view of this.openedViews.values()) { + view.isClosed = true; + } + + this.sendChatOverlayNotification(false); + } + + getOpenViews(): OpenedApprovalView[] { + return Array.from(this.openedViews.values()); + } + + /** + * Opens approval view as popup if visualizer exists, otherwise as main view. + */ + private _openApprovalViewPopup( + machineView: MACHINE_VIEW, + projectPath: string, + agentMetadata?: AgentMetadata + ): { viewType: 'popup' | 'main', hadExistingVisualizer: boolean } { + const hadExistingVisualizer = !!VisualizerWebview.currentPanel; + const viewType: 'popup' | 'main' = hadExistingVisualizer ? 'popup' : 'main'; + + if (viewType === 'popup') { + openPopupView(EVENT_TYPE.OPEN_VIEW, { + view: machineView, + projectPath, + agentMetadata + }); + } else { + openMainView(EVENT_TYPE.OPEN_VIEW, { + view: machineView, + projectPath, + agentMetadata + }); + } + + return { viewType, hadExistingVisualizer }; + } + + /** + * Reopen a previously closed approval view. + */ + reopenApprovalViewPopup(requestId: string): void { + const view = this.openedViews.get(requestId); + + if (!view) { + console.error('[ApprovalViewManager] Cannot reopen - approval view not found:', requestId); + return; + } + + if (view.viewType === 'inline') { + console.log('[ApprovalViewManager] Inline approval - no view to reopen'); + return; + } + + if (!view.projectPath || !view.machineView) { + console.error('[ApprovalViewManager] Cannot reopen - missing required metadata:', requestId); + return; + } + + console.log(`[ApprovalViewManager] Reopening ${view.approvalType} view:`, { + requestId, + wasClosed: view.isClosed, + viewType: view.viewType + }); + + view.isClosed = false; + view.isAutoOpened = false; + + const overlayMessage = this.getOverlayMessage(view.approvalType); + this.sendChatOverlayNotification(true, overlayMessage); + + const { viewType, hadExistingVisualizer } = this._openApprovalViewPopup( + view.machineView, + view.projectPath, + view.agentMetadata + ); + view.viewType = viewType; + view.hadExistingVisualizer = hadExistingVisualizer; + } + + /** + * Open a view in main view (not as popup, no tracking). + * Only opens if AI panel is active. + */ + openView(machineView: MACHINE_VIEW): void { + if (!AiPanelWebview.currentPanel) { + console.log(`[ApprovalViewManager] Skipping ${machineView} open (AI panel closed)`); + return; + } + + console.log(`[ApprovalViewManager] Opening ${machineView} in main view`); + openMainView(EVENT_TYPE.OPEN_VIEW, { view: machineView }); + } +} + +export const approvalViewManager = ApprovalViewManager.getInstance(); diff --git a/workspaces/ballerina/ballerina-extension/src/features/ai/utils/ai-utils.ts b/workspaces/ballerina/ballerina-extension/src/features/ai/utils/ai-utils.ts index 9a1c1c0aa18..83f59b21e9f 100644 --- a/workspaces/ballerina/ballerina-extension/src/features/ai/utils/ai-utils.ts +++ b/workspaces/ballerina/ballerina-extension/src/features/ai/utils/ai-utils.ts @@ -233,20 +233,22 @@ export function sendIntermidateStateNotification(intermediaryState: Documentatio sendAIPanelNotification(msg); } -export function sendToolCallNotification(toolName: string, toolInput?: any): void { +export function sendToolCallNotification(toolName: string, toolInput?: any, toolCallId?: string): void { const msg: ToolCall = { type: "tool_call", toolName: toolName, toolInput: toolInput, + toolCallId: toolCallId, }; sendAIPanelNotification(msg); } -export function sendToolResultNotification(toolName: string, toolOutput?: any): void { +export function sendToolResultNotification(toolName: string, toolOutput?: any, toolCallId?: string): void { const msg: ToolResult = { type: "tool_result", toolName: toolName, toolOutput: toolOutput, + toolCallId: toolCallId, }; sendAIPanelNotification(msg); } @@ -292,6 +294,10 @@ export function sendConnectorGenerationNotification(event: ChatNotify & { type: sendAIPanelNotification(event); } +export function sendConfigurationCollectionNotification(event: ChatNotify & { type: "configuration_collection_event" }): void { + sendAIPanelNotification(event); +} + function sendAIPanelNotification(msg: ChatNotify): void { RPCLayer._messenger.sendNotification(onChatNotify, { type: "webview", webviewType: AiPanelWebview.viewType }, msg); } diff --git a/workspaces/ballerina/ballerina-extension/src/features/ai/utils/events.ts b/workspaces/ballerina/ballerina-extension/src/features/ai/utils/events.ts index f4893ac6c28..e2d68b3c377 100644 --- a/workspaces/ballerina/ballerina-extension/src/features/ai/utils/events.ts +++ b/workspaces/ballerina/ballerina-extension/src/features/ai/utils/events.ts @@ -30,6 +30,7 @@ import { sendAbortNotification, sendSaveChatNotification, sendConnectorGenerationNotification, + sendConfigurationCollectionNotification, sendReviewActionsNotification, } from "./ai-utils"; @@ -75,10 +76,10 @@ export function createWebviewEventHandler(command: Command): CopilotEventHandler sendMessagesNotification(event.messages); break; case "tool_call": - sendToolCallNotification(event.toolName, event.toolInput); + sendToolCallNotification(event.toolName, event.toolInput, event.toolCallId); break; case "tool_result": - sendToolResultNotification(event.toolName, event.toolOutput); + sendToolResultNotification(event.toolName, event.toolOutput, event.toolCallId); break; case "task_approval_request": console.log("[Event Handler] Task approval request received:", event); @@ -103,6 +104,9 @@ export function createWebviewEventHandler(command: Command): CopilotEventHandler case "connector_generation_notification": sendConnectorGenerationNotification(event); break; + case "configuration_collection_event": + sendConfigurationCollectionNotification(event); + break; default: console.warn(`Unhandled event type: ${event}`); break; diff --git a/workspaces/ballerina/ballerina-extension/src/features/ai/utils/feedback.ts b/workspaces/ballerina/ballerina-extension/src/features/ai/utils/feedback.ts new file mode 100644 index 00000000000..3f4bfe6ce4b --- /dev/null +++ b/workspaces/ballerina/ballerina-extension/src/features/ai/utils/feedback.ts @@ -0,0 +1,52 @@ +// Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com/) All Rights Reserved. + +// WSO2 LLC. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +import { SubmitFeedbackRequest } from "@wso2/ballerina-core"; +import { extension } from "../../../BalExtensionContext"; +import { StateMachine } from "../../../stateMachine"; +import { sendTelemetryEvent, TM_EVENT_BALLERINA_AI_GENERATION_FEEDBACK, CMP_BALLERINA_AI_GENERATION } from "../../telemetry"; +import { getHashedProjectId } from "../../telemetry/common/project-id"; + +/** + * Submits user feedback for AI-generated content to the backend. + * + * @param content - The feedback request payload + * @returns True if feedback was submitted successfully, false otherwise + */ +export async function submitFeedback(content: SubmitFeedbackRequest): Promise { + try { + const projectPath = StateMachine.context()?.projectPath || ''; + const projectId = await getHashedProjectId(projectPath); + + sendTelemetryEvent( + extension.ballerinaExtInstance, + TM_EVENT_BALLERINA_AI_GENERATION_FEEDBACK, + CMP_BALLERINA_AI_GENERATION, + { + 'project.id': projectId, + 'feedback.type': content.positive ? 'positive' : 'negative', + 'feedback.message': content.feedbackText || '', + 'feedback.has_text': content.feedbackText ? 'true' : 'false', + 'feedback.text_length': content.feedbackText?.length.toString() || '0', + 'chat.has_thread': content.messages.length > 0 ? 'true' : 'false', + 'chat.thread': JSON.stringify(content.messages), + } + ); + } catch (error) { + console.error("Error submitting feedback:", error); + return false; + } +} diff --git a/workspaces/ballerina/ballerina-extension/src/features/ai/utils/generation-response.ts b/workspaces/ballerina/ballerina-extension/src/features/ai/utils/generation-response.ts new file mode 100644 index 00000000000..9db4adb1a2f --- /dev/null +++ b/workspaces/ballerina/ballerina-extension/src/features/ai/utils/generation-response.ts @@ -0,0 +1,65 @@ +// Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com/) All Rights Reserved. + +// WSO2 LLC. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +import { extension } from "../../../BalExtensionContext"; +import { StateMachine } from "../../../stateMachine"; +import { + sendTelemetryEvent, + TM_EVENT_BALLERINA_AI_GENERATION_KEPT, + TM_EVENT_BALLERINA_AI_GENERATION_DISCARD, + CMP_BALLERINA_AI_GENERATION +} from "../../telemetry"; +import { getHashedProjectId } from "../../telemetry/common/project-id"; + +/** + * Sends a telemetry event when the user keeps an AI-generated response. + * + * @param messageId - The message identifier for the kept generation + */ +export async function sendGenerationKeptTelemetry(messageId: string): Promise { + const projectPath = StateMachine.context()?.projectPath || ''; + const projectId = await getHashedProjectId(projectPath); + + sendTelemetryEvent( + extension.ballerinaExtInstance, + TM_EVENT_BALLERINA_AI_GENERATION_KEPT, + CMP_BALLERINA_AI_GENERATION, + { + 'message.id': messageId, + 'project.id': projectId, + } + ); +} + +/** + * Sends a telemetry event when the user discard an AI-generated response. + * + * @param messageId - The message identifier for the discarded generation + */ +export async function sendGenerationDiscardTelemetry(messageId: string): Promise { + const projectPath = StateMachine.context()?.projectPath || ''; + const projectId = await getHashedProjectId(projectPath); + + sendTelemetryEvent( + extension.ballerinaExtInstance, + TM_EVENT_BALLERINA_AI_GENERATION_DISCARD, + CMP_BALLERINA_AI_GENERATION, + { + 'message.id': messageId, + 'project.id': projectId, + } + ); +} diff --git a/workspaces/ballerina/ballerina-extension/src/features/ai/utils/libs/function-registry.ts b/workspaces/ballerina/ballerina-extension/src/features/ai/utils/libs/function-registry.ts index ef6c86198d1..44fe02353fd 100644 --- a/workspaces/ballerina/ballerina-extension/src/features/ai/utils/libs/function-registry.ts +++ b/workspaces/ballerina/ballerina-extension/src/features/ai/utils/libs/function-registry.ts @@ -32,14 +32,13 @@ import { getAnthropicClient, ANTHROPIC_HAIKU } from "../ai-client"; import { GenerationType } from "./libraries"; // import { getRequiredTypesFromLibJson } from "../healthcare/healthcare"; import { langClient } from "../../activator"; -import { getGenerationMode } from "../ai-utils"; // Constants for type definitions const TYPE_RECORD = 'Record'; const TYPE_CONSTRUCTOR = 'Constructor'; export async function selectRequiredFunctions(prompt: string, selectedLibNames: string[], generationType: GenerationType): Promise { - const selectedLibs: Library[] = await getMaximizedSelectedLibs(selectedLibNames, generationType); + const selectedLibs: Library[] = await getMaximizedSelectedLibs(selectedLibNames); const functionsResponse: GetFunctionResponse[] = await getRequiredFunctions(selectedLibNames, prompt, selectedLibs, generationType); let typeLibraries: Library[] = []; if (generationType === GenerationType.HEALTHCARE_GENERATION) { @@ -201,9 +200,11 @@ async function getSuggestedFunctions( const getLibSystemPrompt = `You are an AI assistant tasked with filtering and removing unwanted functions and clients from a provided set of libraries and clients based on a user query. The provided libraries are a subset of the full requirements for the query. Your goal is to return ONLY the relevant libraries, clients, and functions from the provided context that match the user's needs. -Rules: -1. Use ONLY the libraries listed in Library_Context_JSON. -2. Do NOT create or infer new libraries or functions.`; +CRITICAL RULES: +1. Use ONLY items from Library_Context_JSON - do not create or infer new ones. +2. Your ONLY task is selection - include or exclude items, NEVER modify field values. +3. Copy all field values EXACTLY as provided - preserve every character including backslashes and special characters. +4. For resource functions: "accessor" and "paths" are SEPARATE fields - NEVER combine them.`; const getLibUserPrompt = `You will be provided with a list of libraries, clients, and their functions, and a user query. @@ -221,9 +222,16 @@ To process the user query and filter the libraries, clients, and functions, foll 2. Review the provided libraries, clients, and functions in Library_Context_JSON. 3. Select only the libraries, clients, and functions that directly match the query's needs. 4. Exclude any irrelevant libraries, clients, or functions. -5. If no relevant functions are found, return an empty array for the libraries. +5. If no relevant functions are found, return an empty array for libraries. 6. Organize the remaining relevant information. +CRITICAL - Field Preservation: +- For resource functions: "accessor" contains ONLY the HTTP method (e.g., "post", "get") - do NOT put path info in it. +- The "paths" field is separate - do NOT merge with accessor. +- Copy all values exactly - preserve backslashes, dots, and special characters. + +Return the filtered subset with IDENTICAL field values. + Now, based on the provided libraries, clients, and functions, and the user query, please filter and return the relevant information. `; @@ -329,12 +337,22 @@ function filteredNormalFunctions(functions?: RemoteFunction[], generationType?: })); } -export async function getMaximizedSelectedLibs(libNames: string[], generationType: GenerationType): Promise { +export async function getMaximizedSelectedLibs(libNames: string[]): Promise { const result = (await langClient.getCopilotFilteredLibraries({ - libNames: libNames, - mode: getGenerationMode(generationType), + libNames: libNames })) as { libraries: Library[] }; - return result.libraries as Library[]; + const normalizedLibraries: Library[] = result.libraries.map(lib => { + return { + name: lib.name, + description: lib.description, + clients: lib.clients ? lib.clients : [], + functions: lib.functions ? lib.functions : [], + typeDefs: lib.typeDefs ? lib.typeDefs : [], + services: lib.services ? lib.services : [], + }; + }); + + return normalizedLibraries; } export async function toMaximizedLibrariesFromLibJson( @@ -708,8 +726,7 @@ async function getExternalRecords( if (!library) { console.warn(`Library ${libName} is not found in the context. Fetching library details.`); const result = (await langClient.getCopilotFilteredLibraries({ - libNames: [libName], - mode: getGenerationMode(GenerationType.CODE_GENERATION), + libNames: [libName] })) as { libraries: Library[] }; if (result.libraries && result.libraries.length > 0) { library = result.libraries[0]; diff --git a/workspaces/ballerina/ballerina-extension/src/features/ai/utils/libs/libraries.ts b/workspaces/ballerina/ballerina-extension/src/features/ai/utils/libs/libraries.ts index ce9be84388b..f380a729e56 100644 --- a/workspaces/ballerina/ballerina-extension/src/features/ai/utils/libs/libraries.ts +++ b/workspaces/ballerina/ballerina-extension/src/features/ai/utils/libs/libraries.ts @@ -14,14 +14,11 @@ // specific language governing permissions and limitations // under the License. -import { MinifiedLibrary } from "@wso2/ballerina-core"; +import { LibraryMode, MinifiedLibrary } from "@wso2/ballerina-core"; import { langClient } from "../../activator"; import { getGenerationMode } from "../ai-utils"; - -export const LIBRARY_PROVIDER_TOOL = "LibraryProviderTool"; - // export async function getRelevantLibs(params: GenerateCodeParams): Promise { // // const prompt = getReadmeQuery(params); // const selectedLibs: string[] = await getSelectedLibraries(prompt); @@ -31,11 +28,24 @@ export const LIBRARY_PROVIDER_TOOL = "LibraryProviderTool"; export enum GenerationType { CODE_GENERATION = "CODE_GENERATION", HEALTHCARE_GENERATION = "HEALTHCARE_GENERATION", + ALL = "ALL" +} + +export function getLibraryModeFromGenerationType(generationType: GenerationType): LibraryMode { + switch (generationType) { + case GenerationType.CODE_GENERATION: + return "CORE"; + case GenerationType.HEALTHCARE_GENERATION: + return "HEALTHCARE"; + case GenerationType.ALL: + default: + return "ALL"; + } } export async function getAllLibraries(generationType: GenerationType): Promise { const result = (await langClient.getCopilotCompactLibraries({ - mode: getGenerationMode(generationType), + mode: getLibraryModeFromGenerationType(generationType), })) as { libraries: MinifiedLibrary[] }; return result.libraries as MinifiedLibrary[]; } diff --git a/workspaces/ballerina/ballerina-extension/src/features/project/cmds/cmd-runner.ts b/workspaces/ballerina/ballerina-extension/src/features/project/cmds/cmd-runner.ts index 4adf71b06ee..ec8018823d2 100644 --- a/workspaces/ballerina/ballerina-extension/src/features/project/cmds/cmd-runner.ts +++ b/workspaces/ballerina/ballerina-extension/src/features/project/cmds/cmd-runner.ts @@ -90,7 +90,8 @@ export enum MESSAGES { INVALID_JSON_RESPONSE = "JSON response is invalid.", INVALID_XML = "Invalid XML String", INVALID_XML_RESPONSE = "XML response is invalid.", - NO_PROJECT_FOUND = "No Ballerina project found." + NO_PROJECT_FOUND = "No Ballerina project found.", + NO_FILE_FOUND = "Unable to locate the file." } export const BAL_CONFIG_FILE = 'Config.toml'; diff --git a/workspaces/ballerina/ballerina-extension/src/features/telemetry/activator.ts b/workspaces/ballerina/ballerina-extension/src/features/telemetry/activator.ts index 6b989cf1e25..c6b18be8998 100644 --- a/workspaces/ballerina/ballerina-extension/src/features/telemetry/activator.ts +++ b/workspaces/ballerina/ballerina-extension/src/features/telemetry/activator.ts @@ -35,25 +35,28 @@ export function activate(ballerinaExtInstance: BallerinaExtension) { const langClient = ballerinaExtInstance.langClient; // Start listening telemtry events from language server - langClient.onNotification('telemetry/event', (event: LSTelemetryEvent) => { + langClient.onNotification('telemetry/event', async (event: LSTelemetryEvent) => { let props: { [key: string]: string; }; switch (event.type) { case TM_EVENT_TYPE_ERROR: const errorEvent: LSErrorTelemetryEvent = event; - props = getTelemetryProperties(ballerinaExtInstance, event.component, getMessageObject(TM_EVENT_TYPE_ERROR)); + props = await getTelemetryProperties(ballerinaExtInstance, event.component, + getMessageObject(TM_EVENT_TYPE_ERROR)); props["ballerina.langserver.error.description"] = errorEvent.message; props["ballerina.langserver.error.stacktrace"] = errorEvent.errorStackTrace; props["ballerina.langserver.error.message"] = errorEvent.errorMessage; - reporter.sendTelemetryEvent(TM_ERROR_LANG_SERVER, props); + // TODO: Enable once when the language server telemerty complete + // reporter.sendTelemetryEvent(TM_ERROR_LANG_SERVER, props); break; case TM_EVENT_TYPE_FEATURE_USAGE: const usageEvent: LSFeatureUsageTelemetryEvent = event; - props = getTelemetryProperties(ballerinaExtInstance, event.component, + props = await getTelemetryProperties(ballerinaExtInstance, event.component, getMessageObject(TM_EVENT_TYPE_FEATURE_USAGE)); props["ballerina.langserver.feature.name"] = usageEvent.featureName; props["ballerina.langserver.feature.class"] = usageEvent.featureClass; props["ballerina.langserver.feature.message"] = usageEvent.featureMessage; - reporter.sendTelemetryEvent(TM_FEATURE_USAGE_LANG_SERVER, props); + // TODO: Enable once when the language server telemerty complete + // reporter.sendTelemetryEvent(TM_FEATURE_USAGE_LANG_SERVER, props); break; default: // Do nothing diff --git a/workspaces/ballerina/ballerina-extension/src/features/telemetry/common/project-id.ts b/workspaces/ballerina/ballerina-extension/src/features/telemetry/common/project-id.ts new file mode 100644 index 00000000000..f228b7bae9b --- /dev/null +++ b/workspaces/ballerina/ballerina-extension/src/features/telemetry/common/project-id.ts @@ -0,0 +1,61 @@ +// Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com/) All Rights Reserved. + +// WSO2 LLC. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +import * as crypto from 'crypto'; +import * as fs from 'fs'; +import * as path from 'path'; +import { parseTomlToConfig } from '../../config-generator/utils'; +import { BALLERINA_TOML } from '../../../utils/project-utils'; + +const projectIdCache = new Map(); + +/** + * Generates a stable, anonymized project identifier by hashing + * the project path combined with the package name from Ballerina.toml. + * + * @param projectPath - Absolute path to the Ballerina project + * @returns SHA-256 hashed project ID, or empty string if projectPath is falsy + */ +export async function getHashedProjectId(projectPath: string): Promise { + if (!projectPath) { + return ''; + } + + const cached = projectIdCache.get(projectPath); + if (cached) { + return cached; + } + + let packageName = ''; + const ballerinaTomlPath = path.join(projectPath, 'Ballerina.toml'); + + try { + if (fs.existsSync(ballerinaTomlPath)) { + const tomlContent = await fs.promises.readFile(ballerinaTomlPath, 'utf-8'); + const tomlObj: BALLERINA_TOML = parseTomlToConfig(tomlContent) as BALLERINA_TOML; + packageName = tomlObj?.package?.name || ''; + } + } catch (error) { + console.warn(`[project-id] Failed to read Ballerina.toml from ${projectPath}:`, error); + } + + const hashInput = projectPath + packageName; + const hashedId = crypto.createHash('sha256').update(hashInput).digest('hex'); + + projectIdCache.set(projectPath, hashedId); + + return hashedId; +} diff --git a/workspaces/ballerina/ballerina-extension/src/features/telemetry/common/project-metrics.ts b/workspaces/ballerina/ballerina-extension/src/features/telemetry/common/project-metrics.ts new file mode 100644 index 00000000000..ecd8378a4e6 --- /dev/null +++ b/workspaces/ballerina/ballerina-extension/src/features/telemetry/common/project-metrics.ts @@ -0,0 +1,49 @@ +// Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com/) All Rights Reserved. + +// WSO2 LLC. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +import * as vscode from 'vscode'; +import * as fs from 'fs'; + +export interface ProjectMetrics { + fileCount: number; + lineCount: number; +} + +export async function getProjectMetrics(workspacePath?: string): Promise { + const includePattern = workspacePath + ? new vscode.RelativePattern(workspacePath, '**/*.bal') + : '**/*.bal'; + const excludePattern = workspacePath + ? new vscode.RelativePattern(workspacePath, '**/target/**') + : '**/target/**'; + + const files = await vscode.workspace.findFiles(includePattern, excludePattern); + + let totalLineCount = 0; + for (const fileUri of files) { + try { + const fileContent = await fs.promises.readFile(fileUri.fsPath, 'utf8'); + totalLineCount += fileContent.split('\n').length; + } catch (error) { + console.warn(`Failed to read file ${fileUri.fsPath}:`, error); + } + } + + return { + fileCount: files.length, + lineCount: totalLineCount + }; +} \ No newline at end of file diff --git a/workspaces/ballerina/ballerina-extension/src/features/telemetry/components.ts b/workspaces/ballerina/ballerina-extension/src/features/telemetry/components.ts index d4bd5337dca..58446de600e 100644 --- a/workspaces/ballerina/ballerina-extension/src/features/telemetry/components.ts +++ b/workspaces/ballerina/ballerina-extension/src/features/telemetry/components.ts @@ -45,3 +45,5 @@ export const CMP_CHOREO_AUTHENTICATION = "component.choreo.authentication"; export const CMP_PERF_ANALYZER = "component.perf.analyzer"; export const CMP_NOTEBOOK = "component.notebook"; export const CMP_OPEN_VSCODE_URL = "component.open.vscode.url"; + +export const CMP_BALLERINA_AI_GENERATION = "ballerina.ai.generation"; \ No newline at end of file diff --git a/workspaces/ballerina/ballerina-extension/src/features/telemetry/events.ts b/workspaces/ballerina/ballerina-extension/src/features/telemetry/events.ts index 0fd9cb3b98b..a9e7168dbdb 100644 --- a/workspaces/ballerina/ballerina-extension/src/features/telemetry/events.ts +++ b/workspaces/ballerina/ballerina-extension/src/features/telemetry/events.ts @@ -122,3 +122,13 @@ export const TM_EVENT_OPEN_REPO_CHANGE_PATH = "vscode.open.repo.change.path"; export const TM_EVENT_OPEN_REPO_CANCELED = "vscode.open.repo.canceled"; export const TM_EVENT_OPEN_REPO_NEW_FOLDER = "vscode.open.exist.repo.new.folder"; export const TM_EVENT_OPEN_REPO_SAME_FOLDER = "vscode.open.exist.repo.same.folder"; + + +// events for AI features +export const TM_EVENT_BALLERINA_AI_GENERATION_SUBMITTED = "ballerina.ai.generation.submitted"; +export const TM_EVENT_BALLERINA_AI_GENERATION_COMPLETED = "ballerina.ai.generation.completed"; +export const TM_EVENT_BALLERINA_AI_GENERATION_FAILED = "ballerina.ai.generation.failed"; +export const TM_EVENT_BALLERINA_AI_GENERATION_ABORTED = "ballerina.ai.generation.aborted"; +export const TM_EVENT_BALLERINA_AI_GENERATION_KEPT = "ballerina.ai.generation.kept"; +export const TM_EVENT_BALLERINA_AI_GENERATION_DISCARD = "ballerina.ai.generation.discard"; +export const TM_EVENT_BALLERINA_AI_GENERATION_FEEDBACK = "ballerina.ai.generation.feedback"; \ No newline at end of file diff --git a/workspaces/ballerina/ballerina-extension/src/features/telemetry/index.ts b/workspaces/ballerina/ballerina-extension/src/features/telemetry/index.ts index 1b7ebd0bb55..14834db27ba 100644 --- a/workspaces/ballerina/ballerina-extension/src/features/telemetry/index.ts +++ b/workspaces/ballerina/ballerina-extension/src/features/telemetry/index.ts @@ -18,6 +18,7 @@ import TelemetryReporter from "vscode-extension-telemetry"; import { BallerinaExtension } from "../../core"; +import { getLoginMethod, getBiIntelId } from "../../utils/ai/auth"; //Ballerina-VSCode-Extention repo key as default const DEFAULT_KEY = "3a82b093-5b7b-440c-9aa2-3b8e8e5704e7"; @@ -29,6 +30,20 @@ const CHOREO_COMPONENT_ID = process.env.VSCODE_CHOREO_COMPONENT_ID ? process.env const CHOREO_PROJECT_ID = process.env.VSCODE_CHOREO_PROJECT_ID ? process.env.VSCODE_CHOREO_PROJECT_ID : ''; const CHOREO_ORG_ID = process.env.VSCODE_CHOREO_ORG_ID ? process.env.VSCODE_CHOREO_ORG_ID : ''; +// Whitelist of component names +const WHITELISTED_COMPONENTS = new Set([ + 'ballerina.ai.generation', +]); + +// Whitelist of specific event names +const WHITELISTED_EVENTS = new Set([ + 'editor-workspace-ballerina-extension-activate', +]); + +export function shouldSendToAppInsights(eventName: string, componentName: string): boolean { + return WHITELISTED_EVENTS.has(eventName) || WHITELISTED_COMPONENTS.has(componentName); +} + export function createTelemetryReporter(ext: BallerinaExtension): TelemetryReporter { const reporter = new TelemetryReporter(ext.getID(), ext.getVersion(), INSTRUMENTATION_KEY); if (ext.context) { @@ -37,26 +52,36 @@ export function createTelemetryReporter(ext: BallerinaExtension): TelemetryRepor return reporter; } -export function sendTelemetryEvent(extension: BallerinaExtension, eventName: string, componentName: string, +export async function sendTelemetryEvent(extension: BallerinaExtension, eventName: string, componentName: string, customDimensions: { [key: string]: string; } = {}, measurements: { [key: string]: number; } = {}) { // temporarily disabled in codeserver due to GDPR issue if (extension.isTelemetryEnabled() && !extension.getCodeServerContext().codeServerEnv) { - extension.telemetryReporter.sendTelemetryEvent(eventName, getTelemetryProperties(extension, componentName, - customDimensions), measurements); + // Only send whitelisted AI telemetry events to Application Insights + if (shouldSendToAppInsights(eventName, componentName)) { + extension.telemetryReporter.sendTelemetryEvent(eventName, await getTelemetryProperties(extension, componentName, + customDimensions), measurements); + } } } -export function sendTelemetryException(extension: BallerinaExtension, error: Error, componentName: string, +export async function sendTelemetryException(extension: BallerinaExtension, error: Error, componentName: string, params: { [key: string]: string } = {}) { // temporarily disabled in codeserver due to GDPR issue if (extension.isTelemetryEnabled() && !extension.getCodeServerContext().codeServerEnv) { - extension.telemetryReporter.sendTelemetryException(error, getTelemetryProperties(extension, componentName, - params)); + // Only send whitelisted AI telemetry exceptions to Application Insights + if (shouldSendToAppInsights('', componentName)) { + extension.telemetryReporter.sendTelemetryException(error, await getTelemetryProperties(extension, componentName, + params)); + } } } -export function getTelemetryProperties(extension: BallerinaExtension, component: string, params: { [key: string]: string; } = {}) - : { [key: string]: string; } { +export async function getTelemetryProperties(extension: BallerinaExtension, component: string, params: { [key: string]: string; } = {}) + : Promise<{ [key: string]: string; }> { + + const userType = await getLoginMethod(); + const biIntelId = await getBiIntelId(); + return { ...params, 'ballerina.version': extension ? extension.ballerinaVersion : '', @@ -69,6 +94,8 @@ export function getTelemetryProperties(extension: BallerinaExtension, component: 'component': CHOREO_COMPONENT_ID, 'project': CHOREO_PROJECT_ID, 'org': CHOREO_ORG_ID, + 'user.login_method': userType ?? '', + 'user.bi_intel_id': biIntelId ?? '', }; } diff --git a/workspaces/ballerina/ballerina-extension/src/features/test-explorer/activator.ts b/workspaces/ballerina/ballerina-extension/src/features/test-explorer/activator.ts index ce5727aed37..6ca3ec97975 100644 --- a/workspaces/ballerina/ballerina-extension/src/features/test-explorer/activator.ts +++ b/workspaces/ballerina/ballerina-extension/src/features/test-explorer/activator.ts @@ -17,18 +17,72 @@ * under the License. */ -import { tests, workspace, TestRunProfileKind, TestController, Uri } from "vscode"; +import { tests, workspace, TestRunProfileKind, TestController, Uri, window, commands } from "vscode"; import { BallerinaExtension } from "../../core"; import { runHandler } from "./runner"; import { activateEditBiTest } from "./commands"; +import { createNewEvalset, createNewThread, deleteEvalset, deleteThread } from "./evalset-commands"; import { discoverTestFunctionsInProject, handleFileChange as handleTestFileUpdate, handleFileDelete as handleTestFileDelete } from "./discover"; import { getCurrentBallerinaProject, getWorkspaceRoot } from "../../utils/project-utils"; import { checkIsBallerinaPackage, checkIsBallerinaWorkspace } from "../../utils"; import { PROJECT_TYPE } from "../project"; +import { EvalsetTreeDataProvider } from "./evalset-tree-view"; +import { openView } from "../../stateMachine"; +import { EvalSet, EVENT_TYPE, MACHINE_VIEW } from "@wso2/ballerina-core"; +import * as fs from 'fs'; export let testController: TestController; +export const EVALUATION_GROUP = 'evaluations'; + export async function activate(ballerinaExtInstance: BallerinaExtension) { + // Register command to open evalset viewer + const openEvalsetCommand = commands.registerCommand('ballerina.openEvalsetViewer', async (uri: Uri, threadId?: string) => { + try { + const content = await fs.promises.readFile(uri.fsPath, 'utf-8'); + const evalsetData = JSON.parse(content) as EvalSet; + + openView(EVENT_TYPE.OPEN_VIEW, { + view: MACHINE_VIEW.EvalsetViewer, + evalsetData: { + filePath: uri.fsPath, + content: evalsetData, + threadId: threadId + } + }); + } catch (error) { + console.error('Error opening evalset:', error); + window.showErrorMessage(`Failed to open evalset: ${error}`); + } + }); + + // Register command to save evalset changes + const saveEvalThreadCommand = commands.registerCommand('ballerina.saveEvalThread', async (data: { filePath: string, updatedEvalSet: EvalSet }) => { + try { + const { filePath, updatedEvalSet } = data; + + // Write the updated evalset back to the file + await fs.promises.writeFile( + filePath, + JSON.stringify(updatedEvalSet, null, 2), + 'utf-8' + ); + + window.showInformationMessage('Evalset saved successfully'); + return { success: true }; + } catch (error) { + console.error('Error saving evalset:', error); + window.showErrorMessage(`Failed to save evalset: ${error}`); + return { success: false, error: String(error) }; + } + }); + + // Register commands for creating evalsets and threads + const createEvalsetCommand = commands.registerCommand('ballerina.createNewEvalset', createNewEvalset); + const createThreadCommand = commands.registerCommand('ballerina.createNewThread', createNewThread); + const deleteEvalsetCommand = commands.registerCommand('ballerina.deleteEvalset', deleteEvalset); + const deleteThreadCommand = commands.registerCommand('ballerina.deleteThread', deleteThread); + testController = tests.createTestController('ballerina-integrator-tests', 'WSO2 Integrator: BI Tests'); const workspaceRoot = getWorkspaceRoot(); @@ -46,6 +100,13 @@ export async function activate(ballerinaExtInstance: BallerinaExtension) { return; } + // Create and register Evalset TreeView + const evalsetTreeDataProvider = new EvalsetTreeDataProvider(); + const evalsetTreeView = window.createTreeView('ballerina-evalsets', { + treeDataProvider: evalsetTreeDataProvider, + showCollapseAll: true + }); + // Create test profiles to display. testController.createRunProfile('Run Tests', TestRunProfileKind.Run, runHandler, true); testController.createRunProfile('Debug Tests', TestRunProfileKind.Debug, runHandler, true); @@ -62,9 +123,9 @@ export async function activate(ballerinaExtInstance: BallerinaExtension) { discoverTestFunctionsInProject(ballerinaExtInstance, testController); // Register the test controller and file watcher with the extension context - ballerinaExtInstance.context?.subscriptions.push(testController, fileWatcher); + ballerinaExtInstance.context?.subscriptions.push(testController, fileWatcher, evalsetTreeView, evalsetTreeDataProvider, openEvalsetCommand, saveEvalThreadCommand, createEvalsetCommand, createThreadCommand, deleteEvalsetCommand, deleteThreadCommand); - activateEditBiTest(); + activateEditBiTest(ballerinaExtInstance); } diff --git a/workspaces/ballerina/ballerina-extension/src/features/test-explorer/commands.ts b/workspaces/ballerina/ballerina-extension/src/features/test-explorer/commands.ts index dd21af2f309..ebac3176b1a 100644 --- a/workspaces/ballerina/ballerina-extension/src/features/test-explorer/commands.ts +++ b/workspaces/ballerina/ballerina-extension/src/features/test-explorer/commands.ts @@ -17,9 +17,9 @@ * under the License. */ -import { commands, TestItem, window } from "vscode"; +import { commands, TestItem, window, workspace, WorkspaceEdit, Uri, Range } from "vscode"; import { openView, StateMachine, history } from "../../stateMachine"; -import { BI_COMMANDS, EVENT_TYPE, MACHINE_VIEW } from "@wso2/ballerina-core"; +import { BI_COMMANDS, EVENT_TYPE, MACHINE_VIEW, Annotation, ValueProperty, GetTestFunctionResponse, ComponentInfo } from "@wso2/ballerina-core"; import { isTestFunctionItem } from "./discover"; import path from "path"; import { promises as fs } from 'fs'; @@ -28,9 +28,19 @@ import { VisualizerWebview } from "../../views/visualizer/webview"; import { getCurrentProjectRoot, tryGetCurrentBallerinaFile } from "../../utils/project-utils"; import { findBallerinaPackageRoot } from "../../utils"; import { MESSAGES } from "../project"; -import { findWorkspaceTypeFromWorkspaceFolders } from "../../rpc-managers/common/utils"; +import { BallerinaExtension } from "../../core"; +import { isSupportedSLVersion, createVersionNumber } from "../../utils/config"; +import { EVALUATION_GROUP } from "./activator"; -export function activateEditBiTest() { +export function activateEditBiTest(ballerinaExtInstance: BallerinaExtension) { + // Check if AI Evaluation features are supported + const isAIEvaluationSupported = isSupportedSLVersion( + ballerinaExtInstance, + createVersionNumber(2201, 13, 2) + ); + + // Set VS Code context for UI visibility control + commands.executeCommand('setContext', 'ballerina.ai.evaluationSupported', isAIEvaluationSupported); // register run project tests handler commands.registerCommand(BI_COMMANDS.BI_EDIT_TEST_FUNCTION, async (entry: TestItem) => { const projectPath = await findProjectPath(entry.uri?.fsPath); @@ -44,15 +54,21 @@ export function activateEditBiTest() { return; } - const fileName = entry.id.split(":")[1]; + const fileName = entry.id.split(":")[2]; const fileUri = path.resolve(projectPath, `tests`, fileName); if (fileUri) { const range = entry.range; - openView(EVENT_TYPE.OPEN_VIEW, { documentUri: fileUri, - position: { startLine: range.start.line, startColumn: range.start.character, - endLine: range.end.line, endColumn: range.end.character } }); + openView(EVENT_TYPE.OPEN_VIEW, { + view: MACHINE_VIEW.BIDiagram, + documentUri: fileUri, + identifier: entry.label, + position: { + startLine: range.start.line, startColumn: range.start.character, + endLine: range.end.line, endColumn: range.end.character + } + }); history.clear(); - } + } }); commands.registerCommand(BI_COMMANDS.BI_ADD_TEST_FUNCTION, async (entry?: TestItem) => { @@ -65,11 +81,90 @@ export function activateEditBiTest() { const fileUri = path.resolve(projectPath, `tests`, `tests.bal`); ensureFileExists(fileUri); - openView(EVENT_TYPE.OPEN_VIEW, { view: MACHINE_VIEW.BITestFunctionForm, - documentUri: fileUri, identifier: '', serviceType: 'ADD_NEW_TEST' }); + openView(EVENT_TYPE.OPEN_VIEW, { + view: MACHINE_VIEW.BITestFunctionForm, + documentUri: fileUri, identifier: '', serviceType: 'ADD_NEW_TEST' + }); + }); + + commands.registerCommand(BI_COMMANDS.BI_ADD_AI_EVALUATION, async (entry?: TestItem) => { + const projectPath = await findProjectPath(entry?.uri?.fsPath); + + if (!projectPath) { + window.showErrorMessage(MESSAGES.NO_PROJECT_FOUND); + return; + } + + const fileUri = path.resolve(projectPath, `tests`, `tests.bal`); + ensureFileExists(fileUri); + openView(EVENT_TYPE.OPEN_VIEW, { + view: MACHINE_VIEW.BIAIEvaluationForm, + documentUri: fileUri, + identifier: '', + serviceType: 'ADD_NEW_TEST', + metadata: { + featureSupport: { + aiEvaluation: isAIEvaluationSupported + } + } + }); }); commands.registerCommand(BI_COMMANDS.BI_EDIT_TEST_FUNCTION_DEF, async (entry: TestItem) => { + const fileUri = entry.uri?.fsPath; + + if (!fileUri) { + window.showErrorMessage(MESSAGES.NO_FILE_FOUND); + return; + } + + if (!isTestFunctionItem(entry)) { + return; + } + + if (fileUri) { + const range = entry.range; + + // Fetch the test function to check if it belongs to the "evaluations" group + let viewToOpen = MACHINE_VIEW.BITestFunctionForm; // Default to regular test form + + try { + const response = await ballerinaExtInstance.langClient?.getTestFunction({ + functionName: entry.label, + filePath: fileUri + }); + if (response && isValidTestFunctionResponse(response) && response.function) { + const isEvaluation = hasEvaluationGroup(response.function); + if (isEvaluation) { + viewToOpen = MACHINE_VIEW.BIAIEvaluationForm; + } + } + } catch (error) { + console.warn('Failed to fetch test function, defaulting to regular test form:', error); + // Continue with default form if fetching fails + } + + openView(EVENT_TYPE.OPEN_VIEW, { + view: viewToOpen, + documentUri: fileUri, + identifier: entry.label, + position: { + startLine: range.start.line, + startColumn: range.start.character, + endLine: range.end.line, + endColumn: range.end.character + }, + serviceType: 'UPDATE_TEST', + metadata: { + featureSupport: { + aiEvaluation: isAIEvaluationSupported + } + } + }); + } + }); + + commands.registerCommand(BI_COMMANDS.BI_DELETE_TEST_FUNCTION, async (entry: TestItem) => { const projectPath = await findProjectPath(entry.uri?.fsPath); if (!projectPath) { @@ -78,28 +173,160 @@ export function activateEditBiTest() { } if (!isTestFunctionItem(entry)) { + window.showErrorMessage('Invalid test item. Please select a test function to delete.'); return; } - const fileName = entry.id.split(":")[1]; + // Parse test ID: test:${projectPath}:${fileName}:${functionName} + const idParts = entry.id.split(":"); + if (idParts.length < 4) { + window.showErrorMessage('Unable to parse test item ID.'); + return; + } + + const fileName = idParts[2]; + const functionName = idParts[3]; const fileUri = path.resolve(projectPath, `tests`, fileName); - if (fileUri) { - openView(EVENT_TYPE.OPEN_VIEW, { view: MACHINE_VIEW.BITestFunctionForm, - documentUri: fileUri, identifier: entry.label, serviceType: 'UPDATE_TEST' }); + + // Determine test type for confirmation message + let testType = "test function"; + try { + const response = await ballerinaExtInstance.langClient?.getTestFunction({ + functionName: entry.label, + filePath: fileUri + }); + + if (response && isValidTestFunctionResponse(response) && response.function) { + const isEvaluation = hasEvaluationGroup(response.function); + if (isEvaluation) { + testType = "AI evaluation test"; + } + } + } catch (error) { + console.warn('Failed to determine test type, proceeding with default:', error); + } + + // Confirmation dialog + const confirmation = await window.showWarningMessage( + `Are you sure you want to delete ${testType} '${functionName}'?`, + { modal: true }, + 'Delete' + ); + + if (confirmation !== 'Delete') { + return; + } + + try { + if (!entry.range) { + window.showErrorMessage('Test function range not available. Cannot delete.'); + return; + } + + // Create ComponentInfo from TestItem range + const component: ComponentInfo = { + name: functionName, + filePath: fileUri, + startLine: entry.range.start.line, + startColumn: entry.range.start.character, + endLine: entry.range.end.line, + endColumn: entry.range.end.character + }; + + // Call language server to delete the component + const response = await ballerinaExtInstance.langClient?.deleteByComponentInfo({ + filePath: fileUri, + component: component + }); + + if (!response || !response.textEdits) { + window.showErrorMessage('Failed to delete test function. No response from language server.'); + return; + } + + // Apply the text edits returned by language server + const edit = new WorkspaceEdit(); + + for (const [filePath, edits] of Object.entries(response.textEdits)) { + const uri = Uri.file(filePath); + for (const textEdit of edits) { + edit.replace( + uri, + new Range( + textEdit.range.start.line, + textEdit.range.start.character, + textEdit.range.end.line, + textEdit.range.end.character + ), + textEdit.newText + ); + } + } + + const success = await workspace.applyEdit(edit); + + if (success) { + window.showInformationMessage(`Test function '${functionName}' deleted successfully.`); + // File watcher automatically triggers test rediscovery + } else { + window.showErrorMessage(`Failed to apply deletion edits for test function '${functionName}'.`); + } + } catch (error) { + window.showErrorMessage(`Error deleting test function: ${error}`); + console.error('Delete test function error:', error); } }); } +/** + * Type guard to check if response is a valid GetTestFunctionResponse + * @param response The response to check + * @returns true if response is GetTestFunctionResponse, false if NOT_SUPPORTED_TYPE + */ +function isValidTestFunctionResponse(response: any): response is GetTestFunctionResponse { + return 'function' in response || 'errorMsg' in response || 'stacktrace' in response; +} + +/** + * Check if a test function belongs to the "evaluations" group + * @param testFunction The test function to check + * @returns true if the function has "evaluations" in its groups, false otherwise + */ +function hasEvaluationGroup(testFunction: any): boolean { + if (!testFunction?.annotations) { return false; } + + // Find the Config annotation + const configAnnotation = testFunction.annotations.find( + (annotation: Annotation) => annotation.name === 'Config' + ); + + if (!configAnnotation?.fields) { return false; } + + // Find the groups field + const groupsField = configAnnotation.fields.find( + (field: ValueProperty) => field.originalName === 'groups' + ); + + if (!groupsField?.value) { return false; } + if (!Array.isArray(groupsField.value)) { return false; } + + // Check if "evaluations" is in the groups array + const hasEvaluation = groupsField.value.some((group: string) => { + return group === EVALUATION_GROUP; + }); + return hasEvaluation; +} + async function ensureFileExists(filePath: string) { - try { - await fs.access(filePath); - } catch { - // Ensure the directory exists - await fs.mkdir(path.dirname(filePath), { recursive: true }); - - await fs.writeFile(filePath, '', 'utf8'); - console.log('File created:', filePath); - } + try { + await fs.access(filePath); + } catch { + // Ensure the directory exists + await fs.mkdir(path.dirname(filePath), { recursive: true }); + + await fs.writeFile(filePath, '', 'utf8'); + console.log('File created:', filePath); + } } async function findProjectPath(filePath?: string): Promise { diff --git a/workspaces/ballerina/ballerina-extension/src/features/test-explorer/discover.ts b/workspaces/ballerina/ballerina-extension/src/features/test-explorer/discover.ts index 98d80744175..cfffe73c28e 100644 --- a/workspaces/ballerina/ballerina-extension/src/features/test-explorer/discover.ts +++ b/workspaces/ballerina/ballerina-extension/src/features/test-explorer/discover.ts @@ -119,6 +119,8 @@ function createTests(response: TestsDiscoveryResponse, testController: TestContr // Iterate over the result map (test groups) for (const [group, testFunctions] of entries) { let groupItem: TestItem | undefined; + // Remove leading/trailing quotes from group name for display + const cleanedGroupName = group.replace(/^["']|["']$/g, ''); // For workspace context with DEFAULT_GROUP, skip the group level and add tests directly to project if (isWorkspaceContext && group === 'DEFAULT_GROUP' && projectGroupItem) { @@ -128,7 +130,7 @@ function createTests(response: TestsDiscoveryResponse, testController: TestContr const groupId = `group:${path.basename(projectPath)}:${group}`; groupItem = projectGroupItem.children.get(groupId); if (!groupItem) { - groupItem = testController.createTestItem(groupId, group); + groupItem = testController.createTestItem(groupId, cleanedGroupName); projectGroupItem.children.add(groupItem); groups.push(groupId); } @@ -137,7 +139,7 @@ function createTests(response: TestsDiscoveryResponse, testController: TestContr const groupId = `group:${group}`; groupItem = testController.items.get(groupId); if (!groupItem) { - groupItem = testController.createTestItem(groupId, group); + groupItem = testController.createTestItem(groupId, cleanedGroupName); testController.items.add(groupItem); groups.push(groupId); } diff --git a/workspaces/ballerina/ballerina-extension/src/features/test-explorer/evalset-commands.ts b/workspaces/ballerina/ballerina-extension/src/features/test-explorer/evalset-commands.ts new file mode 100644 index 00000000000..42a909dddc9 --- /dev/null +++ b/workspaces/ballerina/ballerina-extension/src/features/test-explorer/evalset-commands.ts @@ -0,0 +1,267 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import * as vscode from 'vscode'; +import * as path from 'path'; +import * as crypto from 'crypto'; +import * as fs from 'fs'; +import { EvalSet, EvalThread, EvalsetTrace } from '@wso2/ballerina-core'; +import { ensureEvalsetsDirectory, validateEvalsetName, validateThreadName } from './evalset-utils'; + +export async function createNewEvalset(): Promise { + try { + // 1. Ensure evalsets directory exists + const evalsetsDir = await ensureEvalsetsDirectory(); + + // 2. Prompt for name + const name = await vscode.window.showInputBox({ + prompt: 'Enter evalset name', + placeHolder: 'my-evalset', + validateInput: (value) => validateEvalsetName(value, evalsetsDir) + }); + + if (!name) { return; } // User cancelled + + // 3. Create EvalSet with empty threads array + const evalset: EvalSet = { + id: crypto.randomUUID(), + name: name, + threads: [], + created_on: new Date().toISOString() + }; + + // 4. Write file + const filePath = path.join(evalsetsDir, `${name}.evalset.json`); + const jsonContent = JSON.stringify(evalset, null, 2); + const fileUri = vscode.Uri.file(filePath); + + await vscode.workspace.fs.writeFile(fileUri, new TextEncoder().encode(jsonContent)); + + // 5. Success message with Open option + const action = await vscode.window.showInformationMessage( + `Evalset created: ${name}.evalset.json`, + 'Open' + ); + + if (action === 'Open') { + vscode.commands.executeCommand('ballerina.openEvalsetViewer', fileUri); + } + + } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error); + vscode.window.showErrorMessage(`Failed to create evalset: ${errorMessage}`); + } +} + +export async function createNewThread(evalsetFileNode?: any, autoRefresh?: boolean): Promise { + try { + // Validate that this was called from tree view with proper node + if (!evalsetFileNode || !evalsetFileNode.uri) { + vscode.window.showErrorMessage('Please use the + button next to an evalset in the tree view'); + return; + } + + const filePath = evalsetFileNode.uri.fsPath; + + // 1. Read existing evalset file + const fileContent = await fs.promises.readFile(filePath, 'utf8'); + let evalset: EvalSet; + + try { + evalset = JSON.parse(fileContent); + } catch (parseError) { + vscode.window.showErrorMessage('Failed to parse evalset file: Invalid JSON'); + return; + } + + // 2. Validate evalset structure + if (!evalset.threads || !Array.isArray(evalset.threads)) { + vscode.window.showErrorMessage('Invalid evalset file: missing threads array'); + return; + } + + // 3. Prompt for thread name + const threadCount = evalset.threads.length; + const defaultName = `Thread ${threadCount + 1}`; + + const threadName = await vscode.window.showInputBox({ + prompt: 'Enter thread name', + placeHolder: defaultName, + value: defaultName, + validateInput: (value) => validateThreadName(value) + }); + + if (!threadName) { return; } // User cancelled + + // 4. Create default trace with empty message turn + const now = new Date().toISOString(); + const defaultTrace: EvalsetTrace = { + id: crypto.randomUUID(), + userMessage: { + role: 'user', + content: 'User message' + }, + iterations: [], + output: { + role: 'assistant', + content: 'Agent response' + }, + tools: [], + startTime: now, + endTime: now + }; + + // 5. Create new thread with default trace + const newThread: EvalThread = { + id: crypto.randomUUID(), + name: threadName, + traces: [defaultTrace], + created_on: new Date().toISOString() + }; + + // 6. Add to evalset and write file + evalset.threads.push(newThread); + const jsonContent = JSON.stringify(evalset, null, 2); + const fileUri = vscode.Uri.file(filePath); + + await vscode.workspace.fs.writeFile(fileUri, new TextEncoder().encode(jsonContent)); + + // 7. Handle UI refresh based on where the command was called from + if (autoRefresh) { + // Called from evalset viewer - refresh immediately to show new thread in list + vscode.commands.executeCommand('ballerina.openEvalsetViewer', fileUri); + + // Show non-blocking notification + vscode.window.showInformationMessage( + `Thread "${threadName}" added to evalset`, + 'Open' + ).then((action) => { + if (action === 'Open') { + vscode.commands.executeCommand('ballerina.openEvalsetViewer', fileUri, newThread.id); + } + }); + } else { + // Called from tree view - use original behavior with blocking notification + const action = await vscode.window.showInformationMessage( + `Thread "${threadName}" added to evalset`, + 'Open' + ); + + if (action === 'Open') { + vscode.commands.executeCommand('ballerina.openEvalsetViewer', fileUri, newThread.id); + } + } + + } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error); + vscode.window.showErrorMessage(`Failed to create thread: ${errorMessage}`); + } +} + +export async function deleteEvalset(evalsetFileNode?: any): Promise { + try { + // Validate that this was called from tree view with proper node + if (!evalsetFileNode || !evalsetFileNode.uri) { + vscode.window.showErrorMessage('Please use the delete button on an evalset in the tree view'); + return; + } + + const filePath = evalsetFileNode.uri.fsPath; + const fileName = path.basename(filePath); + + // Confirm deletion + const confirmation = await vscode.window.showWarningMessage( + `Are you sure you want to delete "${fileName}"? This action cannot be undone.`, + { modal: true }, + 'Delete' + ); + + if (confirmation !== 'Delete') { + return; // User cancelled + } + + // Delete the file + await vscode.workspace.fs.delete(evalsetFileNode.uri); + + vscode.window.showInformationMessage(`Evalset "${fileName}" deleted successfully`); + + } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error); + vscode.window.showErrorMessage(`Failed to delete evalset: ${errorMessage}`); + } +} + +export async function deleteThread(threadNode?: any, autoRefresh?: boolean): Promise { + try { + // Validate that this was called from tree view with proper node + if (!threadNode || !threadNode.parentUri || !threadNode.threadId) { + vscode.window.showErrorMessage('Please use the delete button on a thread in the tree view'); + return; + } + + const filePath = threadNode.parentUri.fsPath; + const threadId = threadNode.threadId; + + // Read existing evalset file + const fileContent = await fs.promises.readFile(filePath, 'utf8'); + let evalset: EvalSet; + + try { + evalset = JSON.parse(fileContent); + } catch (parseError) { + vscode.window.showErrorMessage('Failed to parse evalset file: Invalid JSON'); + return; + } + + // Find the thread to get its name for confirmation + const threadToDelete = evalset.threads.find(t => t.id === threadId); + if (!threadToDelete) { + vscode.window.showErrorMessage('Thread not found in evalset'); + return; + } + + // Confirm deletion + const confirmation = await vscode.window.showWarningMessage( + `Are you sure you want to delete thread "${threadToDelete.name}"? This action cannot be undone.`, + { modal: true }, + 'Delete' + ); + + if (confirmation !== 'Delete') { + return; // User cancelled + } + + // Remove the thread from evalset + evalset.threads = evalset.threads.filter(t => t.id !== threadId); + + // Write updated evalset back to file + const jsonContent = JSON.stringify(evalset, null, 2); + const fileUri = vscode.Uri.file(filePath); + await vscode.workspace.fs.writeFile(fileUri, new TextEncoder().encode(jsonContent)); + + // Handle UI refresh based on where the command was called from + if (autoRefresh) { + vscode.commands.executeCommand('ballerina.openEvalsetViewer', fileUri); + } + vscode.window.showInformationMessage(`Thread "${threadToDelete.name}" deleted successfully`); + + } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error); + vscode.window.showErrorMessage(`Failed to delete thread: ${errorMessage}`); + } +} diff --git a/workspaces/ballerina/ballerina-extension/src/features/test-explorer/evalset-tree-view.ts b/workspaces/ballerina/ballerina-extension/src/features/test-explorer/evalset-tree-view.ts new file mode 100644 index 00000000000..9c73b33d07a --- /dev/null +++ b/workspaces/ballerina/ballerina-extension/src/features/test-explorer/evalset-tree-view.ts @@ -0,0 +1,229 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import * as vscode from 'vscode'; +import * as fs from 'fs'; +import * as path from 'path'; + +// Interface matching the EvalThread object structure +interface EvalThreadJson { + id: string; + name: string; + traces: any[]; +} + +// Interface matching the new EvalSet JSON structure +interface EvalSetJson { + id: string; + name?: string; + description?: string; + threads: EvalThreadJson[]; // Array of Thread objects + created_on?: number; +} + +/** + * Represents an evalset file node in the tree view + */ +class EvalsetFileNode { + constructor( + public readonly uri: vscode.Uri, + public readonly label: string, + public readonly threadCount: number, + public readonly description?: string + ) { } +} + +/** + * Represents a single thread within an evalset + */ +class EvalsetThreadNode { + constructor( + public readonly parentUri: vscode.Uri, + public readonly threadIndex: number, + public readonly label: string, + public readonly threadId: string, + public readonly traceCount: number + ) { } +} + +type EvalsetNode = EvalsetFileNode | EvalsetThreadNode; + +/** + * TreeDataProvider for displaying evalsets + */ +export class EvalsetTreeDataProvider implements vscode.TreeDataProvider { + private _onDidChangeTreeData: vscode.EventEmitter = + new vscode.EventEmitter(); + readonly onDidChangeTreeData: vscode.Event = + this._onDidChangeTreeData.event; + + private fileWatcher: vscode.FileSystemWatcher | undefined; + + constructor() { + this.setupFileWatcher(); + } + + private setupFileWatcher(): void { + const workspaceFolders = vscode.workspace.workspaceFolders; + if (!workspaceFolders || workspaceFolders.length === 0) { + return; + } + + // Watch all evalset files in workspace + const pattern = '**/evalsets/**/*.evalset.json'; + this.fileWatcher = vscode.workspace.createFileSystemWatcher(pattern); + + // Refresh on file changes + this.fileWatcher.onDidCreate(() => this.refresh()); + this.fileWatcher.onDidChange(() => this.refresh()); + this.fileWatcher.onDidDelete(() => this.refresh()); + } + + refresh(): void { + this._onDidChangeTreeData.fire(); + } + + getTreeItem(element: EvalsetNode): vscode.TreeItem { + if (element instanceof EvalsetFileNode) { + const item = new vscode.TreeItem( + element.label, + vscode.TreeItemCollapsibleState.Collapsed + ); + item.tooltip = element.description || `EvalSet with ${element.threadCount} threads`; + item.description = `${element.threadCount} thread${element.threadCount !== 1 ? 's' : ''}`; + item.iconPath = new vscode.ThemeIcon('collection'); + item.contextValue = 'evalsetFile'; + item.resourceUri = element.uri; + item.command = { + command: 'ballerina.openEvalsetViewer', + title: 'Open Evalset', + arguments: [element.uri] + }; + return item; + } else { + const item = new vscode.TreeItem( + element.label, + vscode.TreeItemCollapsibleState.None + ); + item.tooltip = `Thread ID: ${element.threadId} (${element.traceCount} traces)`; + + item.iconPath = new vscode.ThemeIcon('file-text'); + item.contextValue = 'evalsetThread'; + item.resourceUri = element.parentUri; + + item.command = { + command: 'ballerina.openEvalsetViewer', + title: 'Open Evalset Thread', + arguments: [element.parentUri, element.threadId] + }; + return item; + } + } + + async getChildren(element?: EvalsetNode): Promise { + if (!element) { + // Root level - return all evalset files + return this.getEvalsetFiles(); + } else if (element instanceof EvalsetFileNode) { + // Return threads for this evalset file + return this.getThreadsForFile(element.uri); + } + + return []; + } + + /** + * Get all evalset files in the workspace + */ + private async getEvalsetFiles(): Promise { + const workspaceFolders = vscode.workspace.workspaceFolders; + if (!workspaceFolders || workspaceFolders.length === 0) { + return []; + } + + const evalsetFiles = await vscode.workspace.findFiles('**/evalsets/**/*.evalset.json'); + const nodes: EvalsetFileNode[] = []; + + for (const uri of evalsetFiles) { + try { + const content = await fs.promises.readFile(uri.fsPath, 'utf-8'); + const evalsetData: EvalSetJson = JSON.parse(content); + + // Validation for new format + if (!evalsetData.threads || !Array.isArray(evalsetData.threads)) { + continue; + } + + const threadCount = evalsetData.threads.length; + const label = evalsetData.name || path.basename(uri.fsPath, '.evalset.json'); + const description = evalsetData.description || ''; + + nodes.push(new EvalsetFileNode(uri, label, threadCount, description)); + } catch (error) { + console.error(`Failed to parse evalset file ${uri.fsPath}:`, error); + } + } + + return nodes; + } + + /** + * Get threads for a specific evalset file + */ + private async getThreadsForFile(uri: vscode.Uri): Promise { + try { + const content = await fs.promises.readFile(uri.fsPath, 'utf-8'); + const evalsetData: EvalSetJson = JSON.parse(content); + const nodes: EvalsetThreadNode[] = []; + + if (!evalsetData.threads || !Array.isArray(evalsetData.threads)) { + return []; + } + + evalsetData.threads.forEach((threadObj: EvalThreadJson, index: number) => { + // Ensure traces is an array + const traceCount = Array.isArray(threadObj.traces) ? threadObj.traces.length : 0; + + // Use the name defined in the thread object, fallback to generated name + const label = threadObj.name || `Thread ${index + 1}`; + const threadId = threadObj.id || `thread-${index + 1}`; + + nodes.push(new EvalsetThreadNode( + uri, + index, + label, + threadId, + traceCount + )); + }); + + return nodes; + } catch (error) { + console.error(`Failed to get threads for ${uri.fsPath}:`, error); + return []; + } + } + + /** + * Dispose resources + */ + dispose(): void { + this.fileWatcher?.dispose(); + this._onDidChangeTreeData.dispose(); + } +} diff --git a/workspaces/ballerina/ballerina-extension/src/features/test-explorer/evalset-utils.ts b/workspaces/ballerina/ballerina-extension/src/features/test-explorer/evalset-utils.ts new file mode 100644 index 00000000000..30f26f60b41 --- /dev/null +++ b/workspaces/ballerina/ballerina-extension/src/features/test-explorer/evalset-utils.ts @@ -0,0 +1,90 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import * as vscode from 'vscode'; +import * as path from 'path'; +import * as fs from 'fs'; +import { getCurrentProjectRoot } from '../../utils/project-utils'; + +export async function ensureEvalsetsDirectory(): Promise { + // Check if workspace is open + if (!vscode.workspace.workspaceFolders || vscode.workspace.workspaceFolders.length === 0) { + throw new Error('Please open a workspace first'); + } + + let projectRoot: string; + try { + projectRoot = await getCurrentProjectRoot(); + } catch (error) { + // Fallback to workspace root if project root cannot be determined + projectRoot = vscode.workspace.workspaceFolders[0].uri.fsPath; + } + + const evalsetsDir = path.join(projectRoot, 'evalsets'); + const evalsetsDirUri = vscode.Uri.file(evalsetsDir); + + try { + await vscode.workspace.fs.createDirectory(evalsetsDirUri); + } catch (e) { + // Directory might exist, ignore + } + + return evalsetsDir; +} + +export function validateEvalsetName(name: string, evalsetsDir: string): string | null { + if (!name || name.trim().length === 0) { + return 'Evalset name cannot be empty'; + } + if (!/^[a-zA-Z0-9-_]+$/.test(name)) { + return 'Name can only contain letters, numbers, hyphens, and underscores'; + } + if (name.length > 100) { + return 'Name is too long (max 100 characters)'; + } + const filePath = path.join(evalsetsDir, `${name}.evalset.json`); + if (fs.existsSync(filePath)) { + return 'An evalset with this name already exists'; + } + return null; // Valid +} + +export function validateThreadName(name: string): string | null { + if (!name || name.trim().length === 0) { + return 'Thread name cannot be empty'; + } + if (name.length > 100) { + return 'Thread name is too long (max 100 characters)'; + } + return null; // Valid +} + +export async function findExistingEvalsets(evalsetsDir: string): Promise> { + const pattern = new vscode.RelativePattern(evalsetsDir, '*.evalset.json'); + const files = await vscode.workspace.findFiles(pattern); + + return files.map(uri => ({ + label: path.basename(uri.fsPath, '.evalset.json'), + description: uri.fsPath, + filePath: uri.fsPath + })); +} diff --git a/workspaces/ballerina/ballerina-extension/src/features/test-explorer/runner.ts b/workspaces/ballerina/ballerina-extension/src/features/test-explorer/runner.ts index c1d6aafd496..796559a5497 100644 --- a/workspaces/ballerina/ballerina-extension/src/features/test-explorer/runner.ts +++ b/workspaces/ballerina/ballerina-extension/src/features/test-explorer/runner.ts @@ -19,7 +19,7 @@ import { exec } from 'child_process'; import { CancellationToken, TestRunRequest, TestMessage, TestRun, TestItem, debug, Uri, WorkspaceFolder, DebugConfiguration, workspace, TestRunProfileKind } from 'vscode'; -import { testController } from './activator'; +import { EVALUATION_GROUP, testController } from './activator'; import { StateMachine } from "../../stateMachine"; import { isTestFunctionItem, isTestGroupItem, isProjectGroupItem } from './discover'; import { extension } from '../../BalExtensionContext'; @@ -35,7 +35,7 @@ function getProjectPathFromTestItem(test: TestItem): string | undefined { if (isTestFunctionItem(test)) { // Extract from test ID: test:${projectPath}:${fileName}:${functionName} const parts = test.id.split(':'); - if (parts.length >= 2 && parts[0] === 'test') { + if (parts.length >= 2 && parts[0] === 'test') { return parts[1]; } } else if (isProjectGroupItem(test)) { @@ -84,6 +84,49 @@ function getProjectNameIfWorkspace(projectPath: string): string | undefined { return undefined; } +function isAiEvaluations(test: TestItem): boolean { + // Check if the test item itself is the evaluations group + if (isTestGroupItem(test) && test.label === EVALUATION_GROUP) { + return true; + } + + // Check if the test function's parent is the evaluations group + if (isTestFunctionItem(test) && test.parent && test.parent.label === EVALUATION_GROUP) { + return true; + } + + // Check if the project group contains only evaluations groups + if (isProjectGroupItem(test)) { + // Return true only if all children are evaluation groups + let allChildrenAreEvaluations = true; + let hasChildren = false; + + test.children.forEach((child) => { + hasChildren = true; + if (!isTestGroupItem(child) || child.label !== EVALUATION_GROUP) { + allChildrenAreEvaluations = false; + } + }); + + return hasChildren && allChildrenAreEvaluations; + } + + return false; +} + +function buildTestCommand(test: TestItem, executor: string, projectName: string | undefined, testCaseNames?: string[]): string { + if (isAiEvaluations(test)) { + // Evaluations tests use group-based execution with test report + const projectPart = projectName ? ` ${projectName}` : ''; + return `${executor} test --groups ${EVALUATION_GROUP} --test-report --test-report-dir=evaluation-reports${projectPart}`; + } else { + // Standard tests use code coverage and optional test filtering + const testsPart = testCaseNames && testCaseNames.length > 0 ? ` --tests ${testCaseNames.join(',')}` : ''; + const projectPart = projectName ? ` ${projectName}` : ''; + return `${executor} test --code-coverage${testsPart}${projectPart}`; + } +} + export async function runHandler(request: TestRunRequest, token: CancellationToken) { if (!request.include) { return; @@ -153,17 +196,7 @@ export async function runHandler(request: TestRunRequest, token: CancellationTok } }); - if (projectName) { - // Workspace context - include project name in command - command = testCaseNames.length > 0 - ? `${executor} test --code-coverage --tests ${testCaseNames.join(',')} ${projectName}` - : `${executor} test --code-coverage ${projectName}`; - } else { - // Single project context - command = testCaseNames.length > 0 - ? `${executor} test --code-coverage --tests ${testCaseNames.join(',')}` - : `${executor} test --code-coverage`; - } + command = buildTestCommand(test, executor, projectName, testCaseNames.length > 0 ? testCaseNames : undefined); const startTime = Date.now(); // For workspace, run from workspace root; for single project, run from project path @@ -197,13 +230,7 @@ export async function runHandler(request: TestRunRequest, token: CancellationTok run.started(child); }); - if (projectName) { - // Workspace context - include project name in command - command = `${executor} test --code-coverage --tests ${testCaseNames.join(',')} ${projectName}`; - } else { - // Single project context - command = `${executor} test --code-coverage --tests ${testCaseNames.join(',')}`; - } + command = buildTestCommand(test, executor, projectName, testCaseNames); const startTime = Date.now(); // For workspace, run from workspace root; for single project, run from project path @@ -228,13 +255,7 @@ export async function runHandler(request: TestRunRequest, token: CancellationTok }); }); } else if (isTestFunctionItem(test)) { - if (projectName) { - // Workspace context - include project name in command - command = `${executor} test --code-coverage --tests ${test.label} ${projectName}`; - } else { - // Single project context - command = `${executor} test --code-coverage --tests ${test.label}`; - } + command = buildTestCommand(test, executor, projectName, [test.label]); const parentGroup = test.parent; let testItems: TestItem[] = []; diff --git a/workspaces/ballerina/ballerina-extension/src/features/tracing/activate.ts b/workspaces/ballerina/ballerina-extension/src/features/tracing/activate.ts index d33bf3c59f6..bfa627a7d66 100644 --- a/workspaces/ballerina/ballerina-extension/src/features/tracing/activate.ts +++ b/workspaces/ballerina/ballerina-extension/src/features/tracing/activate.ts @@ -92,8 +92,8 @@ export function activateTracing(ballerinaExtInstance: BallerinaExtension) { const showTraceDetailsCommand = vscode.commands.registerCommand( SHOW_TRACE_DETAILS_COMMAND, - (trace: Trace) => { - showTraceDetails(trace); + (trace: Trace, focusSpanId?: string) => { + showTraceDetails(trace, focusSpanId); } ); @@ -192,9 +192,9 @@ async function showTraceWindow(): Promise { /** * Show trace details in a webview */ -function showTraceDetails(trace: Trace): void { +function showTraceDetails(trace: Trace, focusSpanId?: string): void { try { - TraceDetailsWebview.show(trace); + TraceDetailsWebview.show(trace, false, focusSpanId); } catch (error) { const message = error instanceof Error ? error.message : String(error); vscode.window.showErrorMessage(`Failed to show trace details: ${message}`); diff --git a/workspaces/ballerina/ballerina-extension/src/features/tracing/trace-converter.ts b/workspaces/ballerina/ballerina-extension/src/features/tracing/trace-converter.ts new file mode 100644 index 00000000000..777a69c73c6 --- /dev/null +++ b/workspaces/ballerina/ballerina-extension/src/features/tracing/trace-converter.ts @@ -0,0 +1,329 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { + EvalChatUserMessage as ChatUserMessage, + EvalChatAssistantMessage as ChatAssistantMessage, + EvalChatMessage as ChatMessage, + EvalToolSchema as ToolSchema, + EvalIteration as Iteration, + EvalsetTrace, + EvalFunctionCall +} from '@wso2/ballerina-core'; + +// TraceData interface (from trace-details-webview.ts) +interface TraceData { + traceId: string; + spans: SpanData[]; + resource: ResourceData; + scope: ScopeData; + firstSeen: string; + lastSeen: string; +} + +interface SpanData { + spanId: string; + traceId: string; + parentSpanId: string; + name: string; + kind: string | number; + startTime?: string; + endTime?: string; + attributes?: AttributeData[]; +} + +interface ResourceData { + name: string; + attributes: AttributeData[]; +} + +interface ScopeData { + name: string; + version?: string; + attributes?: AttributeData[]; +} + +interface AttributeData { + key: string; + value: string; +} + +// --- Helper Functions --- + +/** + * Helper to extract a value from the span's attribute list by key. + */ +function getAttribute(span: SpanData, key: string): string | null { + if (!span.attributes) { return null; } + const attr = span.attributes.find((a: AttributeData) => a.key === key); + return attr ? attr.value : null; +} + +/** + * Parses a JSON string safely, returning null or a default if parsing fails. + */ +function safeJsonParse(jsonString: string | null): any { + if (!jsonString) { return null; } + try { + return JSON.parse(jsonString); + } catch (e) { + // If it's not JSON, return the raw string or handle appropriately + return jsonString; + } +} + +// --- Main Conversion Logic --- + +/** + * Converts a TraceData object to an EvalsetTrace format. + */ +export function convertTraceToEvalset(traceData: TraceData): EvalsetTrace { + const spans = traceData.spans; + const rootSpan = spans.find((s: SpanData) => s.kind === 2 || s.kind === '2'); + + // Find all chat spans that contain conversation history + const chatSpans = spans.filter((s: SpanData) => + s.name.startsWith('chat') && s.attributes?.some((a: AttributeData) => a.key === 'gen_ai.input.messages') + ); + + // Find all tool spans in the trace + const toolSpans = spans.filter((s: SpanData) => + s.name.startsWith('execute_tool') + ); + + // Sort tool spans by start time to process in order + toolSpans.sort((a, b) => { + const timeA = a.startTime || ''; + const timeB = b.startTime || ''; + return timeA.localeCompare(timeB); + }); + + // Sort chat spans by start time to process in order + chatSpans.sort((a, b) => { + const timeA = a.startTime || ''; + const timeB = b.startTime || ''; + return timeA.localeCompare(timeB); + }); + + if (!rootSpan || chatSpans.length === 0) { + throw new Error("Could not find required Root span or chat spans in trace."); + } + + // Extract Data + const traceId = traceData.traceId; + const startTime = rootSpan.startTime || traceData.firstSeen; + const endTime = rootSpan.endTime || traceData.lastSeen; + + // Extract Tools (look in any span that has gen_ai.input.tools) + const toolSpan = spans.find((s: SpanData) => + s.attributes?.some((a: AttributeData) => a.key === 'gen_ai.input.tools') + ); + const tools: ToolSchema[] = []; + + if (toolSpan) { + const toolsStr = getAttribute(toolSpan, 'gen_ai.input.tools'); + if (toolsStr && toolsStr.trim() !== '') { + const toolsData = safeJsonParse(toolsStr); + if (Array.isArray(toolsData)) { + toolsData.forEach((t: any) => { + tools.push({ + name: t.name, + description: t.description, + parametersSchema: t.parameters + }); + }); + } + } + } + + // Helper function to parse messages + const parseMessages = (messagesStr: string | null): ChatMessage[] => { + if (!messagesStr) { + return []; + } + + let rawMessages = safeJsonParse(messagesStr); + + // Handle case where messages might be a single string + if (typeof rawMessages === 'string') { + rawMessages = [{ role: 'user', content: rawMessages }]; + } + + // Ensure we have an array + if (!Array.isArray(rawMessages)) { + console.warn('Expected array of messages, got:', typeof rawMessages); + return []; + } + + // Map raw OpenAI-style messages to our ChatMessage types + return rawMessages.map((msg: any) => { + const base: any = { + role: msg.role, + content: msg.content ?? null + }; + + if (msg.name) { base.name = msg.name; } + + // Only include toolCalls for assistant messages + if (msg.role === 'assistant') { + if (msg.tool_calls) { + base.toolCalls = msg.tool_calls.map((tc: any) => ({ + id: tc.id, + name: tc.function?.name || tc.name, + arguments: typeof tc.function?.arguments === 'string' + ? safeJsonParse(tc.function.arguments) + : tc.function?.arguments || tc.arguments + })); + } else if (msg.toolCalls) { + base.toolCalls = msg.toolCalls; + } else { + base.toolCalls = null; + } + } + + if (msg.id) { base.id = msg.id; } + + return base as ChatMessage; + }); + }; + + // Helper function to parse a single output message + const parseOutputMessage = (messageStr: string | null): ChatMessage => { + if (!messageStr) { + return { + role: 'assistant', + content: 'No output available', + toolCalls: null + }; + } + + const rawMessage = safeJsonParse(messageStr); + + // If it's already a properly formatted message object + if (rawMessage && typeof rawMessage === 'object' && rawMessage.role) { + const base: any = { + role: rawMessage.role, + content: rawMessage.content ?? null + }; + + if (rawMessage.name) { base.name = rawMessage.name; } + + // Only include toolCalls for assistant messages + if (rawMessage.role === 'assistant') { + if (rawMessage.tool_calls) { + base.toolCalls = rawMessage.tool_calls.map((tc: any) => ({ + id: tc.id, + name: tc.function?.name || tc.name, + arguments: typeof tc.function?.arguments === 'string' + ? safeJsonParse(tc.function.arguments) + : tc.function?.arguments || tc.arguments + })); + } else if (rawMessage.toolCalls) { + base.toolCalls = rawMessage.toolCalls; + } else { + base.toolCalls = null; + } + } + + if (rawMessage.id) { base.id = rawMessage.id; } + + return base as ChatMessage; + } + + // Fallback: treat as plain content + return { + role: 'assistant', + content: typeof rawMessage === 'string' ? rawMessage : JSON.stringify(rawMessage), + toolCalls: null + }; + }; + + // Build iterations from chat spans + const iterations: Iteration[] = []; + + for (let i = 0; i < chatSpans.length; i++) { + const chatSpan = chatSpans[i]; + const isLastSpan = i === chatSpans.length - 1; + + const inputMessagesStr = getAttribute(chatSpan, 'gen_ai.input.messages'); + const outputMessageStr = getAttribute(chatSpan, 'gen_ai.output.messages'); + + const inputMessages = parseMessages(inputMessagesStr); + const iterationHistory = [...inputMessages]; + + // Parse output message (single object) + const output = parseOutputMessage(outputMessageStr); + + if (!isLastSpan) { + iterationHistory.push(output); + } + + // Create iteration + iterations.push({ + history: iterationHistory, + output: output as ChatAssistantMessage, + startTime: chatSpan.startTime || startTime, + endTime: chatSpan.endTime || endTime + }); + } + + // Determine User Message (Trigger) + const firstChatInputStr = getAttribute(chatSpans[0], 'gen_ai.input.messages'); + const firstInputMessages = parseMessages(firstChatInputStr); + const lastUserMsg = [...firstInputMessages].reverse().find(m => m.role === 'user'); + const userMessage: ChatUserMessage = lastUserMsg + ? (lastUserMsg as ChatUserMessage) + : { role: 'user', content: 'Unknown input' }; + + const lastIteration = iterations[iterations.length - 1]; + const finalOutputToolCalls: EvalFunctionCall[] = []; + + for (let i = 0; i < toolSpans.length; i++) { + const toolSpan = toolSpans[i]; + const toolCallsStr = getAttribute(toolSpan, 'gen_ai.tool.arguments'); + const toolCallsData = safeJsonParse(toolCallsStr); + finalOutputToolCalls.push({ + name: getAttribute(toolSpan, 'gen_ai.tool.name') || 'unknown_tool', + arguments: toolCallsData + }); + } + + // Final output is the last iteration's output + const finalOutput: ChatAssistantMessage = lastIteration.output; + + // Assemble Final Trace Object + const evalsetTrace: EvalsetTrace = { + id: traceId, + userMessage: userMessage, + iterations: iterations, + output: finalOutput, + tools: tools, + ...(finalOutputToolCalls.length > 0 && { toolCalls: finalOutputToolCalls }), + startTime: startTime, + endTime: endTime + }; + + return evalsetTrace; +} + +/** + * Converts multiple TraceData objects to a combined evalset format. + */ +export function convertTracesToEvalset(traces: TraceData[]): EvalsetTrace[] { + return traces.map(trace => convertTraceToEvalset(trace)); +} diff --git a/workspaces/ballerina/ballerina-extension/src/features/tracing/trace-details-webview.ts b/workspaces/ballerina/ballerina-extension/src/features/tracing/trace-details-webview.ts index 4d80bdb88fd..bddd5a0fcba 100644 --- a/workspaces/ballerina/ballerina-extension/src/features/tracing/trace-details-webview.ts +++ b/workspaces/ballerina/ballerina-extension/src/features/tracing/trace-details-webview.ts @@ -18,10 +18,17 @@ import * as vscode from 'vscode'; import * as path from 'path'; +import * as os from 'os'; +import * as fs from 'fs'; +import * as crypto from 'crypto'; import { Uri, ViewColumn, Webview } from 'vscode'; import { extension } from '../../BalExtensionContext'; -import { Trace } from './trace-server'; +import { Trace, TraceServer } from './trace-server'; import { getLibraryWebViewContent, getComposerWebViewOptions, WebViewOptions } from '../../utils/webview-utils'; +import { convertTraceToEvalset, convertTracesToEvalset } from './trace-converter'; +import { EvalThread, EvalSet } from '@wso2/ballerina-core'; +import { getCurrentProjectRoot } from '../../utils/project-utils'; +import { ensureEvalsetsDirectory, validateEvalsetName, findExistingEvalsets } from '../test-explorer/evalset-utils'; // TraceData interface matching the trace-visualizer component interface TraceData { @@ -66,11 +73,15 @@ export class TraceDetailsWebview { private _disposables: vscode.Disposable[] = []; private _trace: Trace | undefined; private _isAgentChat: boolean = false; + private _focusSpanId: string | undefined; + private _sessionId: string | undefined; + private _traceUpdateUnsubscribe: (() => void) | undefined; private constructor() { this._panel = TraceDetailsWebview.createWebview(); this._panel.onDidDispose(() => this.dispose(), null, this._disposables); this.setupMessageHandler(); + this.subscribeToTraceUpdates(); } private setupMessageHandler(): void { @@ -79,7 +90,7 @@ export class TraceDetailsWebview { } this._panel.webview.onDidReceiveMessage( - (message) => { + async (message) => { switch (message.command) { case 'requestTraceData': if (this._trace) { @@ -88,9 +99,36 @@ export class TraceDetailsWebview { command: 'traceData', data: traceData, isAgentChat: this._isAgentChat, + focusSpanId: this._focusSpanId, + sessionId: this._sessionId, }); } break; + case 'exportTrace': + if (message.data) { + await this.exportTrace(message.data); + } + break; + case 'requestSessionTraces': + if (message.sessionId) { + await this.handleSessionTracesRequest(message.sessionId); + } + break; + case 'exportSession': + if (message.data) { + await this.exportSession(message.data.sessionTraces, message.data.sessionId); + } + break; + case 'exportTraceAsEvalset': + if (message.data) { + await this.exportTraceAsEvalset(message.data); + } + break; + case 'exportSessionAsEvalset': + if (message.data) { + await this.exportSessionAsEvalset(message.data.sessionTraces, message.data.sessionId); + } + break; } }, null, @@ -98,11 +136,41 @@ export class TraceDetailsWebview { ); } + private subscribeToTraceUpdates(): void { + this._traceUpdateUnsubscribe = TraceServer.onTracesUpdated(() => { + if (!this._trace && this._sessionId && this._panel) { + this.refreshSessionTraces(); + } + }); + } + + private async refreshSessionTraces(): Promise { + if (!this._sessionId || !this._panel) { + return; + } + + try { + const sessionTraces = TraceServer.getTracesBySessionId(this._sessionId); + const traces = sessionTraces.map(trace => this.convertTraceToTraceData(trace)); + + // Send updated traces to the webview with isUpdate flag + // This prevents forcing the view mode change on updates + this._panel.webview.postMessage({ + command: 'sessionTraces', + traces, + sessionId: this._sessionId, + isUpdate: true + }); + } catch (error) { + console.error('Failed to refresh session traces:', error); + } + } + private static createWebview(): vscode.WebviewPanel { const panel = vscode.window.createWebviewPanel( 'ballerina.trace-details', 'Trace Details', - ViewColumn.Active, + ViewColumn.One, { enableScripts: true, localResourceRoots: [ @@ -119,7 +187,7 @@ export class TraceDetailsWebview { return panel; } - public static show(trace: Trace, isAgentChat: boolean = false): void { + public static show(trace: Trace, isAgentChat: boolean = false, focusSpanId?: string, sessionId?: string): void { if (!TraceDetailsWebview.instance || !TraceDetailsWebview.instance._panel) { // Create new instance if it doesn't exist or was disposed TraceDetailsWebview.instance = new TraceDetailsWebview(); @@ -129,18 +197,39 @@ export class TraceDetailsWebview { const instance = TraceDetailsWebview.instance; instance._trace = trace; instance._isAgentChat = isAgentChat; + instance._focusSpanId = focusSpanId; + instance._sessionId = sessionId; // Update title based on isAgentChat flag if (instance._panel) { - instance._panel.title = isAgentChat ? 'Agent Chat Logs' : 'Trace Details'; + instance._panel.title = 'Trace Logs'; + } + + vscode.commands.executeCommand('workbench.action.closeSidebar'); + + instance._panel!.reveal(ViewColumn.One); + instance.updateWebview(); + } + + public static async showSessionOverview(sessionId: string): Promise { + // Create or reuse webview instance + if (!TraceDetailsWebview.instance || !TraceDetailsWebview.instance._panel) { + TraceDetailsWebview.instance = new TraceDetailsWebview(); } - instance._panel!.reveal(); + const instance = TraceDetailsWebview.instance; + instance._trace = null; + instance._isAgentChat = true; + instance._sessionId = sessionId; + + vscode.commands.executeCommand('workbench.action.closeSidebar'); + + instance._panel!.reveal(ViewColumn.One); instance.updateWebview(); } private updateWebview(): void { - if (!this._panel || !this._trace) { + if (!this._panel) { return; } @@ -148,11 +237,13 @@ export class TraceDetailsWebview { // Send trace data immediately after updating HTML (in case webview is already loaded) // The webview will also request it if needed - const traceData = this.convertTraceToTraceData(this._trace); + const traceData = this._trace ? this.convertTraceToTraceData(this._trace) : null; this._panel.webview.postMessage({ command: 'traceData', data: traceData, isAgentChat: this._isAgentChat, + focusSpanId: this._focusSpanId, + sessionId: this._sessionId }); } @@ -183,7 +274,453 @@ export class TraceDetailsWebview { }; } - private getWebviewContent(trace: Trace, webView: Webview): string { + private async exportTrace(traceData: TraceData): Promise { + try { + const fileName = `trace-${traceData.traceId}.json`; + // Default to ./traces inside the first workspace folder; fallback to home directory + const wf = vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders[0]; + let defaultUri: vscode.Uri; + + if (wf) { + const tracesDirPath = path.join(wf.uri.fsPath, 'traces'); + const tracesDirUri = vscode.Uri.file(tracesDirPath); + try { + // Ensure the traces directory exists (create if missing) + await vscode.workspace.fs.createDirectory(tracesDirUri); + } catch (e) { + // Ignore errors and fall back to workspace root below + } + + defaultUri = vscode.Uri.file(path.join(tracesDirPath, fileName)); + } else { + defaultUri = vscode.Uri.file(path.join(os.homedir(), fileName)); + } + + const fileUri = await vscode.window.showSaveDialog({ + defaultUri, + filters: { + 'JSON Files': ['json'], + 'All Files': ['*'] + } + }); + + if (fileUri) { + const jsonContent = JSON.stringify(traceData, null, 2); + await vscode.workspace.fs.writeFile(fileUri, Buffer.from(jsonContent, 'utf8')); + vscode.window.showInformationMessage(`Trace exported to ${fileUri.fsPath}`); + } + } catch (error) { + vscode.window.showErrorMessage(`Failed to export trace: ${error}`); + } + } + + private async handleSessionTracesRequest(sessionId: string): Promise { + try { + const sessionTraces = TraceServer.getTracesBySessionId(sessionId); + + // Convert to TraceData format + const traces = sessionTraces.map(trace => this.convertTraceToTraceData(trace)); + + // Send to webview + this._panel?.webview.postMessage({ + command: 'sessionTraces', + traces, + sessionId + }); + } catch (error) { + vscode.window.showErrorMessage(`Failed to fetch session traces: ${error}`); + } + } + + private async exportSession(sessionTraces: TraceData[], sessionId: string): Promise { + try { + const fileName = `session-${sessionId}.json`; + const wf = vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders[0]; + let defaultUri: vscode.Uri; + + if (wf) { + const tracesDirPath = path.join(wf.uri.fsPath, 'traces'); + const tracesDirUri = vscode.Uri.file(tracesDirPath); + try { + await vscode.workspace.fs.createDirectory(tracesDirUri); + } catch (e) { + // Ignore errors + } + + defaultUri = vscode.Uri.file(path.join(tracesDirPath, fileName)); + } else { + defaultUri = vscode.Uri.file(path.join(os.homedir(), fileName)); + } + + const fileUri = await vscode.window.showSaveDialog({ + defaultUri, + filters: { + 'JSON Files': ['json'], + 'All Files': ['*'] + } + }); + + if (fileUri) { + const jsonContent = JSON.stringify({ + sessionId, + traces: sessionTraces + }, null, 2); + await vscode.workspace.fs.writeFile(fileUri, Buffer.from(jsonContent, 'utf8')); + vscode.window.showInformationMessage(`Session exported to ${fileUri.fsPath}`); + } + } catch (error) { + vscode.window.showErrorMessage(`Failed to export session: ${error}`); + } + } + + private async exportTraceAsEvalset(traceData: TraceData): Promise { + const mode = await this.promptExportMode(); + if (!mode) { return; } + + if (mode === 'new') { + await this.createNewEvalsetFromTrace(traceData); + } else { + await this.appendTraceToExistingEvalset(traceData); + } + } + + /** + * Creates thread from traces + */ + private createThreadFromTraces( + sessionTraces: TraceData[], + sessionId: string, + threadName?: string + ): EvalThread { + const evalsetTraces = convertTracesToEvalset(sessionTraces); + + return { + id: crypto.randomUUID(), + name: threadName || `Thread - ${sessionId.substring(0, 8)}`, + traces: evalsetTraces, + created_on: new Date().toISOString() + }; + } + + /** + * Creates thread from a single trace + */ + private createThreadFromTrace( + traceData: TraceData, + threadName?: string + ): EvalThread { + const evalsetTrace = convertTraceToEvalset(traceData); + + return { + id: crypto.randomUUID(), + name: threadName || `Thread - ${traceData.traceId.substring(0, 8)}`, + traces: [evalsetTrace], + created_on: new Date().toISOString() + }; + } + + /** + * Prompt for export mode (new vs append) + */ + private async promptExportMode(): Promise<'new' | 'append' | undefined> { + const mode = await vscode.window.showQuickPick([ + { label: 'Create new evalset', value: 'new' as const }, + { label: 'Append to existing evalset', value: 'append' as const } + ], { + placeHolder: 'How would you like to export this session?' + }); + + return mode?.value; + } + + /** + * Creates a new evalset + */ + private async createNewEvalset( + sessionTraces: TraceData[], + sessionId: string + ): Promise { + try { + // 1. Ensure evalsets directory exists + const evalsetsDir = await ensureEvalsetsDirectory(); + + // 2. Prompt for name + const name = await vscode.window.showInputBox({ + prompt: 'Enter evalset name', + placeHolder: `session-${sessionId.substring(0, 8)}`, + value: `session-${sessionId.substring(0, 8)}`, + validateInput: (value) => validateEvalsetName(value, evalsetsDir) + }); + + if (!name) { return; } // User cancelled + + // 3. Create EvalSet with single thread + const thread = this.createThreadFromTraces(sessionTraces, sessionId); + const evalset: EvalSet = { + id: crypto.randomUUID(), + name: name, + description: `Session export`, + threads: [thread], + created_on: new Date().toISOString() + }; + + // 4. Write file + const filePath = path.join(evalsetsDir, `${name}.evalset.json`); + const jsonContent = JSON.stringify(evalset, null, 2); + const fileUri = vscode.Uri.file(filePath); + + await vscode.workspace.fs.writeFile(fileUri, Buffer.from(jsonContent, 'utf8')); + + // 5. Success message with View option + const action = await vscode.window.showInformationMessage( + `Evalset created: ${name}.evalset.json`, + 'View' + ); + + if (action === 'View') { + vscode.commands.executeCommand('ballerina.openEvalsetViewer', fileUri, thread.id); + } + + } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error); + vscode.window.showErrorMessage(`Failed to create evalset: ${errorMessage}`); + } + } + + /** + * Creates a new evalset from a single trace + */ + private async createNewEvalsetFromTrace( + traceData: TraceData + ): Promise { + try { + // 1. Ensure evalsets directory exists + const evalsetsDir = await ensureEvalsetsDirectory(); + + // 2. Prompt for name + const name = await vscode.window.showInputBox({ + prompt: 'Enter evalset name', + placeHolder: `trace-${traceData.traceId.substring(0, 8)}`, + value: `trace-${traceData.traceId.substring(0, 8)}`, + validateInput: (value) => validateEvalsetName(value, evalsetsDir) + }); + + if (!name) { return; } // User cancelled + + // 3. Create EvalSet with single thread + const thread = this.createThreadFromTrace(traceData); + const evalset: EvalSet = { + id: crypto.randomUUID(), + name: name, + description: `Single trace export`, + threads: [thread], + created_on: new Date().toISOString() + }; + + // 4. Write file + const filePath = path.join(evalsetsDir, `${name}.evalset.json`); + const jsonContent = JSON.stringify(evalset, null, 2); + const fileUri = vscode.Uri.file(filePath); + + await vscode.workspace.fs.writeFile(fileUri, Buffer.from(jsonContent, 'utf8')); + + // 5. Success message with View option + const action = await vscode.window.showInformationMessage( + `Evalset created: ${name}.evalset.json`, + 'View' + ); + + if (action === 'View') { + vscode.commands.executeCommand('ballerina.openEvalsetViewer', fileUri, thread.id); + } + + } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error); + vscode.window.showErrorMessage(`Failed to create evalset: ${errorMessage}`); + } + } + + /** + * Appends a single trace to an existing evalset as a new thread + */ + private async appendTraceToExistingEvalset( + traceData: TraceData + ): Promise { + try { + // 1. Ensure evalsets directory and find files + const evalsetsDir = await ensureEvalsetsDirectory(); + const existingEvalsets = await findExistingEvalsets(evalsetsDir); + + if (existingEvalsets.length === 0) { + vscode.window.showErrorMessage('No evalsets found. Create a new one first.'); + return; + } + + // 2. Select evalset + const selected = await vscode.window.showQuickPick(existingEvalsets, { + placeHolder: 'Select an evalset to append to' + }); + + if (!selected) { return; } // User cancelled + + // 3. Prompt for thread name (quick pick: auto vs custom) + const nameChoice = await vscode.window.showQuickPick([ + { label: 'Auto-generate thread name', value: 'auto' as const }, + { label: 'Enter custom thread name', value: 'custom' as const } + ], { + placeHolder: 'How would you like to name the new thread?' + }); + + if (!nameChoice) { return; } // User cancelled + + let threadName: string | undefined; + if (nameChoice.value === 'custom') { + threadName = await vscode.window.showInputBox({ + prompt: 'Enter thread name', + value: `Thread - ${traceData.traceId.substring(0, 8)}`, + placeHolder: `Thread - ${traceData.traceId.substring(0, 8)}` + }); + + if (!threadName) { return; } // User cancelled + } + + // 4. Read existing evalset + const fileUri = vscode.Uri.file(selected.filePath); + let evalset: EvalSet; + + try { + const content = await vscode.workspace.fs.readFile(fileUri); + evalset = JSON.parse(Buffer.from(content).toString('utf8')); + } catch (parseError) { + throw new Error('Invalid evalset file: corrupted or invalid JSON'); + } + + // Validate schema + if (!evalset.threads || !Array.isArray(evalset.threads)) { + throw new Error('Invalid evalset format: missing threads array'); + } + + // 5. Add new thread + const newThread = this.createThreadFromTrace(traceData, threadName); + evalset.threads.push(newThread); + + // 6. Write back + const jsonContent = JSON.stringify(evalset, null, 2); + await vscode.workspace.fs.writeFile(fileUri, Buffer.from(jsonContent, 'utf8')); + + // 7. Success message with View option + const action = await vscode.window.showInformationMessage( + `Thread added to ${selected.label}.evalset.json`, + 'View' + ); + + if (action === 'View') { + vscode.commands.executeCommand('ballerina.openEvalsetViewer', fileUri, newThread.id); + } + + } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error); + vscode.window.showErrorMessage(`Failed to append to evalset: ${errorMessage}`); + } + } + + /** + * Appends traces to an existing evalset as a new thread + */ + private async appendToExistingEvalset( + sessionTraces: TraceData[], + sessionId: string + ): Promise { + try { + // 1. Ensure evalsets directory and find files + const evalsetsDir = await ensureEvalsetsDirectory(); + const existingEvalsets = await findExistingEvalsets(evalsetsDir); + + if (existingEvalsets.length === 0) { + vscode.window.showErrorMessage('No evalsets found. Create a new one first.'); + return; + } + + // 2. Select evalset + const selected = await vscode.window.showQuickPick(existingEvalsets, { + placeHolder: 'Select an evalset to append to' + }); + + if (!selected) { return; } // User cancelled + + // 3. Prompt for thread name (quick pick: auto vs custom) + const nameChoice = await vscode.window.showQuickPick([ + { label: 'Auto-generate thread name', value: 'auto' }, + { label: 'Enter custom thread name', value: 'custom' } + ], { + placeHolder: 'How would you like to name the new thread?' + }); + + if (!nameChoice) { return; } // User cancelled + + let threadName: string | undefined; + if (nameChoice.value === 'custom') { + threadName = await vscode.window.showInputBox({ + prompt: 'Enter thread name', + value: `Thread - ${sessionId.substring(0, 8)}`, + placeHolder: `Thread - ${sessionId.substring(0, 8)}` + }); + + if (!threadName) { return; } // User cancelled + } + + // 4. Read existing evalset + const fileUri = vscode.Uri.file(selected.filePath); + let evalset: EvalSet; + + try { + const content = await vscode.workspace.fs.readFile(fileUri); + evalset = JSON.parse(Buffer.from(content).toString('utf8')); + } catch (parseError) { + throw new Error('Invalid evalset file: corrupted or invalid JSON'); + } + + // Validate schema + if (!evalset.threads || !Array.isArray(evalset.threads)) { + throw new Error('Invalid evalset format: missing threads array'); + } + + // 5. Add new thread + const newThread = this.createThreadFromTraces(sessionTraces, sessionId, threadName); + evalset.threads.push(newThread); + + // 6. Write back + const jsonContent = JSON.stringify(evalset, null, 2); + await vscode.workspace.fs.writeFile(fileUri, Buffer.from(jsonContent, 'utf8')); + + // 7. Success message with View option + const action = await vscode.window.showInformationMessage( + `Thread added to ${selected.label}.evalset.json`, + 'View' + ); + + if (action === 'View') { + vscode.commands.executeCommand('ballerina.openEvalsetViewer', fileUri, newThread.id); + } + + } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error); + vscode.window.showErrorMessage(`Failed to append to evalset: ${errorMessage}`); + } + } + + private async exportSessionAsEvalset(sessionTraces: TraceData[], sessionId: string): Promise { + const mode = await this.promptExportMode(); + if (!mode) { return; } + + if (mode === 'new') { + await this.createNewEvalset(sessionTraces, sessionId); + } else { + await this.appendToExistingEvalset(sessionTraces, sessionId); + } + } + + private getWebviewContent(trace: Trace | null, webView: Webview): string { const body = `
`; const bodyCss = ``; const styles = ` @@ -195,17 +732,54 @@ export class TraceDetailsWebview { `; const scripts = ` const vscode = acquireVsCodeApi(); + window.vscode = vscode; // Make vscode API available globally let traceData = null; let isAgentChat = false; + let focusSpanId = undefined; + let sessionId = false; + + // Expose API for React components to communicate with extension + window.traceVisualizerAPI = { + requestSessionTraces: (sessionId) => { + vscode.postMessage({ + command: 'requestSessionTraces', + sessionId: sessionId + }); + }, + exportSession: (sessionTraces, sessionId) => { + vscode.postMessage({ + command: 'exportSession', + data: { sessionTraces, sessionId } + }); + }, + exportTrace: (traceData) => { + vscode.postMessage({ + command: 'exportTrace', + data: traceData + }); + }, + exportTraceAsEvalset: (traceData) => { + vscode.postMessage({ + command: 'exportTraceAsEvalset', + data: traceData + }); + }, + exportSessionAsEvalset: (sessionTraces, sessionId) => { + vscode.postMessage({ + command: 'exportSessionAsEvalset', + data: { sessionTraces, sessionId } + }); + } + }; function renderTraceDetails() { - if (window.traceVisualizer && window.traceVisualizer.renderWebview && traceData) { + if (window.traceVisualizer && window.traceVisualizer.renderWebview) { const container = document.getElementById("webview-container"); if (container) { - window.traceVisualizer.renderWebview(traceData, isAgentChat, container); + window.traceVisualizer.renderWebview(traceData, isAgentChat, container, focusSpanId, sessionId); } - } else if (!traceData) { - // Request trace data from extension + } else if (!traceData && !sessionId) { + // Request trace data from extension only if we don't have sessionId vscode.postMessage({ command: 'requestTraceData' }); } else { console.error("TraceVisualizer not loaded"); @@ -220,11 +794,59 @@ export class TraceDetailsWebview { case 'traceData': traceData = message.data; isAgentChat = message.isAgentChat || false; + focusSpanId = message.focusSpanId; + sessionId = message.sessionId || false; renderTraceDetails(); break; } }); + // Listen for export requests from React component + window.addEventListener('exportTrace', (event) => { + if (event.detail && event.detail.traceData) { + vscode.postMessage({ + command: 'exportTrace', + data: event.detail.traceData + }); + } + }); + + // Listen for session export requests from React component + window.addEventListener('exportSession', (event) => { + if (event.detail && event.detail.sessionTraces && event.detail.currentSessionId) { + vscode.postMessage({ + command: 'exportSession', + data: { + sessionTraces: event.detail.sessionTraces, + sessionId: event.detail.currentSessionId + } + }); + } + }); + + // Listen for evalset export requests from React component + window.addEventListener('exportTraceAsEvalset', (event) => { + if (event.detail && event.detail.traceData) { + vscode.postMessage({ + command: 'exportTraceAsEvalset', + data: event.detail.traceData + }); + } + }); + + // Listen for session evalset export requests from React component + window.addEventListener('exportSessionAsEvalset', (event) => { + if (event.detail && event.detail.sessionTraces && event.detail.currentSessionId) { + vscode.postMessage({ + command: 'exportSessionAsEvalset', + data: { + sessionTraces: event.detail.sessionTraces, + sessionId: event.detail.currentSessionId + } + }); + } + }); + function loadedScript() { // Request trace data when script is loaded vscode.postMessage({ command: 'requestTraceData' }); @@ -244,6 +866,12 @@ export class TraceDetailsWebview { public dispose(): void { + // Unsubscribe from trace updates + if (this._traceUpdateUnsubscribe) { + this._traceUpdateUnsubscribe(); + this._traceUpdateUnsubscribe = undefined; + } + this._panel?.dispose(); while (this._disposables.length) { @@ -255,11 +883,10 @@ export class TraceDetailsWebview { this._panel = undefined; this._trace = undefined; - + // Clear the static instance when disposed if (TraceDetailsWebview.instance === this) { TraceDetailsWebview.instance = undefined; } } } - diff --git a/workspaces/ballerina/ballerina-extension/src/features/tracing/trace-server.ts b/workspaces/ballerina/ballerina-extension/src/features/tracing/trace-server.ts index d29a8fb1f8f..f73e3d4a9bf 100644 --- a/workspaces/ballerina/ballerina-extension/src/features/tracing/trace-server.ts +++ b/workspaces/ballerina/ballerina-extension/src/features/tracing/trace-server.ts @@ -70,6 +70,8 @@ export interface TraceServer { getTraceByLastSeen(lastSeen: Date): Trace; onTracesUpdated(callback: () => void): () => void; onTracesCleared(callback: () => void): () => void; + getTracesBySessionId(sessionId: string): Trace[]; + getSessionIds(): string[]; } @@ -339,7 +341,7 @@ app.post('/v1/traces', async (req, res) => { const extractResourceName = (resource: any): string => { if (resource.name) { return resource.name; } if (resource.attributes) { - const serviceNameAttr = resource.attributes.find((attr: any) => + const serviceNameAttr = resource.attributes.find((attr: any) => attr.key === 'service.name' || attr.key === 'service_name' ); if (serviceNameAttr) { @@ -350,7 +352,7 @@ app.post('/v1/traces', async (req, res) => { }; // Helper function to process resource attributes - const processAttributes = (attributes: any[]): Array<{key: string; value: string}> => { + const processAttributes = (attributes: any[]): Array<{ key: string; value: string }> => { if (!attributes || !Array.isArray(attributes)) { return []; } return attributes.map((attr: any) => ({ key: attr.key || '', @@ -369,7 +371,7 @@ app.post('/v1/traces', async (req, res) => { // Process resource and scope const resourceName = extractResourceName(resourceSpan.resource); const scopeName = scopeSpan.scope?.name || 'Unknown Scope'; - + traceMap.set(traceId, { spans: [], resource: { @@ -465,7 +467,7 @@ export const TraceServer: TraceServer = { resolve(); return; } - + server = app.listen(port, () => { resolve(); }); @@ -522,5 +524,29 @@ export const TraceServer: TraceServer = { onTracesCleared: (callback: () => void) => { traceEvents.on('tracesCleared', callback); return () => traceEvents.off('tracesCleared', callback); + }, + getTracesBySessionId: (sessionId: string) => { + return Array.from(traceStore.values()).filter(trace => + trace.spans.some(span => { + const conversationId = span.attributes?.find( + attr => attr.key === 'gen_ai.conversation.id' + )?.value; + return conversationId === sessionId; + }) + ); + }, + getSessionIds: () => { + const sessionIds = new Set(); + for (const trace of traceStore.values()) { + for (const span of trace.spans) { + const conversationId = span.attributes?.find( + attr => attr.key === 'gen_ai.conversation.id' + )?.value; + if (conversationId) { + sessionIds.add(conversationId); + } + } + } + return Array.from(sessionIds); } }; \ No newline at end of file diff --git a/workspaces/ballerina/ballerina-extension/src/features/tracing/trace-tree-view.ts b/workspaces/ballerina/ballerina-extension/src/features/tracing/trace-tree-view.ts index aa2bee9098f..86e8cd2cafd 100644 --- a/workspaces/ballerina/ballerina-extension/src/features/tracing/trace-tree-view.ts +++ b/workspaces/ballerina/ballerina-extension/src/features/tracing/trace-tree-view.ts @@ -120,6 +120,18 @@ export class TraceTreeDataProvider implements vscode.TreeDataProvider t.traceId === element.traceId); + if (trace) { + item.command = { + command: 'ballerina.showTraceDetails', + title: 'Show Trace Details', + arguments: [trace, element.span.spanId] + }; + } + return item; } } diff --git a/workspaces/ballerina/ballerina-extension/src/features/tryit/activator.ts b/workspaces/ballerina/ballerina-extension/src/features/tryit/activator.ts index 1752037dcd2..02132b2b7ab 100644 --- a/workspaces/ballerina/ballerina-extension/src/features/tryit/activator.ts +++ b/workspaces/ballerina/ballerina-extension/src/features/tryit/activator.ts @@ -89,7 +89,7 @@ async function openTryItView(withNotice: boolean = false, resourceMetadata?: Res // Check if service is already running BEFORE we potentially start it // This will be used to determine if we should reuse the session ID for AI Agent service - const wasServiceAlreadyRunning = await isServiceAlreadyRunning(projectPath); + let wasServiceAlreadyRunning = await isServiceAlreadyRunning(projectPath); if (withNotice) { const selection = await vscode.window.showInformationMessage( @@ -101,6 +101,8 @@ async function openTryItView(withNotice: boolean = false, resourceMetadata?: Res if (selection !== "Test") { return; } + + wasServiceAlreadyRunning = false; } else { const processesRunning = await checkBallerinaProcessRunning(projectPath); if (!processesRunning) { @@ -1192,7 +1194,6 @@ async function getProjectPathAndServices( projectPath = getProjectWorkingDirectory(root); const services = await getServiceInfo(projectPath, serviceMetadata, filePath); if (!services || services.length === 0) { - vscode.window.showInformationMessage('No services found in the integration'); return; } serviceInfos[projectPath] = services; diff --git a/workspaces/ballerina/ballerina-extension/src/rpc-managers/agent-chat/rpc-handler.ts b/workspaces/ballerina/ballerina-extension/src/rpc-managers/agent-chat/rpc-handler.ts index b92592eb749..458cec8ffb3 100644 --- a/workspaces/ballerina/ballerina-extension/src/rpc-managers/agent-chat/rpc-handler.ts +++ b/workspaces/ballerina/ballerina-extension/src/rpc-managers/agent-chat/rpc-handler.ts @@ -23,7 +23,9 @@ import { getChatMessage, getTracingStatus, showTraceView, + showSessionOverview, TraceInput, + SessionInput, getChatHistory, clearChatHistory, getAgentStatus @@ -37,6 +39,7 @@ export function registerAgentChatRpcHandlers(messenger: Messenger) { messenger.onNotification(abortChatRequest, () => rpcManger.abortChatRequest()); messenger.onRequest(getTracingStatus, () => rpcManger.getTracingStatus()); messenger.onNotification(showTraceView, (args: TraceInput) => rpcManger.showTraceView(args)); + messenger.onNotification(showSessionOverview, (args: SessionInput) => rpcManger.showSessionOverview(args)); messenger.onRequest(getChatHistory, () => rpcManger.getChatHistory()); messenger.onRequest(clearChatHistory, () => rpcManger.clearChatHistory()); messenger.onRequest(getAgentStatus, () => rpcManger.getAgentStatus()); diff --git a/workspaces/ballerina/ballerina-extension/src/rpc-managers/agent-chat/rpc-manager.ts b/workspaces/ballerina/ballerina-extension/src/rpc-managers/agent-chat/rpc-manager.ts index 031e10b92eb..4e019e1a629 100644 --- a/workspaces/ballerina/ballerina-extension/src/rpc-managers/agent-chat/rpc-manager.ts +++ b/workspaces/ballerina/ballerina-extension/src/rpc-managers/agent-chat/rpc-manager.ts @@ -20,12 +20,14 @@ import { AgentChatAPI, ChatReqMessage, ChatRespMessage, + ExecutionStep, TraceInput, TraceStatus, ChatHistoryMessage, ChatHistoryResponse, AgentStatusResponse, - ClearChatResponse + ClearChatResponse, + SessionInput } from "@wso2/ballerina-core"; import * as vscode from 'vscode'; import { extension } from '../../BalExtensionContext'; @@ -66,7 +68,6 @@ export class AgentChatRpcManager implements AgentChatAPI { this.currentAbortController = new AbortController(); const payload = { sessionId: extension.agentChatContext.chatSessionId, ...params }; - console.log('[Agent Chat] Sending message with session ID:', payload.sessionId); const response = await this.fetchTestData( extension.agentChatContext.chatEp, @@ -75,21 +76,23 @@ export class AgentChatRpcManager implements AgentChatAPI { ); if (response && response.message) { // Find trace and extract tool calls and execution steps - const trace = this.findTraceForMessage(params.message); - - const chatResponse: ChatRespMessage = { - message: response.message - }; + const trace = this.findTraceForMessage(extension.agentChatContext.chatSessionId, params.message); + const executionSteps = trace ? this.extractExecutionSteps(trace) : undefined; // Store agent response in history this.addMessageToHistory(sessionId, { type: 'message', text: response.message, isUser: false, - traceId: trace?.traceId + traceId: trace?.traceId, + executionSteps }); - resolve(chatResponse); + resolve({ + message: response.message, + traceId: trace?.traceId, + executionSteps + } as ChatRespMessage); } else { reject(new Error("Invalid response format:", response)); } @@ -101,15 +104,31 @@ export class AgentChatRpcManager implements AgentChatAPI { : "An unknown error occurred"; const sessionId = extension.agentChatContext?.chatSessionId; + let traceId: string | undefined; + let executionSteps: ExecutionStep[] | undefined; + if (sessionId) { + const trace = this.findTraceForMessage(extension.agentChatContext.chatSessionId, params.message); + traceId = trace?.traceId; + executionSteps = trace ? this.extractExecutionSteps(trace) : undefined; + this.addMessageToHistory(sessionId, { type: 'error', text: errorMessage, - isUser: false + isUser: false, + traceId, + executionSteps }); } - reject(error); + // Embed trace information in the error for RPC transmission + const traceInfo = { traceId, executionSteps }; + const errorWithTrace = new Error(JSON.stringify({ + message: errorMessage, + traceInfo: traceInfo + })); + + reject(errorWithTrace); } finally { this.currentAbortController = null; } @@ -152,6 +171,7 @@ export class AgentChatRpcManager implements AgentChatAPI { }); if (!response.ok) { + const errorData = await response.json(); switch (response.status) { case 400: throw new Error("Bad Request: The server could not understand the request."); @@ -203,13 +223,23 @@ export class AgentChatRpcManager implements AgentChatAPI { /** * Find the trace that corresponds to a chat message by matching span attributes + * @param sessionId The chat session ID * @param userMessage The user's input message * @returns The matching trace or undefined if not found */ - findTraceForMessage(userMessage: string): Trace | undefined { + findTraceForMessage(sessionId: string, userMessage: string): Trace | undefined { // Get all traces from the TraceServer const traces = TraceServer.getTraces(); + // Sort traces from most recent to least recent based on lastSeen timestamp + traces.sort((a, b) => { + const timeA = a.lastSeen.getTime(); + const timeB = b.lastSeen.getTime(); + + // Sort in descending order (most recent first) + return timeB - timeA; + }); + // Helper function to extract string value from attribute value const extractValue = (value: any): string => { if (typeof value === 'string') { @@ -229,6 +259,7 @@ export class AgentChatRpcManager implements AgentChatAPI { // 1. span.type === "ai" // 2. gen_ai.operation.name === "invoke_agent" // 3. gen_ai.input.messages matches the user message + // 4. gen_ai.output.messages matches the agent response (if provided) const attributes = span.attributes || []; @@ -236,6 +267,8 @@ export class AgentChatRpcManager implements AgentChatAPI { let spanType: string | undefined; let operationName: string | undefined; let inputMessages: string | undefined; + let outputMessages: string | undefined; + let conversationId: string | undefined; for (const attr of attributes) { const attrValue = extractValue(attr.value); @@ -246,6 +279,10 @@ export class AgentChatRpcManager implements AgentChatAPI { operationName = attrValue; } else if (attr.key === 'gen_ai.input.messages') { inputMessages = attrValue; + } else if (attr.key === 'gen_ai.output.messages') { + outputMessages = attrValue; + } else if (attr.key === 'gen_ai.conversation.id') { + conversationId = attrValue; } } @@ -253,11 +290,13 @@ export class AgentChatRpcManager implements AgentChatAPI { if (spanType === 'ai' && operationName === 'invoke_agent' && inputMessages) { + + // If sessionId doesn't match, skip + if (conversationId != sessionId) { continue; } + // Check if the input message matches - // inputMessages might be JSON or contain the message - if (inputMessages.includes(userMessage)) { - return trace; - } + const inputMatches = inputMessages.includes(userMessage); + if (inputMatches) { return trace; } } } } @@ -266,24 +305,128 @@ export class AgentChatRpcManager implements AgentChatAPI { } /** - * Show trace details webview for a given chat message - * Finds the trace matching the message and opens it in the trace details webview - * @param userMessage The user's input message - * @throws Error if no trace is found for the message + * Remove operation prefixes from span names + * @param name The span name to clean + * @returns The cleaned span name + */ + private stripSpanPrefix(name: string): string { + const prefixes = ['invoke_agent ', 'execute_tool ', 'chat ']; + for (const prefix of prefixes) { + if (name.startsWith(prefix)) { + return name.substring(prefix.length); + } + } + return name; + } + + /** + * Extract execution steps from a trace + * @param trace The trace to extract execution steps from + * @returns Array of execution steps sorted chronologically */ - async showTraceDetailsForMessage(userMessage: string): Promise { + private extractExecutionSteps(trace: Trace): ExecutionStep[] { + const steps: ExecutionStep[] = []; + + // Helper function to extract string value from attribute value + const extractValue = (value: any): string => { + if (typeof value === 'string') { + return value; + } + if (value && typeof value === 'object' && 'stringValue' in value) { + return String(value.stringValue); + } + return ''; + }; + + // Iterate through all spans in the trace + for (const span of trace.spans || []) { + const attributes = span.attributes || []; + + let operationName = ''; + let toolName = ''; + let hasError = false; + + // Extract relevant attributes + for (const attr of attributes) { + const value = extractValue(attr.value); + + if (attr.key === 'gen_ai.operation.name') { + operationName = value; + } else if (attr.key === 'gen_ai.tool.name') { + toolName = value; + } else if (attr.key === 'error.message') { + hasError = true; + } + } + + // Determine operation type based on operation name + let operationType: 'invoke' | 'chat' | 'tool' | 'other' = 'other'; + let displayName = operationName; + + if (operationName.startsWith('invoke_agent')) { + operationType = 'invoke'; + displayName = this.stripSpanPrefix(span.name); + } else if (operationName.startsWith('chat')) { + operationType = 'chat'; + displayName = this.stripSpanPrefix(span.name); + } else if (operationName.startsWith('execute_tool')) { + operationType = 'tool'; + displayName = toolName || this.stripSpanPrefix(span.name); + } else { + // Skip spans that don't match our criteria + continue; + } + + // Calculate duration from ISO timestamps + const startTimeISO = span.startTime; + const endTimeISO = span.endTime; + let duration = 0; + + if (startTimeISO && endTimeISO) { + const startMs = new Date(startTimeISO).getTime(); + const endMs = new Date(endTimeISO).getTime(); + duration = endMs - startMs; + } + + steps.push({ + spanId: span.spanId, + operationType, + name: displayName, + fullName: operationName, + duration, + startTime: startTimeISO, + endTime: endTimeISO, + hasError + }); + } + + // Sort by start time chronologically + steps.sort((a, b) => { + if (!a.startTime || !b.startTime) { return 0; } + return a.startTime.localeCompare(b.startTime); + }); + + return steps; + } + + async showTraceView(params: TraceInput): Promise { try { - // Find the trace that matches the user message - const trace = this.findTraceForMessage(userMessage); + let trace: Trace | undefined; + + // Support direct trace lookup by traceId + if (params.traceId) { + const traces = TraceServer.getTraces(); + trace = traces.find(t => t.traceId === params.traceId); + } if (!trace) { - const errorMessage = 'No trace found for the given message. Make sure tracing is enabled and the agent has processed this message.'; + const errorMessage = 'No trace found. Make sure tracing is enabled and the agent has processed this message.'; vscode.window.showErrorMessage(errorMessage); throw new Error(errorMessage); } - // Open the trace details webview with isAgentChat=true - TraceDetailsWebview.show(trace, true); + // Open the trace details webview with isAgentChat=true and optional focusSpanId + TraceDetailsWebview.show(trace, true, params.focusSpanId, extension.agentChatContext?.chatSessionId); } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Failed to show trace details'; vscode.window.showErrorMessage(`Error: ${errorMessage}`); @@ -291,8 +434,23 @@ export class AgentChatRpcManager implements AgentChatAPI { } } - async showTraceView(params: TraceInput): Promise { - await this.showTraceDetailsForMessage(params.message); + async showSessionOverview(params: SessionInput): Promise { + try { + // Use provided sessionId or fall back to current session + const sessionId = params.sessionId || extension.agentChatContext?.chatSessionId; + + if (!sessionId) { + const errorMessage = 'No active session found'; + vscode.window.showErrorMessage(errorMessage); + throw new Error(errorMessage); + } + + await TraceDetailsWebview.showSessionOverview(sessionId); + } catch (error) { + const errorMessage = error instanceof Error ? error.message : 'Failed to show session overview'; + vscode.window.showErrorMessage(`Error: ${errorMessage}`); + throw error; + } } async getChatHistory(): Promise { diff --git a/workspaces/ballerina/ballerina-extension/src/rpc-managers/ai-panel/rpc-handler.ts b/workspaces/ballerina/ballerina-extension/src/rpc-managers/ai-panel/rpc-handler.ts index 06868551057..8ea82657ac1 100644 --- a/workspaces/ballerina/ballerina-extension/src/rpc-managers/ai-panel/rpc-handler.ts +++ b/workspaces/ballerina/ballerina-extension/src/rpc-managers/ai-panel/rpc-handler.ts @@ -28,10 +28,13 @@ import { approveTask, ApproveTaskRequest, cancelConnectorSpec, + cancelConfiguration, clearChat, clearInitialPrompt, ConnectorSpecCancelRequest, ConnectorSpecRequest, + ConfigurationCancelRequest, + ConfigurationProvideRequest, createTestDirecoryIfNotExists, declineChanges, declinePlan, @@ -69,6 +72,7 @@ import { ProcessMappingParametersRequest, promptGithubAuthorize, provideConnectorSpec, + provideConfiguration, RequirementSpecification, restoreCheckpoint, RestoreCheckpointRequest, @@ -123,6 +127,8 @@ export function registerAiPanelRpcHandlers(messenger: Messenger) { messenger.onRequest(declineTask, (args: TaskDeclineRequest) => rpcManger.declineTask(args)); messenger.onRequest(provideConnectorSpec, (args: ConnectorSpecRequest) => rpcManger.provideConnectorSpec(args)); messenger.onRequest(cancelConnectorSpec, (args: ConnectorSpecCancelRequest) => rpcManger.cancelConnectorSpec(args)); + messenger.onRequest(provideConfiguration, (args: ConfigurationProvideRequest) => rpcManger.provideConfiguration(args)); + messenger.onRequest(cancelConfiguration, (args: ConfigurationCancelRequest) => rpcManger.cancelConfiguration(args)); messenger.onRequest(getChatMessages, () => rpcManger.getChatMessages()); messenger.onRequest(getCheckpoints, () => rpcManger.getCheckpoints()); messenger.onRequest(restoreCheckpoint, (args: RestoreCheckpointRequest) => rpcManger.restoreCheckpoint(args)); diff --git a/workspaces/ballerina/ballerina-extension/src/rpc-managers/ai-panel/rpc-manager.ts b/workspaces/ballerina/ballerina-extension/src/rpc-managers/ai-panel/rpc-manager.ts index 9b46f21f63c..a5bff090143 100644 --- a/workspaces/ballerina/ballerina-extension/src/rpc-managers/ai-panel/rpc-manager.ts +++ b/workspaces/ballerina/ballerina-extension/src/rpc-managers/ai-panel/rpc-manager.ts @@ -57,6 +57,8 @@ import { openChatWindowWithCommand } from "../../features/ai/data-mapper/index"; import { generateDocumentationForService } from "../../features/ai/documentation/generator"; import { generateOpenAPISpec } from "../../features/ai/openapi/index"; import { OLD_BACKEND_URL } from "../../features/ai/utils"; +import { submitFeedback as submitFeedbackUtil } from "../../features/ai/utils/feedback"; +import { sendGenerationKeptTelemetry, sendGenerationDiscardTelemetry } from "../../features/ai/utils/generation-response"; import { fetchWithAuth } from "../../features/ai/utils/ai-client"; import { getLLMDiagnosticArrayAsString } from "../../features/natural-programming/utils"; import { StateMachine, updateView } from "../../stateMachine"; @@ -92,7 +94,7 @@ export class AiPanelRpcManager implements AIPanelAPI { async getDefaultPrompt(): Promise { let defaultPrompt: AIPanelPrompt = extension.aiChatDefaultPrompt; - + // Normalize code context to use relative paths if (defaultPrompt && 'codeContext' in defaultPrompt && defaultPrompt.codeContext) { defaultPrompt = { @@ -100,7 +102,7 @@ export class AiPanelRpcManager implements AIPanelAPI { codeContext: normalizeCodeContext(defaultPrompt.codeContext) }; } - + return new Promise((resolve) => { resolve(defaultPrompt); }); @@ -236,34 +238,7 @@ export class AiPanelRpcManager implements AIPanelAPI { } async submitFeedback(content: SubmitFeedbackRequest): Promise { - return new Promise(async (resolve) => { - try { - const payload = { - feedback: content.feedbackText, - positive: content.positive, - messages: content.messages, - diagnostics: cleanDiagnosticMessages(content.diagnostics) - }; - - const response = await fetchWithAuth(`${OLD_BACKEND_URL}/feedback`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify(payload) - }); - - if (response.ok) { - resolve(true); - } else { - console.error("Failed to submit feedback"); - resolve(false); - } - } catch (error) { - console.error("Error submitting feedback:", error); - resolve(false); - } - }); + return await submitFeedbackUtil(content); } async generateOpenAPI(params: GenerateOpenAPIRequest): Promise { @@ -488,6 +463,9 @@ export class AiPanelRpcManager implements AIPanelAPI { chatStateStorage.acceptAllReviews(workspaceId, threadId); console.log("[Review Actions] Marked all under_review generations as accepted"); + // Send telemetry for generation kept + sendGenerationKeptTelemetry(latestReview.id); + // Clear affectedPackagePaths from all completed reviews to prevent stale data for (const generation of underReviewGenerations) { chatStateStorage.updateReviewState(workspaceId, threadId, generation.id, { @@ -540,6 +518,10 @@ export class AiPanelRpcManager implements AIPanelAPI { chatStateStorage.declineAllReviews(workspaceId, threadId); console.log("[Review Actions] Marked all under_review generations as declined"); + // Send telemetry for generation discard + const latestReview = underReviewGenerations[underReviewGenerations.length - 1]; + sendGenerationDiscardTelemetry(latestReview.id); + // Clear affectedPackagePaths from all completed reviews to prevent stale data for (const generation of underReviewGenerations) { chatStateStorage.updateReviewState(workspaceId, threadId, generation.id, { @@ -583,6 +565,14 @@ export class AiPanelRpcManager implements AIPanelAPI { approvalManager.resolveConnectorSpec(params.requestId, false, undefined, params.comment); } + async provideConfiguration(params: { requestId: string; configValues: Record }): Promise { + approvalManager.resolveConfiguration(params.requestId, true, params.configValues); + } + + async cancelConfiguration(params: { requestId: string; comment?: string }): Promise { + approvalManager.resolveConfiguration(params.requestId, false, undefined, params.comment); + } + async restoreCheckpoint(params: RestoreCheckpointRequest): Promise { // Get workspace and thread identifiers const workspaceId = StateMachine.context().projectPath; diff --git a/workspaces/ballerina/ballerina-extension/src/rpc-managers/bi-diagram/rpc-handler.ts b/workspaces/ballerina/ballerina-extension/src/rpc-managers/bi-diagram/rpc-handler.ts index bdd91ec0b50..dbb06022085 100644 --- a/workspaces/ballerina/ballerina-extension/src/rpc-managers/bi-diagram/rpc-handler.ts +++ b/workspaces/ballerina/ballerina-extension/src/rpc-managers/bi-diagram/rpc-handler.ts @@ -69,6 +69,7 @@ import { FunctionNodeRequest, generateOpenApiClient, getAiSuggestions, + getAvailableAgents, getAvailableChunkers, getAvailableDataLoaders, getAvailableEmbeddingProviders, @@ -151,7 +152,9 @@ import { UpdateTypesRequest, verifyTypeDelete, VerifyTypeDeleteRequest, - VisibleTypesRequest + VisibleTypesRequest, + ValidateProjectFormRequest, + validateProjectPath } from "@wso2/ballerina-core"; import { Messenger } from "vscode-messenger"; import { BiDiagramRpcManager } from "./rpc-manager"; @@ -163,6 +166,7 @@ export function registerBiDiagramRpcHandlers(messenger: Messenger) { messenger.onRequest(deleteFlowNode, (args: BISourceCodeRequest) => rpcManger.deleteFlowNode(args)); messenger.onRequest(deleteByComponentInfo, (args: BIDeleteByComponentInfoRequest) => rpcManger.deleteByComponentInfo(args)); messenger.onRequest(getAvailableNodes, (args: BIAvailableNodesRequest) => rpcManger.getAvailableNodes(args)); + messenger.onRequest(getAvailableAgents, (args: BIAvailableNodesRequest) => rpcManger.getAvailableAgents(args)); messenger.onRequest(getAvailableModelProviders, (args: BIAvailableNodesRequest) => rpcManger.getAvailableModelProviders(args)); messenger.onRequest(getAvailableVectorStores, (args: BIAvailableNodesRequest) => rpcManger.getAvailableVectorStores(args)); messenger.onRequest(getAvailableEmbeddingProviders, (args: BIAvailableNodesRequest) => rpcManger.getAvailableEmbeddingProviders(args)); @@ -173,6 +177,7 @@ export function registerBiDiagramRpcHandlers(messenger: Messenger) { messenger.onRequest(getNodeTemplate, (args: BINodeTemplateRequest) => rpcManger.getNodeTemplate(args)); messenger.onRequest(getAiSuggestions, (args: BIAiSuggestionsRequest) => rpcManger.getAiSuggestions(args)); messenger.onNotification(createProject, (args: ProjectRequest) => rpcManger.createProject(args)); + messenger.onRequest(validateProjectPath, (args: ValidateProjectFormRequest) => rpcManger.validateProjectPath(args)); messenger.onNotification(deleteProject, (args: DeleteProjectRequest) => rpcManger.deleteProject(args)); messenger.onNotification(addProjectToWorkspace, (args: AddProjectToWorkspaceRequest) => rpcManger.addProjectToWorkspace(args)); messenger.onRequest(getWorkspaces, () => rpcManger.getWorkspaces()); diff --git a/workspaces/ballerina/ballerina-extension/src/rpc-managers/bi-diagram/rpc-manager.ts b/workspaces/ballerina/ballerina-extension/src/rpc-managers/bi-diagram/rpc-manager.ts index dca33238b36..bdca95d1f0d 100644 --- a/workspaces/ballerina/ballerina-extension/src/rpc-managers/bi-diagram/rpc-manager.ts +++ b/workspaces/ballerina/ballerina-extension/src/rpc-managers/bi-diagram/rpc-manager.ts @@ -67,6 +67,8 @@ import { DeleteProjectRequest, DeleteTypeRequest, DeleteTypeResponse, + ValidateProjectFormRequest, + ValidateProjectFormResponse, DeploymentRequest, DeploymentResponse, DevantMetadata, @@ -169,7 +171,7 @@ import { BreakpointManager } from "../../features/debugger/breakpoint-manager"; import { StateMachine, updateView } from "../../stateMachine"; import { getAccessToken, getLoginMethod } from "../../utils/ai/auth"; import { getCompleteSuggestions } from '../../utils/ai/completions'; -import { README_FILE, addProjectToExistingWorkspace, convertProjectToWorkspace, createBIAutomation, createBIFunction, createBIProjectPure, createBIWorkspace, deleteProjectFromWorkspace, openInVSCode } from "../../utils/bi"; +import { README_FILE, addProjectToExistingWorkspace, convertProjectToWorkspace, createBIAutomation, createBIFunction, createBIProjectPure, createBIWorkspace, deleteProjectFromWorkspace, openInVSCode, validateProjectPath } from "../../utils/bi"; import { writeBallerinaFileDidOpen } from "../../utils/modification"; import { updateSourceCode } from "../../utils/source-utils"; import { getView } from "../../utils/state-machine-utils"; @@ -181,6 +183,31 @@ import { getCurrentBallerinaProject } from "../../utils/project-utils"; export class BiDiagramRpcManager implements BIDiagramAPI { OpenConfigTomlRequest: (params: OpenConfigTomlRequest) => Promise; + private toRawPath(input: string): string { + if (input.includes('://')) { + return Uri.parse(input).fsPath; + } + return input; + } + + private mapTempPathToOriginal(tempFilePath: string): string { + const rawPath = this.toRawPath(tempFilePath); + const context = StateMachine.context(); + const originalRoot = context.workspacePath || context.projectPath; + const workspaceId = context.projectPath; + const threadId = 'default'; + const pendingReview = chatStateStorage.getPendingReviewGeneration(workspaceId, threadId); + if (pendingReview?.reviewState?.tempProjectPath && originalRoot) { + const normalizedTempRoot = pendingReview.reviewState.tempProjectPath.replace(/\\/g, '/'); + const normalizedFilePath = rawPath.replace(/\\/g, '/'); + if (normalizedFilePath.startsWith(normalizedTempRoot)) { + const relativePath = normalizedFilePath.substring(normalizedTempRoot.length); + return originalRoot + relativePath; + } + } + return rawPath; + } + async getFlowModel(params: BIFlowModelRequest): Promise { console.log(">>> requesting bi flow model from ls", params); return new Promise((resolve) => { @@ -189,8 +216,13 @@ export class BiDiagramRpcManager implements BIDiagramAPI { // If params has all required fields, use them directly if (params?.filePath && params?.startLine && params?.endLine) { console.log(">>> using params to create request"); + let filePath = params.filePath; + // When useFileSchema is set, map temp path to original project path + if (params.useFileSchema) { + filePath = this.mapTempPathToOriginal(filePath); + } request = { - filePath: params.filePath, + filePath, startLine: params.startLine, endLine: params.endLine, forceAssign: params.forceAssign ?? true, @@ -199,7 +231,7 @@ export class BiDiagramRpcManager implements BIDiagramAPI { // Fall back to context if params are not complete console.log(">>> params incomplete, falling back to context"); const context = StateMachine.context(); - + if (!context.position) { // TODO: check why this hits when we are in review mode console.log(">>> position not found in context, cannot create request"); @@ -247,7 +279,10 @@ export class BiDiagramRpcManager implements BIDiagramAPI { const artifacts = await updateSourceCode({ textEdits: model.textEdits, description: this.getSourceDescription(params) }); resolve({ artifacts }); } else { - const artifacts = await updateSourceCode({ textEdits: model.textEdits, artifactData: this.getArtifactDataFromNodeKind(params.flowNode.codedata.node), description: this.getSourceDescription(params)}, params.isHelperPaneChange); + const nodeKind = params.flowNode.codedata.node; + const skipFormatting = nodeKind === 'DATA_MAPPER_CREATION' || nodeKind === 'FUNCTION_CREATION'; + const artifactData = params.artifactData || this.getArtifactDataFromNodeKind(nodeKind); + const artifacts = await updateSourceCode({ textEdits: model.textEdits, artifactData, description: this.getSourceDescription(params)}, params.isHelperPaneChange, skipFormatting); resolve({ artifacts }); } }) @@ -614,6 +649,10 @@ export class BiDiagramRpcManager implements BIDiagramAPI { } } + async validateProjectPath(params: ValidateProjectFormRequest): Promise { + return validateProjectPath(params.projectPath, params.projectName, params.createDirectory); + } + async deleteProject(params: DeleteProjectRequest): Promise { const projectInfo = StateMachine.context().projectInfo; const targetProject = projectInfo?.children.find((child) => child.projectPath === params.projectPath); @@ -1435,9 +1474,15 @@ export class BiDiagramRpcManager implements BIDiagramAPI { async getEnclosedFunction(params: BIGetEnclosedFunctionRequest): Promise { console.log(">>> requesting parent functin definition", params); + // When useFileSchema is set, map temp path to original project path + let filePath = params.filePath; + if (params.useFileSchema) { + filePath = this.mapTempPathToOriginal(filePath); + } + const request = { filePath, position: params.position, findClass: params.findClass }; return new Promise((resolve) => { StateMachine.langClient() - .getEnclosedFunctionDef(params) + .getEnclosedFunctionDef(request) .then((response) => { if (response?.filePath && response?.startLine && response?.endLine) { console.log(">>> parent function position ", response); @@ -1511,8 +1556,13 @@ export class BiDiagramRpcManager implements BIDiagramAPI { return new Promise((resolve) => { let projectPath: string; if (params?.projectPath) { - const uri = Uri.file(params.projectPath); - projectPath = uri.with({ scheme: 'ai' }).toString(); + if (params.useFileSchema) { + // Map temp project path to original project raw path + projectPath = this.mapTempPathToOriginal(params.projectPath); + } else { + const uri = Uri.file(params.projectPath); + projectPath = uri.with({ scheme: 'ai' }).toString(); + } } else { projectPath = StateMachine.context().projectPath; } @@ -1549,6 +1599,11 @@ export class BiDiagramRpcManager implements BIDiagramAPI { }); } + // When useFileSchema is set, map temp path to original project path + if (params.useFileSchema) { + filePath = this.mapTempPathToOriginal(filePath); + } + return new Promise((resolve, reject) => { StateMachine.langClient() .getTypes({ filePath }) @@ -2103,6 +2158,21 @@ export class BiDiagramRpcManager implements BIDiagramAPI { }); } + async getAvailableAgents(params: BIAvailableNodesRequest): Promise { + console.log(">>> requesting bi available agents from ls", params); + return new Promise((resolve) => { + StateMachine.langClient() + .getAvailableAgents(params) + .then((model) => { + console.log(">>> bi available agents from ls", model); + resolve(model); + }) + .catch((error) => { + console.log(">>> error fetching available agents from ls", error); + resolve(undefined); + }); + }); + } } export function getRepoRoot(projectRoot: string): string | undefined { diff --git a/workspaces/ballerina/ballerina-extension/src/rpc-managers/data-mapper/utils.ts b/workspaces/ballerina/ballerina-extension/src/rpc-managers/data-mapper/utils.ts index 649e782c2df..9b8e12ca60c 100644 --- a/workspaces/ballerina/ballerina-extension/src/rpc-managers/data-mapper/utils.ts +++ b/workspaces/ballerina/ballerina-extension/src/rpc-managers/data-mapper/utils.ts @@ -32,7 +32,8 @@ import { ExpandModelOptions, ExpandedDMModel, MACHINE_VIEW, - IntermediateClauseType + IntermediateClauseType, + InputCategory } from "@wso2/ballerina-core"; import { updateSourceCode, UpdateSourceCodeRequest } from "../../utils"; import { StateMachine, updateDataMapperView } from "../../stateMachine"; @@ -481,10 +482,13 @@ export function expandDMModel( */ function processInputRoots(model: DMModel): IOType[] { const inputs: IORoot[] = []; + const moduleLevelInputs: IORoot[] = []; const focusInputs: Record = {}; for (const input of model.inputs) { if (input.focusExpression && (input.isIterationVariable || input.isSeq || input.isGroupingKey)) { focusInputs[input.focusExpression] = input as IOTypeField; + } else if (isModuleLevelInput(input)) { + moduleLevelInputs.push(input); } else { inputs.push(input); } @@ -497,10 +501,45 @@ function processInputRoots(model: DMModel): IOType[] { focusInputs }; - return inputs.map(input => { + const processedInputs = inputs.map(input => { preProcessedModel.traversingRoot = input.name; return processIORoot(input, preProcessedModel); }); + + return moduleLevelInputs.length + ? [buildModuleLevelInputsGroup(moduleLevelInputs, preProcessedModel), ...processedInputs] + : processedInputs; +} + +/** + * Checks if the given input is a module level input + */ +function isModuleLevelInput(input: IORoot): boolean { + return input.category === InputCategory.Constant + || input.category === InputCategory.Configurable + || input.category === InputCategory.ModuleVariable + || input.category === InputCategory.Enum; +} + +/** + * Builds an IOType to group module level inputs + */ +function buildModuleLevelInputsGroup(moduleLevelInputs: IORoot[], model: DMModel): IOType { + + const id = "MODULE_LEVEL_INPUTS$"; // Suffix $ to avoid conflicts with user defined names and special case port handling + model.traversingRoot = id; + const fields = moduleLevelInputs.map(input => { + model.focusInputRootMap[input.name] = model.traversingRoot; + return processIORoot(input, model); + }); + + return { + id, + name: id, + displayName: "Global Inputs", + kind: TypeKind.Record, + fields + }; } /** @@ -787,4 +826,3 @@ function processEnum( ...(member.optional && { optional: member.optional }) })); } - diff --git a/workspaces/ballerina/ballerina-extension/src/rpc-managers/test-manager/rpc-handler.ts b/workspaces/ballerina/ballerina-extension/src/rpc-managers/test-manager/rpc-handler.ts index 8809c1bdbd9..eb29639dc5c 100644 --- a/workspaces/ballerina/ballerina-extension/src/rpc-managers/test-manager/rpc-handler.ts +++ b/workspaces/ballerina/ballerina-extension/src/rpc-managers/test-manager/rpc-handler.ts @@ -15,8 +15,8 @@ * specific language governing permissions and limitations * under the License. */ -import { addTestFunction, getTestFunction, GetTestFunctionRequest, - AddOrUpdateTestFunctionRequest, updateTestFunction } from "@wso2/ballerina-core"; +import { addTestFunction, getTestFunction, GetTestFunctionRequest, + AddOrUpdateTestFunctionRequest, updateTestFunction, getEvalsets, GetEvalsetsRequest } from "@wso2/ballerina-core"; import { Messenger } from "vscode-messenger"; import { TestServiceManagerRpcManager } from "./rpc-manager"; @@ -25,5 +25,6 @@ export function registerTestManagerRpcHandlers(messenger: Messenger) { messenger.onRequest(getTestFunction, (args: GetTestFunctionRequest) => rpcManger.getTestFunction(args)); messenger.onRequest(addTestFunction, (args: AddOrUpdateTestFunctionRequest) => rpcManger.addTestFunction(args)); messenger.onRequest(updateTestFunction, (args: AddOrUpdateTestFunctionRequest) => rpcManger.updateTestFunction(args)); + messenger.onRequest(getEvalsets, (args: GetEvalsetsRequest) => rpcManger.getEvalsets(args)); } diff --git a/workspaces/ballerina/ballerina-extension/src/rpc-managers/test-manager/rpc-manager.ts b/workspaces/ballerina/ballerina-extension/src/rpc-managers/test-manager/rpc-manager.ts index 40bf18f8eb5..416b216b8bc 100644 --- a/workspaces/ballerina/ballerina-extension/src/rpc-managers/test-manager/rpc-manager.ts +++ b/workspaces/ballerina/ballerina-extension/src/rpc-managers/test-manager/rpc-manager.ts @@ -24,12 +24,17 @@ import { SyntaxTree, TestManagerServiceAPI, TestSourceEditResponse, + GetEvalsetsRequest, + GetEvalsetsResponse, + EvalsetItem, } from "@wso2/ballerina-core"; import { ModulePart, NodePosition, STKindChecker } from "@wso2/syntax-tree"; import * as fs from 'fs'; import { existsSync, writeFileSync } from "fs"; import { StateMachine } from "../../stateMachine"; import { updateSourceCode } from "../../utils/source-utils"; +import * as vscode from 'vscode'; +import * as path from 'path'; export class TestServiceManagerRpcManager implements TestManagerServiceAPI { @@ -85,4 +90,50 @@ export class TestServiceManagerRpcManager implements TestManagerServiceAPI { } }); } + + async getEvalsets(params: GetEvalsetsRequest): Promise { + return new Promise(async (resolve) => { + try { + const pattern = params.projectPath + ? new vscode.RelativePattern(vscode.Uri.file(params.projectPath), '**/evalsets/**/*.evalset.json') + : '**/evalsets/**/*.evalset.json'; + const evalsetFiles = await vscode.workspace.findFiles(pattern); + const evalsets: EvalsetItem[] = []; + + for (const uri of evalsetFiles) { + try { + const content = await fs.promises.readFile(uri.fsPath, 'utf-8'); + const evalsetData = JSON.parse(content); + + // Validate the evalset structure + if (!evalsetData.threads || !Array.isArray(evalsetData.threads)) { + continue; + } + + const threadCount = evalsetData.threads.length; + const name = evalsetData.name || path.basename(uri.fsPath, '.evalset.json'); + const description = evalsetData.description || ''; + const filePath = params.projectPath + ? path.relative(params.projectPath, uri.fsPath) + : uri.fsPath; + + evalsets.push({ + id: evalsetData.id || uri.fsPath, + name: name, + filePath: filePath, + threadCount: threadCount, + description: description + }); + } catch (error) { + console.error(`Failed to parse evalset file ${uri.fsPath}:`, error); + } + } + + resolve({ evalsets }); + } catch (error) { + console.error('Failed to get evalsets:', error); + resolve({ evalsets: [] }); + } + }); + } } diff --git a/workspaces/ballerina/ballerina-extension/src/rpc-managers/visualizer/rpc-handler.ts b/workspaces/ballerina/ballerina-extension/src/rpc-managers/visualizer/rpc-handler.ts index 32b05613080..447ddcb2d94 100644 --- a/workspaces/ballerina/ballerina-extension/src/rpc-managers/visualizer/rpc-handler.ts +++ b/workspaces/ballerina/ballerina-extension/src/rpc-managers/visualizer/rpc-handler.ts @@ -26,13 +26,19 @@ import { goBack, goHome, goSelected, + handleApprovalPopupClose, + HandleApprovalPopupCloseRequest, HistoryEntry, joinProjectPath, JoinProjectPathRequest, openView, OpenViewRequest, redo, + reopenApprovalView, + ReopenApprovalViewRequest, resetUndoRedoStack, + saveEvalThread, + SaveEvalThreadRequest, undo, undoRedoState, updateCurrentArtifactLocation, @@ -59,4 +65,7 @@ export function registerVisualizerRpcHandlers(messenger: Messenger) { messenger.onRequest(getThemeKind, () => rpcManger.getThemeKind()); messenger.onRequest(updateCurrentArtifactLocation, (args: UpdatedArtifactsResponse) => rpcManger.updateCurrentArtifactLocation(args)); messenger.onNotification(reviewAccepted, () => rpcManger.reviewAccepted()); + messenger.onNotification(handleApprovalPopupClose, (args: HandleApprovalPopupCloseRequest) => rpcManger.handleApprovalPopupClose(args)); + messenger.onNotification(reopenApprovalView, (args: ReopenApprovalViewRequest) => rpcManger.reopenApprovalView(args)); + messenger.onRequest(saveEvalThread, (args: SaveEvalThreadRequest) => rpcManger.saveEvalThread(args)); } diff --git a/workspaces/ballerina/ballerina-extension/src/rpc-managers/visualizer/rpc-manager.ts b/workspaces/ballerina/ballerina-extension/src/rpc-managers/visualizer/rpc-manager.ts index 7a271dee1c2..495a374a100 100644 --- a/workspaces/ballerina/ballerina-extension/src/rpc-managers/visualizer/rpc-manager.ts +++ b/workspaces/ballerina/ballerina-extension/src/rpc-managers/visualizer/rpc-manager.ts @@ -19,6 +19,7 @@ import { AddToUndoStackRequest, ColorThemeKind, EVENT_TYPE, + HandleApprovalPopupCloseRequest, HistoryEntry, JoinProjectPathRequest, JoinProjectPathResponse, @@ -26,6 +27,9 @@ import { OpenViewRequest, PopupVisualizerLocation, ProjectStructureArtifactResponse, + ReopenApprovalViewRequest, + SaveEvalThreadRequest, + SaveEvalThreadResponse, SHARED_COMMANDS, undo, UndoRedoStateResponse, @@ -34,9 +38,11 @@ import { VisualizerLocation } from "@wso2/ballerina-core"; import fs from "fs"; +import path from "path"; import { commands, Range, Uri, window, workspace, WorkspaceEdit } from "vscode"; import { URI, Utils } from "vscode-uri"; import { notifyCurrentWebview } from "../../RPCLayer"; +import { approvalViewManager } from "../../features/ai/state/ApprovalViewManager"; import { history, openView, StateMachine, undoRedoManager, updateView } from "../../stateMachine"; import { openPopupView } from "../../stateMachinePopup"; import { ArtifactNotificationHandler, ArtifactsUpdated } from "../../utils/project-artifacts-handler"; @@ -303,4 +309,78 @@ export class VisualizerRpcManager implements VisualizerAPI { } ); } + + handleApprovalPopupClose(params: HandleApprovalPopupCloseRequest): void { + approvalViewManager.handlePopupClosed(params.requestId); + } + + reopenApprovalView(params: ReopenApprovalViewRequest): void { + approvalViewManager.reopenApprovalViewPopup(params.requestId); + } + + async saveEvalThread(params: SaveEvalThreadRequest): Promise { + try { + const { filePath, updatedEvalSet } = params; + + // Validate and canonicalize the file path to prevent path traversal attacks + const normalizedPath = path.normalize(filePath); + const resolvedPath = path.resolve(normalizedPath); + + // Get workspace folders to validate the path is within an allowed workspace + const workspaceFolders = workspace.workspaceFolders; + if (!workspaceFolders || workspaceFolders.length === 0) { + const errorMsg = 'No workspace folder is open'; + console.error('saveEvalThread error:', errorMsg); + window.showErrorMessage(`Failed to save evalset: ${errorMsg}`); + return { success: false, error: errorMsg }; + } + + // Check if the resolved path starts with any of the workspace roots + const isPathInWorkspace = workspaceFolders.some(folder => { + const workspaceRoot = folder.uri.fsPath; + const resolvedWorkspaceRoot = path.resolve(workspaceRoot); + return resolvedPath.startsWith(resolvedWorkspaceRoot + path.sep) || + resolvedPath === resolvedWorkspaceRoot; + }); + + if (!isPathInWorkspace) { + const errorMsg = `Path is outside workspace: ${resolvedPath}`; + console.error('saveEvalThread error:', errorMsg); + window.showErrorMessage(`Failed to save evalset: Path must be within workspace`); + return { success: false, error: errorMsg }; + } + + // Write the updated evalset back to the file using the validated path + await fs.promises.writeFile( + resolvedPath, + JSON.stringify(updatedEvalSet, null, 2), + 'utf-8' + ); + + // Read back the file to get fresh data + const savedContent = await fs.promises.readFile(resolvedPath, 'utf-8'); + const savedEvalSet = JSON.parse(savedContent); + + // Get the current threadId from context + const currentContext = StateMachine.context(); + const threadId = currentContext.evalsetData?.threadId; + + // Reload the view with fresh data from disk using the validated path + openView(EVENT_TYPE.OPEN_VIEW, { + view: MACHINE_VIEW.EvalsetViewer, + evalsetData: { + filePath: resolvedPath, + content: savedEvalSet, + threadId + } + }); + + window.showInformationMessage('Evalset saved successfully'); + return { success: true }; + } catch (error) { + console.error('Error saving evalset:', error); + window.showErrorMessage(`Failed to save evalset: ${error}`); + return { success: false, error: String(error) }; + } + } } diff --git a/workspaces/ballerina/ballerina-extension/src/stateMachine.ts b/workspaces/ballerina/ballerina-extension/src/stateMachine.ts index 87e89eef813..a64366f3815 100644 --- a/workspaces/ballerina/ballerina-extension/src/stateMachine.ts +++ b/workspaces/ballerina/ballerina-extension/src/stateMachine.ts @@ -310,11 +310,13 @@ const stateMachine = createMachine( type: (context, event) => event.viewLocation?.type, isGraphql: (context, event) => event.viewLocation?.isGraphql, metadata: (context, event) => event.viewLocation?.metadata, + agentMetadata: (context, event) => event.viewLocation?.agentMetadata, addType: (context, event) => event.viewLocation?.addType, dataMapperMetadata: (context, event) => event.viewLocation?.dataMapperMetadata, artifactInfo: (context, event) => event.viewLocation?.artifactInfo, rootDiagramId: (context, event) => event.viewLocation?.rootDiagramId, reviewData: (context, event) => event.viewLocation?.reviewData, + evalsetData: (context, event) => event.viewLocation?.evalsetData, isViewUpdateTransition: false }), (context, event) => notifyTreeView( @@ -375,8 +377,10 @@ const stateMachine = createMachine( position: (context, event) => event.data.position, syntaxTree: (context, event) => event.data.syntaxTree, focusFlowDiagramView: (context, event) => event.data.focusFlowDiagramView, + agentMetadata: (context, event) => event.data.agentMetadata, dataMapperMetadata: (context, event) => event.data.dataMapperMetadata, reviewData: (context, event) => event.data.reviewData, + evalsetData: (context, event) => event.data.evalsetData, isViewUpdateTransition: false }) } @@ -399,11 +403,13 @@ const stateMachine = createMachine( type: (context, event) => event.viewLocation?.type, isGraphql: (context, event) => event.viewLocation?.isGraphql, metadata: (context, event) => event.viewLocation?.metadata, + agentMetadata: (context, event) => event.viewLocation?.agentMetadata, addType: (context, event) => event.viewLocation?.addType, dataMapperMetadata: (context, event) => event.viewLocation?.dataMapperMetadata, artifactInfo: (context, event) => event.viewLocation?.artifactInfo, rootDiagramId: (context, event) => event.viewLocation?.rootDiagramId, reviewData: (context, event) => event.viewLocation?.reviewData, + evalsetData: (context, event) => event.viewLocation?.evalsetData, isViewUpdateTransition: false }), (context, event) => notifyTreeView( @@ -424,10 +430,16 @@ const stateMachine = createMachine( identifier: (context, event) => event.viewLocation.identifier, serviceType: (context, event) => event.viewLocation.serviceType, type: (context, event) => event.viewLocation?.type, + agentMetadata: (context, event) => event.viewLocation?.agentMetadata, isGraphql: (context, event) => event.viewLocation?.isGraphql, addType: (context, event) => event.viewLocation?.addType, dataMapperMetadata: (context, event) => event.viewLocation?.dataMapperMetadata, reviewData: (context, event) => event.viewLocation?.reviewData, + evalsetData: (context, event) => event.viewLocation?.evalsetData, + metadata: (context, event) => event.viewLocation?.metadata ? { + ...context.metadata, + ...event.viewLocation.metadata + } : context.metadata, isViewUpdateTransition: true }), (context, event) => notifyTreeView( @@ -652,8 +664,10 @@ const stateMachine = createMachine( type: context?.type, isGraphql: context?.isGraphql, addType: context?.addType, + agentMetadata: context?.agentMetadata, dataMapperMetadata: context?.dataMapperMetadata, - reviewData: context?.reviewData + reviewData: context?.reviewData, + evalsetData: context?.evalsetData } }); return resolve(); diff --git a/workspaces/ballerina/ballerina-extension/src/stateMachinePopup.ts b/workspaces/ballerina/ballerina-extension/src/stateMachinePopup.ts index b0506e90673..0764575e099 100644 --- a/workspaces/ballerina/ballerina-extension/src/stateMachinePopup.ts +++ b/workspaces/ballerina/ballerina-extension/src/stateMachinePopup.ts @@ -66,6 +66,7 @@ const stateMachinePopup = createMachine({ identifier: (context, event) => event.viewLocation.identifier, documentUri: (context, event) => event.viewLocation.documentUri, metadata: (context, event) => event.viewLocation.metadata, + agentMetadata: (context, event) => event.viewLocation?.agentMetadata, dataMapperMetadata: (context, event) => event.viewLocation?.dataMapperMetadata }) }, @@ -85,6 +86,7 @@ const stateMachinePopup = createMachine({ identifier: (context, event) => event.viewLocation.identifier, documentUri: (context, event) => event.viewLocation.documentUri, metadata: (context, event) => event.viewLocation.metadata, + agentMetadata: (context, event) => event.viewLocation?.agentMetadata, dataMapperMetadata: (context, event) => event.viewLocation?.dataMapperMetadata }) }, @@ -96,6 +98,7 @@ const stateMachinePopup = createMachine({ identifier: (context, event) => event.viewLocation.identifier, documentUri: (context, event) => event.viewLocation.documentUri, metadata: (context, event) => event.viewLocation.metadata, + agentMetadata: (context, event) => event.viewLocation?.agentMetadata, dataMapperMetadata: (context, event) => event.viewLocation?.dataMapperMetadata }) }, diff --git a/workspaces/ballerina/ballerina-extension/src/utils/ai/auth.ts b/workspaces/ballerina/ballerina-extension/src/utils/ai/auth.ts index ae521dc1807..ea36238dc98 100644 --- a/workspaces/ballerina/ballerina-extension/src/utils/ai/auth.ts +++ b/workspaces/ballerina/ballerina-extension/src/utils/ai/auth.ts @@ -102,7 +102,7 @@ vscode.authentication.onDidChangeSessions(async e => { await extension.context.secrets.delete('GITHUB_COPILOT_TOKEN'); await extension.context.secrets.delete('GITHUB_TOKEN'); } else { - //it could be a login(which we havent captured) or a logout + //it could be a login(which we havent captured) or a logout // vscode.window.showInformationMessage( // 'WSO2 Integrator: BI supports completions with GitHub Copilot.', // 'Login with GitHub Copilot' @@ -179,7 +179,7 @@ export const getAccessToken = async (): Promise => // Priority 2: Check stored credentials if (process.env.ANTHROPIC_API_KEY && process.env.ANTHROPIC_API_KEY.trim() !== "") { - resolve({loginMethod: LoginMethod.ANTHROPIC_KEY, secrets: {apiKey: process.env.ANTHROPIC_API_KEY.trim()}}); + resolve({ loginMethod: LoginMethod.ANTHROPIC_KEY, secrets: { apiKey: process.env.ANTHROPIC_API_KEY.trim() } }); return; } const credentials = await getAuthCredentials(); @@ -256,6 +256,26 @@ export const getAwsBedrockCredentials = async (): Promise<{ return credentials.secrets; }; +// ================================== +// Unique user identifier for BIIntel +// ================================== +export const getBiIntelId = async (): Promise => { + try { + const credentials = await getAuthCredentials(); + if (!credentials || credentials.loginMethod !== LoginMethod.BI_INTEL) { + return undefined; + } + + const { accessToken } = credentials.secrets; + const decoded = jwtDecode(accessToken); + return decoded.sub; + } catch (error) { + console.error('Error decoding JWT token:', error); + return undefined; + } +}; + + export const getRefreshedAccessToken = async (): Promise => { return new Promise(async (resolve, reject) => { const CommonReqHeaders = { @@ -324,7 +344,7 @@ export const exchangeStsToken = async (choreoStsToken: string): Promise.. + const versionMatch = ballerinaVersion.match(/(\d+\.\d+\.\d+)/); + return versionMatch ? versionMatch[1] : undefined; + } catch (error) { + debug(`Failed to extract Ballerina distribution version: ${error}`); + return undefined; + } +} + /** * Orchestrates the setup of project information * @param projectRequest - The project request containing all necessary information @@ -251,13 +327,19 @@ export function createBIProjectPure(projectRequest: ProjectRequest): string { const EMPTY = "\n"; + // Get the Ballerina distribution version + const distribution = getBallerinaDistribution(); + + // Build the distribution line if version is available + const distributionLine = distribution ? `distribution = "${distribution}"\n` : ''; + const libraryLine = projectRequest.isLibrary ? '\nlibrary = true' : ''; const ballerinaTomlContent = ` [package] org = "${finalOrgName}" name = "${finalPackageName}" version = "${finalVersion}" -title = "${integrationName}"${libraryLine} +${distributionLine}title = "${integrationName}" [build-options] sticky = true @@ -486,7 +568,12 @@ export async function createBIProjectFromMigration(params: MigrateRequest) { if (fileName === "Ballerina.toml") { content = content.replace(/name = ".*?"/, `name = "${sanitizedPackageName}"`); content = content.replace(/org = ".*?"/, `org = "${projectInfo.finalOrgName}"`); - content = content.replace(/version = ".*?"/, `version = "${projectInfo.finalVersion}"\ntitle = "${projectInfo.integrationName}"`); + + // Get the Ballerina distribution version + const distribution = getBallerinaDistribution(); + const distributionLine = distribution ? `\ndistribution = "${distribution}"` : ''; + + content = content.replace(/version = ".*?"/, `version = "${projectInfo.finalVersion}"${distributionLine}\ntitle = "${projectInfo.integrationName}"`); } writeBallerinaFileDidOpen(filePath, content || EMPTY); diff --git a/workspaces/ballerina/ballerina-extension/src/utils/source-utils.ts b/workspaces/ballerina/ballerina-extension/src/utils/source-utils.ts index d5d312c5dda..3fa703f099e 100644 --- a/workspaces/ballerina/ballerina-extension/src/utils/source-utils.ts +++ b/workspaces/ballerina/ballerina-extension/src/utils/source-utils.ts @@ -41,7 +41,7 @@ export interface UpdateSourceCodeRequest { skipUpdateViewOnTomlUpdate?: boolean; // This is used to skip updating the view on toml updates in certain scenarios. } -export async function updateSourceCode(updateSourceCodeRequest: UpdateSourceCodeRequest, isChangeFromHelperPane?: boolean): Promise { +export async function updateSourceCode(updateSourceCodeRequest: UpdateSourceCodeRequest, isChangeFromHelperPane?: boolean, skipFormatting?: boolean): Promise { try { let tomlFilesUpdated = false; StateMachine.setEditMode(); @@ -158,10 +158,13 @@ export async function updateSourceCode(updateSourceCodeRequest: UpdateSourceCode undoRedoManager?.addFileToBatch(fileUri.fsPath, formattedSource.newText, formattedSource.newText); } } + undoRedoManager?.commitBatchOperation(updateSourceCodeRequest.description ? updateSourceCodeRequest.description : (updateSourceCodeRequest.artifactData ? `Change in ${updateSourceCodeRequest.artifactData?.artifactType} ${updateSourceCodeRequest.artifactData?.identifier}` : "Update Source Code")); - // Apply all formatted changes at once - await workspace.applyEdit(formattedWorkspaceEdit); + if (!skipFormatting) { //TODO: Remove the skipFormatting flag once LS APIs are updated to give already formatted text edits + // Apply all formatted changes at once + await workspace.applyEdit(formattedWorkspaceEdit); + } // Handle missing dependencies after all changes are applied if (updateSourceCodeRequest.resolveMissingDependencies) { diff --git a/workspaces/ballerina/ballerina-extension/src/utils/toml-utils.ts b/workspaces/ballerina/ballerina-extension/src/utils/toml-utils.ts new file mode 100644 index 00000000000..f5cc1d5887e --- /dev/null +++ b/workspaces/ballerina/ballerina-extension/src/utils/toml-utils.ts @@ -0,0 +1,336 @@ +// Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com/) All Rights Reserved. + +// WSO2 LLC. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +import * as fs from "fs"; +import * as path from "path"; +import { parse, stringify } from "@iarna/toml"; + +export interface ConfigVariable { + name: string; + description: string; + type?: "string" | "int"; +} + +// Cache regex for performance +const PLACEHOLDER_REGEX = /^\$\{([A-Z_0-9]+)\}$/; + +/** + * Read all keys from Config.toml and return their status — filled or placeholder. + * Returns empty object if file doesn't exist. + */ +export function getAllConfigStatus( + configPath: string +): Record { + const status: Record = {}; + + if (!fs.existsSync(configPath)) { + return status; + } + + try { + const content = fs.readFileSync(configPath, "utf-8"); + const config = parse(content) as Record; + + function collectStatus(obj: any, prefix: string = "") { + for (const [key, value] of Object.entries(obj)) { + const fullKey = prefix ? `${prefix}.${key}` : key; + if (Array.isArray(value)) { + // Arrays of tables [[...]] or primitive arrays + value.forEach((item, index) => { + if (item !== null && typeof item === "object") { + collectStatus(item, `${fullKey}[${index}]`); + } else if (typeof item === "string" && PLACEHOLDER_REGEX.test(item)) { + status[`${fullKey}[${index}]`] = "missing"; + } else { + status[`${fullKey}[${index}]`] = "filled"; + } + }); + // Also mark the array key itself if empty + if (value.length === 0) { + status[fullKey] = "filled"; + } + } else if (value !== null && typeof value === "object") { + collectStatus(value, fullKey); + } else if (typeof value === "string" && PLACEHOLDER_REGEX.test(value)) { + status[fullKey] = "missing"; + } else { + status[fullKey] = "filled"; + } + } + } + + collectStatus(config); + } catch (error) { + console.error(`[TOML Utils] Error reading config status:`, error); + } + + return status; +} + +/** + * Create or update Config.toml with placeholder variables + */ +export function createConfigWithPlaceholders( + configPath: string, + variables: ConfigVariable[], + overwrite: boolean = false +): void { + let config: Record = {}; + + // Read existing config if exists + if (fs.existsSync(configPath)) { + try { + const content = fs.readFileSync(configPath, "utf-8"); + config = parse(content) as Record; + } catch (error) { + console.error(`[TOML Utils] Error reading existing config:`, error); + throw error; + } + } + + // Add placeholder variables (convert API_KEY to apikey) + for (const variable of variables) { + const tomlKey = toTomlKey(variable.name); + + if (!Object.prototype.hasOwnProperty.call(config, tomlKey) || overwrite) { + config[tomlKey] = `\${${variable.name}}`; + } + } + + // Write back to file + try { + const dirPath = path.dirname(configPath); + if (!fs.existsSync(dirPath)) { + fs.mkdirSync(dirPath, { recursive: true }); + } + + const tomlContent = stringify(config); + fs.writeFileSync(configPath, tomlContent, "utf-8"); + + console.log(`[TOML Utils] Created/updated Config.toml with ${variables.length} placeholder(s)`); + } catch (error) { + console.error(`[TOML Utils] Error writing config:`, error); + throw error; + } +} + +/** + * Check configuration value status - returns metadata only, never actual values + */ +export function checkConfigurationStatus( + configPath: string, + variableNames: string[] +): Record { + const status: Record = {}; + + if (!fs.existsSync(configPath)) { + for (const name of variableNames) { + status[name] = "missing"; + } + return status; + } + + try { + const content = fs.readFileSync(configPath, "utf-8"); + const config = parse(content) as Record; + + for (const name of variableNames) { + const tomlKey = toTomlKey(name); + const value = getNestedValue(config, tomlKey); + + if (value === undefined || value === null) { + status[name] = "missing"; + } else if (typeof value === "string" && value.startsWith("${")) { + status[name] = "missing"; + } else { + status[name] = "filled"; + } + } + } catch (error) { + console.error(`[TOML Utils] Error checking configuration status:`, error); + for (const name of variableNames) { + status[name] = "missing"; + } + } + + return status; +} + +/** + * Write configuration values to Config.toml - SECURITY: never logs values + */ +export function writeConfigValuesToConfig( + configPath: string, + configValues: Record, + variables?: ConfigVariable[] +): void { + let config: Record = {}; + + if (fs.existsSync(configPath)) { + try { + const content = fs.readFileSync(configPath, "utf-8"); + config = parse(content) as Record; + } catch (error) { + console.error(`[TOML Utils] Error reading config for value write:`, error); + throw error; + } + } + + // Create a map of variable types for quick lookup + const typeMap = new Map(); + if (variables) { + for (const variable of variables) { + typeMap.set(variable.name, variable.type || "string"); + } + } + + // Replace placeholders with actual values (convert API_KEY to apikey) + const intKeys = new Set(); + for (const [variableName, value] of Object.entries(configValues)) { + const tomlKey = toTomlKey(variableName); + const varType = typeMap.get(variableName) || "string"; + + // Convert value based on type + if (varType === "int") { + const intValue = parseInt(value, 10); + if (isNaN(intValue)) { + throw new Error(`Invalid integer value for ${variableName}`); + } + config[tomlKey] = intValue; + intKeys.add(tomlKey); + } else { + config[tomlKey] = value; + } + } + + try { + const dirPath = path.dirname(configPath); + if (!fs.existsSync(dirPath)) { + fs.mkdirSync(dirPath, { recursive: true }); + } + + let tomlContent = stringify(config); + + // Fix TOML integer formatting - remove underscores from integer values + // The @iarna/toml library adds underscores to large numbers for readability (e.g., 8_080) + // We need to remove them for Ballerina compatibility + for (const intKey of intKeys) { + const intValue = config[intKey]; + if (typeof intValue === 'number') { + // Replace formatted number (with underscores) with plain number + const escapedKey = intKey.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + const formattedPattern = new RegExp(`^\\s*${escapedKey}\\s*=\\s*[0-9_]+`, 'gm'); + tomlContent = tomlContent.replace(formattedPattern, `${intKey} = ${intValue}`); + } + } + + fs.writeFileSync(configPath, tomlContent, "utf-8"); + + console.log(`[TOML Utils] Updated ${Object.keys(configValues).length} configuration value(s) in Config.toml`); + } catch (error) { + console.error(`[TOML Utils] Error writing configuration values:`, error); + throw error; + } +} + +function getNestedValue(obj: any, key: string): any { + if (key.includes(".")) { + const parts = key.split("."); + let current = obj; + for (const part of parts) { + if (current && typeof current === "object") { + current = current[part]; + } else { + return undefined; + } + } + return current; + } + return obj[key]; +} + +export function validateVariableName(name: string): boolean { + return /^[A-Z_0-9]+$/.test(name); +} + +/** + * Converts configuration variable name to TOML key format + * Example: API_KEY -> apikey, DB_HOST -> dbhost + */ +export function toTomlKey(variableName: string): string { + return variableName.toLowerCase().replace(/_/g, ""); +} + +/** + * Read existing configuration values from Config.toml + * Returns actual values (to be shown in UI for editing) + */ +export function readExistingConfigValues( + configPath: string, + variableNames: string[] +): Record { + const existingValues: Record = {}; + + if (!fs.existsSync(configPath)) { + return existingValues; + } + + try { + const content = fs.readFileSync(configPath, "utf-8"); + const config = parse(content) as Record; + + for (const name of variableNames) { + const tomlKey = toTomlKey(name); + const value = getNestedValue(config, tomlKey); + + // Include the value if it exists and is not a placeholder + if (value !== undefined && value !== null) { + if (typeof value === "string") { + // Don't include placeholder values like ${VARIABLE_NAME} + if (!value.startsWith("${")) { + existingValues[name] = value; + } + } else if (typeof value === "number") { + // Convert number to string for UI display + existingValues[name] = value.toString(); + } + } + } + } catch (error) { + console.error(`[TOML Utils] Error reading existing configuration values:`, error); + } + + return existingValues; +} + +/** + * Create status metadata from configuration values - returns only fill status, never values + */ +export function createStatusMetadata( + configValues: Record +): Record { + const status: Record = {}; + + for (const [key, value] of Object.entries(configValues)) { + if (!value || value.trim() === "" || value.startsWith("${")) { + status[key] = "missing"; + } else { + status[key] = "filled"; + } + } + + return status; +} diff --git a/workspaces/ballerina/ballerina-extension/src/views/ai-panel/webview.ts b/workspaces/ballerina/ballerina-extension/src/views/ai-panel/webview.ts index a22a7f477d1..d5cf9e0489a 100644 --- a/workspaces/ballerina/ballerina-extension/src/views/ai-panel/webview.ts +++ b/workspaces/ballerina/ballerina-extension/src/views/ai-panel/webview.ts @@ -24,6 +24,7 @@ import { RPCLayer } from '../../RPCLayer'; import { extension } from '../../BalExtensionContext'; import { AIStateMachine } from './aiMachine'; import { AIMachineEventType } from '@wso2/ballerina-core'; +import { approvalManager } from '../../features/ai/state/ApprovalManager'; export class AiPanelWebview { public static currentPanel: AiPanelWebview | undefined; @@ -126,6 +127,9 @@ export class AiPanelWebview { } public dispose() { + + approvalManager.cancelAllPending("AI Panel closed"); + AiPanelWebview.currentPanel = undefined; AIStateMachine.sendEvent(AIMachineEventType.DISPOSE); this._panel?.dispose(); diff --git a/workspaces/ballerina/ballerina-extension/src/views/visualizer/webview.ts b/workspaces/ballerina/ballerina-extension/src/views/visualizer/webview.ts index 4b13946ad73..6a70e71d062 100644 --- a/workspaces/ballerina/ballerina-extension/src/views/visualizer/webview.ts +++ b/workspaces/ballerina/ballerina-extension/src/views/visualizer/webview.ts @@ -28,6 +28,8 @@ import { LANGUAGE } from "../../core"; import { CodeData, MACHINE_VIEW } from "@wso2/ballerina-core"; import { refreshDataMapper } from "../../rpc-managers/data-mapper/utils"; import { AiPanelWebview } from "../ai-panel/webview"; +import { approvalViewManager } from "../../features/ai/state/ApprovalViewManager"; +import { StateMachinePopup } from "../../stateMachinePopup"; export class VisualizerWebview { public static currentPanel: VisualizerWebview | undefined; @@ -106,8 +108,10 @@ export class VisualizerWebview { vscode.commands.executeCommand('setContext', 'isBalVisualizerActive', this._panel?.active); // Refresh the webview when becomes active const state = StateMachine.state(); + const popupState = StateMachinePopup.state(); const machineReady = typeof state === 'object' && 'viewActive' in state && state.viewActive === "viewReady"; - if (this._panel?.active && machineReady) { + const popupActive = typeof popupState === 'object' && 'open' in popupState && popupState.open === "active"; + if (this._panel?.active && machineReady && !popupActive) { sendUpdateNotificationToWebview(true); } }); @@ -281,6 +285,8 @@ export class VisualizerWebview { } public dispose() { + approvalViewManager.onVisualizerClosed(); + VisualizerWebview.currentPanel = undefined; this._panel?.dispose(); diff --git a/workspaces/ballerina/ballerina-low-code-diagram/package.json b/workspaces/ballerina/ballerina-low-code-diagram/package.json index 6deaf8a0924..14e568138e1 100644 --- a/workspaces/ballerina/ballerina-low-code-diagram/package.json +++ b/workspaces/ballerina/ballerina-low-code-diagram/package.json @@ -100,9 +100,9 @@ "tslint-react": "5.0.0", "tslint-react-hooks": "2.2.2", "typescript": "5.8.3", - "webpack": "5.99.9", + "webpack": "5.104.1", "webpack-cli": "6.0.1", - "webpack-dev-server": "5.2.1" + "webpack-dev-server": "5.2.3" }, "repository": { "type": "git", diff --git a/workspaces/ballerina/ballerina-rpc-client/src/BallerinaRpcClient.ts b/workspaces/ballerina/ballerina-rpc-client/src/BallerinaRpcClient.ts index f4cba7d1927..599835e60db 100644 --- a/workspaces/ballerina/ballerina-rpc-client/src/BallerinaRpcClient.ts +++ b/workspaces/ballerina/ballerina-rpc-client/src/BallerinaRpcClient.ts @@ -59,7 +59,9 @@ import { ProjectMigrationResult, onMigratedProject, refreshReviewMode, - onHideReviewActions + onHideReviewActions, + approvalOverlayState, + ApprovalOverlayState } from "@wso2/ballerina-core"; import { LangClientRpcClient } from "./rpc-clients/lang-client/rpc-client"; import { LibraryBrowserRpcClient } from "./rpc-clients/library-browser/rpc-client"; @@ -280,4 +282,8 @@ export class BallerinaRpcClient { onHideReviewActions(callback: () => void) { this.messenger.onNotification(onHideReviewActions, callback); } + + onApprovalOverlayState(callback: (data: ApprovalOverlayState) => void) { + this.messenger.onNotification(approvalOverlayState, callback); + } } diff --git a/workspaces/ballerina/ballerina-rpc-client/src/rpc-clients/agent-chat/rpc-client.ts b/workspaces/ballerina/ballerina-rpc-client/src/rpc-clients/agent-chat/rpc-client.ts index a188f336d61..72b02b5ff1b 100644 --- a/workspaces/ballerina/ballerina-rpc-client/src/rpc-clients/agent-chat/rpc-client.ts +++ b/workspaces/ballerina/ballerina-rpc-client/src/rpc-clients/agent-chat/rpc-client.ts @@ -25,7 +25,9 @@ import { getChatMessage, getTracingStatus, showTraceView, + showSessionOverview, TraceInput, + SessionInput, TraceStatus, ChatHistoryResponse, AgentStatusResponse, @@ -60,6 +62,10 @@ export class AgentChatRpcClient implements AgentChatAPI { return this._messenger.sendRequest(showTraceView, HOST_EXTENSION, params); } + showSessionOverview(params: SessionInput): Promise { + return this._messenger.sendRequest(showSessionOverview, HOST_EXTENSION, params); + } + getChatHistory(): Promise { return this._messenger.sendRequest(getChatHistory, HOST_EXTENSION); } diff --git a/workspaces/ballerina/ballerina-rpc-client/src/rpc-clients/ai-panel/rpc-client.ts b/workspaces/ballerina/ballerina-rpc-client/src/rpc-clients/ai-panel/rpc-client.ts index e61df942a79..8819bea3351 100644 --- a/workspaces/ballerina/ballerina-rpc-client/src/rpc-clients/ai-panel/rpc-client.ts +++ b/workspaces/ballerina/ballerina-rpc-client/src/rpc-clients/ai-panel/rpc-client.ts @@ -27,6 +27,8 @@ import { CheckpointInfo, ConnectorSpecCancelRequest, ConnectorSpecRequest, + ConfigurationCancelRequest, + ConfigurationProvideRequest, DocGenerationRequest, GenerateAgentCodeRequest, GenerateOpenAPIRequest, @@ -51,6 +53,7 @@ import { approvePlan, approveTask, cancelConnectorSpec, + cancelConfiguration, clearChat, clearInitialPrompt, createTestDirecoryIfNotExists, @@ -83,6 +86,7 @@ import { openChatWindowWithCommand, promptGithubAuthorize, provideConnectorSpec, + provideConfiguration, restoreCheckpoint, showSignInAlert, submitFeedback, @@ -247,6 +251,14 @@ export class AiPanelRpcClient implements AIPanelAPI { return this._messenger.sendRequest(cancelConnectorSpec, HOST_EXTENSION, params); } + provideConfiguration(params: ConfigurationProvideRequest): Promise { + return this._messenger.sendRequest(provideConfiguration, HOST_EXTENSION, params); + } + + cancelConfiguration(params: ConfigurationCancelRequest): Promise { + return this._messenger.sendRequest(cancelConfiguration, HOST_EXTENSION, params); + } + getChatMessages(): Promise { return this._messenger.sendRequest(getChatMessages, HOST_EXTENSION); } diff --git a/workspaces/ballerina/ballerina-rpc-client/src/rpc-clients/bi-diagram/rpc-client.ts b/workspaces/ballerina/ballerina-rpc-client/src/rpc-clients/bi-diagram/rpc-client.ts index 1e45c2e40b0..1de3365b79a 100644 --- a/workspaces/ballerina/ballerina-rpc-client/src/rpc-clients/bi-diagram/rpc-client.ts +++ b/workspaces/ballerina/ballerina-rpc-client/src/rpc-clients/bi-diagram/rpc-client.ts @@ -119,6 +119,8 @@ import { UpdateTypesRequest, UpdateTypesResponse, UpdatedArtifactsResponse, + ValidateProjectFormRequest, + ValidateProjectFormResponse, VerifyTypeDeleteRequest, VerifyTypeDeleteResponse, VisibleTypesRequest, @@ -143,6 +145,7 @@ import { formDidOpen, generateOpenApiClient, getAiSuggestions, + getAvailableAgents, getAvailableChunkers, getAvailableDataLoaders, getAvailableEmbeddingProviders, @@ -200,6 +203,7 @@ import { updateServiceClass, updateType, updateTypes, + validateProjectPath, verifyTypeDelete } from "@wso2/ballerina-core"; import { HOST_EXTENSION } from "vscode-messenger-common"; @@ -232,6 +236,10 @@ export class BiDiagramRpcClient implements BIDiagramAPI { return this._messenger.sendRequest(getAvailableNodes, HOST_EXTENSION, params); } + getAvailableAgents(params: BIAvailableNodesRequest): Promise { + return this._messenger.sendRequest(getAvailableAgents, HOST_EXTENSION, params); + } + getAvailableModelProviders(params: BIAvailableNodesRequest): Promise { return this._messenger.sendRequest(getAvailableModelProviders, HOST_EXTENSION, params); } @@ -272,6 +280,10 @@ export class BiDiagramRpcClient implements BIDiagramAPI { return this._messenger.sendNotification(createProject, HOST_EXTENSION, params); } + validateProjectPath(params: ValidateProjectFormRequest): Promise { + return this._messenger.sendRequest(validateProjectPath, HOST_EXTENSION, params); + } + deleteProject(params: DeleteProjectRequest): void { return this._messenger.sendNotification(deleteProject, HOST_EXTENSION, params); } diff --git a/workspaces/ballerina/ballerina-rpc-client/src/rpc-clients/test-manager/rpc-client.ts b/workspaces/ballerina/ballerina-rpc-client/src/rpc-clients/test-manager/rpc-client.ts index 68ef5a6f610..9c8dc050ac2 100644 --- a/workspaces/ballerina/ballerina-rpc-client/src/rpc-clients/test-manager/rpc-client.ts +++ b/workspaces/ballerina/ballerina-rpc-client/src/rpc-clients/test-manager/rpc-client.ts @@ -15,10 +15,10 @@ * specific language governing permissions and limitations * under the License. */ -import { TestManagerServiceAPI, GetTestFunctionRequest, AddOrUpdateTestFunctionRequest, - TestSourceEditResponse, GetTestFunctionResponse, - getTestFunction, addTestFunction, updateTestFunction, - SourceUpdateResponse} from "@wso2/ballerina-core"; +import { TestManagerServiceAPI, GetTestFunctionRequest, AddOrUpdateTestFunctionRequest, + TestSourceEditResponse, GetTestFunctionResponse, + getTestFunction, addTestFunction, updateTestFunction, + SourceUpdateResponse, GetEvalsetsRequest, GetEvalsetsResponse, getEvalsets} from "@wso2/ballerina-core"; import { HOST_EXTENSION } from "vscode-messenger-common"; import { Messenger } from "vscode-messenger-webview"; @@ -40,5 +40,9 @@ export class TestManagerServiceRpcClient implements TestManagerServiceAPI { updateTestFunction(params: AddOrUpdateTestFunctionRequest): Promise { return this._messenger.sendRequest(updateTestFunction, HOST_EXTENSION, params); } + + getEvalsets(params: GetEvalsetsRequest): Promise { + return this._messenger.sendRequest(getEvalsets, HOST_EXTENSION, params); + } } diff --git a/workspaces/ballerina/ballerina-rpc-client/src/rpc-clients/visualizer/rpc-client.ts b/workspaces/ballerina/ballerina-rpc-client/src/rpc-clients/visualizer/rpc-client.ts index 9e76681ec11..ae7fb14ca49 100644 --- a/workspaces/ballerina/ballerina-rpc-client/src/rpc-clients/visualizer/rpc-client.ts +++ b/workspaces/ballerina/ballerina-rpc-client/src/rpc-clients/visualizer/rpc-client.ts @@ -20,11 +20,15 @@ import { AddToUndoStackRequest, ColorThemeKind, + HandleApprovalPopupCloseRequest, HistoryEntry, JoinProjectPathRequest, JoinProjectPathResponse, OpenViewRequest, + ReopenApprovalViewRequest, ProjectStructureArtifactResponse, + SaveEvalThreadRequest, + SaveEvalThreadResponse, UndoRedoStateResponse, UpdatedArtifactsResponse, VisualizerAPI, @@ -35,10 +39,13 @@ import { goBack, goHome, goSelected, + handleApprovalPopupClose, joinProjectPath, openView, redo, + reopenApprovalView, resetUndoRedoStack, + saveEvalThread, undo, undoRedoState, updateCurrentArtifactLocation, @@ -113,4 +120,15 @@ export class VisualizerRpcClient implements VisualizerAPI { reviewAccepted(): void { return this._messenger.sendNotification(reviewAccepted, HOST_EXTENSION); } + + handleApprovalPopupClose(params: HandleApprovalPopupCloseRequest): void { + return this._messenger.sendNotification(handleApprovalPopupClose, HOST_EXTENSION, params); + } + + reopenApprovalView(params: ReopenApprovalViewRequest): void { + return this._messenger.sendNotification(reopenApprovalView, HOST_EXTENSION, params); + } + saveEvalThread(params: SaveEvalThreadRequest): Promise { + return this._messenger.sendRequest(saveEvalThread, HOST_EXTENSION, params); + } } diff --git a/workspaces/ballerina/ballerina-side-panel/package.json b/workspaces/ballerina/ballerina-side-panel/package.json index c6e09e677d2..8c63a27064d 100644 --- a/workspaces/ballerina/ballerina-side-panel/package.json +++ b/workspaces/ballerina/ballerina-side-panel/package.json @@ -30,7 +30,7 @@ "@wso2/ballerina-rpc-client": "workspace:*", "@wso2/ui-toolkit": "workspace:*", "lodash": "4.17.23", - "markdown-it": "14.1.0", + "markdown-it": "14.1.1", "prosemirror-commands": "1.7.1", "prosemirror-gapcursor": "1.4.0", "prosemirror-history": "1.5.0", diff --git a/workspaces/ballerina/ballerina-side-panel/src/components/Form/index.tsx b/workspaces/ballerina/ballerina-side-panel/src/components/Form/index.tsx index c0c95b4c22c..423ee0dff25 100644 --- a/workspaces/ballerina/ballerina-side-panel/src/components/Form/index.tsx +++ b/workspaces/ballerina/ballerina-side-panel/src/components/Form/index.tsx @@ -38,18 +38,18 @@ import { Diagnostic, LineRange, NodeKind, - NodePosition, SubPanel, SubPanelView, FormDiagnostics, FlowNode, ExpressionProperty, RecordTypeField, - Type, VisualizableField, NodeProperties, VisualizerLocation, getPrimaryInputType, + MACHINE_VIEW, + EditorDisplayMode, } from "@wso2/ballerina-core"; import { FormContext, Provider } from "../../context"; import { @@ -496,60 +496,66 @@ export const Form = forwardRef((props: FormProps) => { formFields.forEach((field) => { // Only set field defaults if no existing value is present if (defaultValues[field.key] === undefined) { - if (field.hidden) { - defaultValues[field.key] = field.value; - } else if (isDropdownField(field)) { - defaultValues[field.key] = getValueForDropdown(field) ?? ""; - } else if (field.type === "FLAG" && field.types?.length > 1) { - defaultValues[field.key] = String(field.value === "true") || String((typeof field.value === "boolean" && field.value)); - } else if (field.type === "FLAG") { - defaultValues[field.key] = field.value || "true"; - } else if (typeof field.value === "string") { - defaultValues[field.key] = formatJSONLikeString(field.value) ?? ""; - } else { - defaultValues[field.key] = field.value ?? ""; - } - if (field.key === "variable") { - defaultValues[field.key] = formValues[field.key] ?? defaultValues[field.key] ?? ""; - } - if (field.key === "parameters" && field.value.length === 0) { - defaultValues[field.key] = formValues[field.key] ?? []; - } + if (field.hidden) { + defaultValues[field.key] = field.value; + } else if (isDropdownField(field)) { + defaultValues[field.key] = getValueForDropdown(field) ?? ""; + } else if (field.type === "FLAG" && field.types?.length > 1) { + if (field.value && typeof field.value === "boolean") { + defaultValues[field.key] = String(field.value); + } + else { + defaultValues[field.key] = field.value; + } + } else if (field.type === "FLAG") { + defaultValues[field.key] = field.value || "true"; + } else if (typeof field.value === "string") { + defaultValues[field.key] = formatJSONLikeString(field.value) ?? ""; + } else { + defaultValues[field.key] = field.value ?? ""; + } + if (field.key === "variable") { + defaultValues[field.key] = formValues[field.key] ?? defaultValues[field.key] ?? ""; + } + if (field.key === "parameters" && field.value.length === 0) { + defaultValues[field.key] = formValues[field.key] ?? []; + } - if (field.key === "type") { - // Handle the case where the type is changed via 'Add Type' - const existingType = formValues[field.key]; - const newType = field.value; + if (field.key === "type") { + // Handle the case where the type is changed via 'Add Type' + const existingType = formValues[field.key]; + const newType = field.value; - if (existingType !== newType) { - setValue(field.key, newType); - getVisualiableFields(); + if (existingType !== newType) { + setValue(field.key, newType); + getVisualiableFields(); + } } - } - // Handle choice fields and their properties - if (field?.choices && field.choices.length > 0) { - // Get the selected choice index (default to 0 if not set) - const selectedChoiceIndex = formValues[field.key] !== undefined ? Number(formValues[field.key]) : 0; + // Handle choice fields and their properties + if (field?.choices && field.choices.length > 0) { + // Get the selected choice index (default to 0 if not set) + const selectedChoiceIndex = formValues[field.key] !== undefined ? Number(formValues[field.key]) : 0; - const selectedChoice = field.choices[selectedChoiceIndex]; + const selectedChoice = field.choices[selectedChoiceIndex]; - if (selectedChoice && selectedChoice?.properties) { - Object.entries(selectedChoice.properties).forEach(([propKey, propValue]) => { - // Preserve existing form values if they exist, otherwise use propValue.value - if (formValues[propKey] !== undefined && formValues[propKey] !== "") { - defaultValues[propKey] = formValues[propKey]; - } else if (propValue?.value !== undefined && defaultValues[propKey] === undefined) { - defaultValues[propKey] = propValue.value; - } + if (selectedChoice && selectedChoice?.properties) { + Object.entries(selectedChoice.properties).forEach(([propKey, propValue]) => { + // Preserve existing form values if they exist, otherwise use propValue.value + if (formValues[propKey] !== undefined && formValues[propKey] !== "") { + defaultValues[propKey] = formValues[propKey]; + } else if (propValue?.value !== undefined && defaultValues[propKey] === undefined) { + defaultValues[propKey] = propValue.value; + } - diagnosticsMap.push({ key: propKey, diagnostics: [] }); - }); + diagnosticsMap.push({ key: propKey, diagnostics: [] }); + }); + } } - } - diagnosticsMap.push({ key: field.key, diagnostics: [] }); - }}); + diagnosticsMap.push({ key: field.key, diagnostics: [] }); + } + }); setDiagnosticsInfo(diagnosticsMap); reset(defaultValues); @@ -564,24 +570,26 @@ export const Form = forwardRef((props: FormProps) => { onSubmit && onSubmit(data, dirtyFields); }; - const handleFormValidation = async (): Promise => { + const handleFormValidation = async (formData?: FormValues): Promise => { + if (!onFormValidation) { + return true; + } + setIsValidatingForm(true); - const data = getValues(); - const validationResult = await onFormValidation(data, dirtyFields); - setIsValidatingForm(false); - return validationResult; + const data = formData ?? getValues(); + + try { + const validationResult = await onFormValidation(data, dirtyFields); + return validationResult; + } finally { + setIsValidatingForm(false); + } } const handleOnBlur = async () => { onBlur?.(getValues(), dirtyFields); }; - // Expose a method to trigger the save - // useImperativeHandle(ref, () => ({ - // triggerSave: () => handleSubmit(handleOnSave)(), // Call handleSubmit with the save function - // resetForm: (values) => reset(values), - // })); - const handleOpenRecordEditor = (open: boolean, typeField?: FormField, newType?: string | NodeProperties) => { openRecordEditor?.(open, getValues(), typeField, newType); }; @@ -721,9 +729,13 @@ export const Form = forwardRef((props: FormProps) => { const expressionField = formFields.find((field) => field.key === "expression"); const targetTypeField = formFields.find((field) => field.codedata?.kind === "PARAM_FOR_TYPE_INFER"); const hasParameters = hasRequiredParameters(formFields, selectedNode) || hasOptionalParameters(formFields); - const canOpenInDataMapper = selectedNode === "VARIABLE" && + + const canOpenInDataMapper = (selectedNode === "VARIABLE" && expressionField && - visualizableField?.isDataMapped; + visualizableField?.isDataMapped) || + selectedNode === "DATA_MAPPER_CREATION"; + + const canOpenInFunctionEditor = selectedNode === "FUNCTION_CREATION"; const contextValue: FormContext = { form: { @@ -897,23 +909,50 @@ export const Form = forwardRef((props: FormProps) => { if (data.expression === '' && visualizableField?.defaultValue) { data.expression = visualizableField.defaultValue; } - return handleOnSave({ ...data, openInDataMapper: true }); + return handleOnSave({ + ...data, + editorConfig: { + view: selectedNode === "VARIABLE" ? MACHINE_VIEW.InlineDataMapper : MACHINE_VIEW.DataMapper, + displayMode: EditorDisplayMode.VIEW, + }, + }); })(); }; - const handleOnSaveClick = async () => { - setSavingButton('save'); + const handleOnOpenInFunctionEditor = () => { + setSavingButton('functionEditor'); + handleSubmit((data) => { + return handleOnSave({ + ...data, + editorConfig: { + view: MACHINE_VIEW.BIDiagram, + displayMode: EditorDisplayMode.VIEW, + }, + }); + })(); + }; - // Check for existing form errors (including pattern validation errors) - if (Object.keys(errors).length > 0) { - setSavingButton(null); - return; - } + const handleOnSaveClick = () => { + setSavingButton('save'); - const isValidForm = onFormValidation ? await handleFormValidation() : true; - if (isValidForm) { - handleSubmit(handleOnSave)(); - } + handleSubmit( + async (data) => { + try { + const isValidForm = await handleFormValidation(data); + if (!isValidForm) { + setSavingButton(null); + return; + } + handleOnSave(data); + } catch (error) { + console.error(">>> Error validating form before save", error); + setSavingButton(null); + } + }, + () => { + setSavingButton(null); + } + )(); }; const formContent = ( @@ -921,105 +960,51 @@ export const Form = forwardRef((props: FormProps) => { {actionButton && {actionButton}} {infoLabel && !compact && ( - - {stripHtmlTags(infoLabel)} - - {markdownRef.current && markdownRef.current.scrollHeight > 200 && ( - - - - {isMarkdownExpanded ? "Show Less" : "Show More"} - - - )} - - )} - {!preserveOrder && !compact && ( - - )} + + {stripHtmlTags(infoLabel)} + + {markdownRef.current && markdownRef.current.scrollHeight > 200 && ( + + + + {isMarkdownExpanded ? "Show Less" : "Show More"} + + + )} + + )} + {!preserveOrder && !compact && ( + + )} - {/* + {/* * Two rendering modes based on preserveOrder prop: * * 1. preserveOrder = true: Render all fields in original order from formFields array * 2. preserveOrder = false: Render name and type fields at the bottom, and rest at top */} - - {(() => { - const fieldsToRender = formFields - .sort((a, b) => b.groupNo - a.groupNo) - .filter((field) => field.type !== "VIEW"); - - const renderedComponents: React.ReactNode[] = []; - let renderedFieldCount = 0; - const injectedIndices = new Set(); // Track which injections have been added - - fieldsToRender.forEach((field) => { - // Check if we need to inject components before this field - if (injectedComponents) { - injectedComponents.forEach((injected) => { - if (injected.index === renderedFieldCount && !injectedIndices.has(injected.index)) { - renderedComponents.push( - - {injected.component} - - ); - injectedIndices.add(injected.index); - } - }); - } - - if (field.advanced || field.hidden) { - return; - } - // When preserveOrder is false, skip prioritized fields (they'll be rendered at bottom) - if (!preserveOrder && isPrioritizedField(field)) { - return; - } - - const updatedField = updateFormFieldWithImports(field, formImports); - renderedComponents.push( - - handleOpenRecordEditor(open, updatedField, newType)) - } - openSubPanel={handleOpenSubPanel} - subPanelView={subPanelView} - handleOnFieldFocus={handleOnFieldFocus} - autoFocus={firstEditableFieldIndex === formFields.indexOf(updatedField) && !hideSaveButton} - recordTypeFields={recordTypeFields} - onIdentifierEditingStateChange={handleIdentifierEditingStateChange} - handleOnTypeChange={handleOnTypeChange} - setSubComponentEnabled={setIsSubComponentEnabled} - handleNewTypeSelected={handleNewTypeSelected} - onBlur={handleOnBlur} - isContextTypeEditorSupported={updatedField?.isContextTypeSupported} - openFormTypeEditor={ - openFormTypeEditor && - ((open: boolean, newType?: string) => openFormTypeEditor(open, newType, updatedField)) - } - /> - {updatedField.key === "scope" && scopeFieldAddon} - - ); - renderedFieldCount++; - }); - - // Check if we need to inject components after all fields + + {(() => { + const fieldsToRender = formFields + .sort((a, b) => b.groupNo - a.groupNo) + .filter((field) => field.type !== "VIEW"); + + const renderedComponents: React.ReactNode[] = []; + let renderedFieldCount = 0; + const injectedIndices = new Set(); // Track which injections have been added + + fieldsToRender.forEach((field) => { + // Check if we need to inject components before this field if (injectedComponents) { injectedComponents.forEach((injected) => { - if (injected.index >= renderedFieldCount && !injectedIndices.has(injected.index)) { + if (injected.index === renderedFieldCount && !injectedIndices.has(injected.index)) { renderedComponents.push( {injected.component} @@ -1030,6 +1015,60 @@ export const Form = forwardRef((props: FormProps) => { }); } + if (field.advanced || field.hidden) { + return; + } + // When preserveOrder is false, skip prioritized fields (they'll be rendered at bottom) + if (!preserveOrder && isPrioritizedField(field)) { + return; + } + + const updatedField = updateFormFieldWithImports(field, formImports); + renderedComponents.push( + + handleOpenRecordEditor(open, updatedField, newType)) + } + openSubPanel={handleOpenSubPanel} + subPanelView={subPanelView} + handleOnFieldFocus={handleOnFieldFocus} + autoFocus={firstEditableFieldIndex === formFields.indexOf(updatedField) && !hideSaveButton} + recordTypeFields={recordTypeFields} + onIdentifierEditingStateChange={handleIdentifierEditingStateChange} + handleOnTypeChange={handleOnTypeChange} + setSubComponentEnabled={setIsSubComponentEnabled} + handleNewTypeSelected={handleNewTypeSelected} + onBlur={handleOnBlur} + isContextTypeEditorSupported={updatedField?.isContextTypeSupported} + openFormTypeEditor={ + openFormTypeEditor && + ((open: boolean, newType?: string) => openFormTypeEditor(open, newType, updatedField)) + } + /> + {updatedField.key === "scope" && scopeFieldAddon} + + ); + renderedFieldCount++; + }); + + // Check if we need to inject components after all fields + if (injectedComponents) { + injectedComponents.forEach((injected) => { + if (injected.index >= renderedFieldCount && !injectedIndices.has(injected.index)) { + renderedComponents.push( + + {injected.component} + + ); + injectedIndices.add(injected.index); + } + }); + } + return renderedComponents; })()} {hasAdvanceFields && ( @@ -1058,7 +1097,7 @@ export const Form = forwardRef((props: FormProps) => { name={"chevron-up"} iconSx={{ fontSize: 12 }} sx={{ height: 12 }} - />Collapsed + />Collapse )} @@ -1113,54 +1152,54 @@ export const Form = forwardRef((props: FormProps) => { })} - {!preserveOrder && (variableField || typeField || targetTypeField) && ( - - {variableField && ( - - )} - {typeField && !isInferredReturnType && ( + {!preserveOrder && (variableField || typeField || targetTypeField) && ( + + {variableField && ( + + )} + {typeField && !isInferredReturnType && ( + handleOpenRecordEditor(open, typeField, newType)) + } + handleOnFieldFocus={handleOnFieldFocus} + handleOnTypeChange={handleOnTypeChange} + recordTypeFields={recordTypeFields} + onIdentifierEditingStateChange={handleIdentifierEditingStateChange} + handleNewTypeSelected={handleNewTypeSelected} + onBlur={handleOnBlur} + + /> + )} + {targetTypeField && !targetTypeField.advanced && ( + <> handleOpenRecordEditor(open, typeField, newType)) - } + field={targetTypeField} handleOnFieldFocus={handleOnFieldFocus} - handleOnTypeChange={handleOnTypeChange} recordTypeFields={recordTypeFields} onIdentifierEditingStateChange={handleIdentifierEditingStateChange} handleNewTypeSelected={handleNewTypeSelected} + handleOnTypeChange={handleOnTypeChange} onBlur={handleOnBlur} - /> - )} - {targetTypeField && !targetTypeField.advanced && ( - <> - - {typeField && ( - - )} - - )} - - )} + )} + + )} + + )} {concertMessage && ( @@ -1199,6 +1238,17 @@ export const Form = forwardRef((props: FormProps) => { ) : submitText || "Open in Data Mapper"} } + {canOpenInFunctionEditor && ( + + )} + + + + ); + } + + if (currentStage === "error" && data.error) { + return ( + +
+ + Configuration Collection Failed +
+ + {data.error.message} + Error Code: {data.error.code} + +
+ ); + } + + if (currentStage === "done") { + return ( + +
+ + {data.message} +
+
+ ); + } + + if (currentStage === "skipped") { + return ( + +
+ + {data.message} +
+
+ ); + } + + return null; +}; diff --git a/workspaces/ballerina/ballerina-visualizer/src/views/AIPanel/styles.tsx b/workspaces/ballerina/ballerina-visualizer/src/views/AIPanel/styles.tsx index e05cab3ce56..33a7dbe2f5b 100644 --- a/workspaces/ballerina/ballerina-visualizer/src/views/AIPanel/styles.tsx +++ b/workspaces/ballerina/ballerina-visualizer/src/views/AIPanel/styles.tsx @@ -75,3 +75,26 @@ export const Badge = styled.div` export const ResetsInBadge = styled.div` font-size: 10px; `; + +export const ApprovalOverlay = styled.div` + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.5); + display: flex; + align-items: center; + justify-content: center; + z-index: 1000; + pointer-events: all; +`; + +export const OverlayMessage = styled.div` + color: var(--vscode-foreground); + font-size: 14px; + padding: 16px 24px; + background: var(--vscode-editor-background); + border: 1px solid var(--vscode-panel-border); + border-radius: 4px; +`; diff --git a/workspaces/ballerina/ballerina-visualizer/src/views/AgentChatPanel/Components/ChatInput.tsx b/workspaces/ballerina/ballerina-visualizer/src/views/AgentChatPanel/Components/ChatInput.tsx index c1c31770274..59623e9fa4d 100644 --- a/workspaces/ballerina/ballerina-visualizer/src/views/AgentChatPanel/Components/ChatInput.tsx +++ b/workspaces/ballerina/ballerina-visualizer/src/views/AgentChatPanel/Components/ChatInput.tsx @@ -20,6 +20,7 @@ import React, { useState, useRef, useEffect, forwardRef, useImperativeHandle, KeyboardEvent, useCallback } from "react"; import styled from "@emotion/styled"; +import { Icon } from "@wso2/ui-toolkit"; const Container = styled.div` width: calc(100% - 40px); @@ -246,7 +247,7 @@ const ChatInput: React.FC = ({ value = "", onSend, onStop, isLoa disabled={!inputValue.trim() && !isLoading} onClick={isLoading ? onStop : handleSend} > - + diff --git a/workspaces/ballerina/ballerina-visualizer/src/views/AgentChatPanel/Components/ChatInterface.tsx b/workspaces/ballerina/ballerina-visualizer/src/views/AgentChatPanel/Components/ChatInterface.tsx index fcf341e0f78..b61d2f20842 100644 --- a/workspaces/ballerina/ballerina-visualizer/src/views/AgentChatPanel/Components/ChatInterface.tsx +++ b/workspaces/ballerina/ballerina-visualizer/src/views/AgentChatPanel/Components/ChatInterface.tsx @@ -22,9 +22,15 @@ import React, { useState, useEffect, useRef } from "react"; import styled from "@emotion/styled"; import ChatInput from "./ChatInput"; import LoadingIndicator from "./LoadingIndicator"; +import { ExecutionTimeline } from "./ExecutionTimeline"; import { useRpcContext } from "@wso2/ballerina-rpc-client"; -import { Codicon, Icon, Button, ThemeColors } from "@wso2/ui-toolkit"; +import { Icon, Button, ThemeColors } from "@wso2/ui-toolkit"; import ReactMarkdown from "react-markdown"; +import remarkMath from 'remark-math'; +import remarkGfm from 'remark-gfm'; +import rehypeKatex from 'rehype-katex'; +import 'katex/dist/katex.min.css'; +import { ExecutionStep } from "@wso2/ballerina-core"; enum ChatMessageType { MESSAGE = "message", @@ -36,6 +42,7 @@ interface ChatMessage { text: string; isUser: boolean; traceId?: string; + executionSteps?: ExecutionStep[]; } // ---------- WATER MARK ---------- @@ -70,14 +77,14 @@ const WatermarkSubTitle = styled.div` `; // ---------- CHAT AREA ---------- -const ChatWrapper = styled.div` +export const ChatWrapper = styled.div` display: flex; flex-direction: column; height: 100vh; width: 100%; `; -const ChatContainer = styled.div` +export const ChatContainer = styled.div` position: relative; display: flex; flex-direction: column; @@ -86,36 +93,49 @@ const ChatContainer = styled.div` margin: 20px 0 32px 0; `; -const Messages = styled.div` +export const Messages = styled.div` flex: 1; overflow-y: auto; - padding: 8px 0; display: flex; flex-direction: column; gap: 8px; position: relative; z-index: 1; padding: 8px 20px; + height: 100%; + + @media (min-width: 1000px) { + padding: 8px 10%; + } + + @media (min-width: 1600px) { + padding: 8px 15%; + } + + @media (min-width: 2000px) { + padding: 8px 20%; + } `; -const MessageContainer = styled.div<{ isUser: boolean }>` +export const MessageContainer = styled.div<{ isUser: boolean }>` display: flex; align-items: flex-end; justify-content: ${({ isUser }: { isUser: boolean }) => (isUser ? "flex-end" : "flex-start")}; gap: 6px; `; -const ProfilePic = styled.div` - width: 18px; - height: 18px; +export const ProfilePic = styled.div` + padding: 4px; + border: 1px solid var(--vscode-panel-border); + background-color: var(--vscode-editor-background); border-radius: 50%; object-fit: cover; `; -const MessageBubble = styled.div<{ isUser: boolean; isError?: boolean; isLoading?: boolean }>` +export const MessageBubble = styled.div<{ isUser: boolean; isError?: boolean; isLoading?: boolean }>` position: relative; - padding: ${({ isLoading }: { isLoading?: boolean }) => (isLoading ? "10px 14px" : "0 14px")}; - max-width: 55%; + padding: ${({ isLoading }: { isLoading?: boolean }) => (isLoading ? "10px 14px" : "2px 14px")}; + max-width: 100%; align-self: ${({ isUser }: { isUser: boolean }) => (isUser ? "flex-end" : "flex-start")}; overflow-wrap: break-word; word-break: break-word; @@ -127,16 +147,26 @@ const MessageBubble = styled.div<{ isUser: boolean; isError?: boolean; isLoading content: ""; position: absolute; inset: 0; - background-color: ${({ isUser }: { isUser: boolean }) => - isUser ? "var(--vscode-button-background)" : "var(--vscode-tab-inactiveBackground)"}; - opacity: ${({ isUser }: { isUser: boolean }) => (isUser ? "0.3" : "1")}; + background-color: ${({ isUser, isError }: { isUser: boolean; isError?: boolean }) => + isError ? "var(--vscode-errorForeground)" : isUser ? "var(--vscode-button-background)" : "var(--vscode-input-background)"}; + opacity: ${({ isUser, isError }: { isUser: boolean; isError?: boolean }) => (isUser ? "0.3" : isError ? "0.05" : "1")}; border-radius: inherit; + border: 1px solid ${({ isUser }: { isUser: boolean }) => + isUser ? "var(--vscode-peekView-border)" : "var(--vscode-panel-border)"}; z-index: -1; } border-radius: ${({ isUser }: { isUser: boolean }) => (isUser ? "12px 12px 0px 12px" : "12px 12px 12px 0px")}; `; +const MessageActionsContainer = styled.div` + display: flex; + align-items: center; + gap: 12px; + margin: -4px 0 0 36px; + flex-wrap: wrap; +`; + // ---------- CHAT FOOTER ---------- const ChatFooter = styled.div` position: sticky; @@ -149,9 +179,8 @@ const ShowLogsButton = styled.button` background: none; border: none; color: var(--vscode-textLink-foreground); - font-size: 11px; - padding: 0; - margin: -4px 0 8px 24px; + font-size: 12px; + padding: 4px 0; cursor: pointer; text-decoration: none; display: inline-flex; @@ -169,9 +198,11 @@ const ChatHeader = styled.div` top: 0; display: flex; justify-content: flex-end; + align-items: center; padding: 12px 8px 8px; z-index: 2; border-bottom: 1px solid var(--vscode-panel-border); + gap: 8px; `; const ClearChatButton = styled.button` @@ -280,6 +311,19 @@ const ClearChatWarningPopup: React.FC = ({ isOpen, o ); }; +// Preprocess LaTeX delimiters to convert \(...\) and \[...\] to $...$ and $$...$$ +export function preprocessLatex(text: string): string { + if (!text || typeof text !== 'string') return text; + + // Convert display math \[...\] to $$...$$ + let processed = text.replace(/\\\[(.*?)\\\]/gs, (_, math) => `$$${math}$$`); + + // Convert inline math \(...\) to $...$ + processed = processed.replace(/\\\((.*?)\\\)/gs, (_, math) => `$${math}$`); + + return processed; +} + const ChatInterface: React.FC = () => { const { rpcClient } = useRpcContext(); const [messages, setMessages] = useState([]); @@ -289,6 +333,9 @@ const ChatInterface: React.FC = () => { const messagesEndRef = useRef(null); + // Check if we have any traces (to enable/disable Session Logs button) + const hasTraces = messages.some(msg => !msg.isUser && msg.traceId); + // Load chat history and check tracing status on mount useEffect(() => { const loadChatHistory = async () => { @@ -302,7 +349,8 @@ const ChatInterface: React.FC = () => { type: msg.type === 'error' ? ChatMessageType.ERROR : ChatMessageType.MESSAGE, text: msg.text, isUser: msg.isUser, - traceId: msg.traceId + traceId: msg.traceId, + executionSteps: msg.executionSteps })); setMessages(chatMessages); } @@ -342,15 +390,46 @@ const ChatInterface: React.FC = () => { setMessages((prev) => [ ...prev, - { type: ChatMessageType.MESSAGE, text: chatResponse.message, isUser: false }, + { + type: ChatMessageType.MESSAGE, + text: chatResponse.message, + isUser: false, + traceId: chatResponse.traceId, + executionSteps: chatResponse.executionSteps + }, ]); } catch (error) { - const errorMessage = - error && typeof error === "object" && "message" in error - ? String(error.message) - : "An unknown error occurred"; + let errorMessage = "An unknown error occurred"; + let traceId: string | undefined; + let executionSteps: ExecutionStep[] | undefined; + + // Try to parse structured error with trace information + if (error && typeof error === "object" && "message" in error) { + try { + const parsedError = JSON.parse(String(error.message)); + if (parsedError.message && parsedError.traceInfo) { + errorMessage = parsedError.message; + traceId = parsedError.traceInfo.traceId; + executionSteps = parsedError.traceInfo.executionSteps; + } else { + // Fallback to regular error message + errorMessage = String(error.message); + } + } catch (parseError) { + // If JSON parsing fails, use the original error message + errorMessage = String(error.message); + } + } + + console.error("Chat message error:", error); - setMessages((prev) => [...prev, { type: ChatMessageType.ERROR, text: errorMessage, isUser: false }]); + setMessages((prev) => [...prev, { + type: ChatMessageType.ERROR, + text: errorMessage, + isUser: false, + traceId, + executionSteps + }]); } finally { setIsLoading(false); } @@ -363,24 +442,17 @@ const ChatInterface: React.FC = () => { const handleShowLogs = async (messageIndex: number) => { try { - // Find the corresponding user message - // Look backwards from the current index to find the last user message - let userMessage = ''; - - for (let i = messageIndex - 1; i >= 0; i--) { - if (messages[i].isUser) { - userMessage = messages[i].text; - break; - } - } + // Get the trace ID from the agent's response message + const message = messages[messageIndex]; - if (!userMessage) { - console.error('Could not find user message for this response'); + if (!message || message.isUser || !message.traceId) { + console.error('No trace ID found for this message'); return; } - // Call the RPC method to show the trace view - await rpcClient.getAgentChatRpcClient().showTraceView({ message: userMessage }); + await rpcClient.getAgentChatRpcClient().showTraceView({ + traceId: message.traceId + }); } catch (error) { console.error('Failed to show trace view:', error); } @@ -409,12 +481,39 @@ const ChatInterface: React.FC = () => { setShowClearWarning(false); }; + const handleViewInTrace = async (traceId: string, spanId: string) => { + try { + await rpcClient.getAgentChatRpcClient().showTraceView({ + traceId, + focusSpanId: spanId + }); + } catch (error) { + console.error('Failed to show trace view:', error); + } + }; + + const handleShowSessionLogs = async () => { + try { + await rpcClient.getAgentChatRpcClient().showSessionOverview({}); + } catch (error) { + console.error('Failed to show session overview:', error); + } + }; + return ( {messages.length > 0 && ( +
+ {isTracingEnabled && hasTraces && ( + + + Session Logs + + )} +
- + Clear Chat
@@ -434,6 +533,13 @@ const ChatInterface: React.FC = () => { {/* Render each message */} {messages.map((msg, idx) => ( + {!msg.isUser && isTracingEnabled && msg?.executionSteps && msg.executionSteps.length > 0 && msg.traceId && ( + + )} {!msg.isUser && ( @@ -442,19 +548,24 @@ const ChatInterface: React.FC = () => { sx={{ width: 18, height: 18 }} iconSx={{ fontSize: "18px", - color: "var(--vscode-foreground)", + color: "var(--vscode-terminal-ansiBrightCyan)", cursor: "default", }} /> )} - {msg.text} + + {preprocessLatex(msg.text)} + {msg.isUser && ( - { )} - {/* Show "Show logs" button after agent responses (not user messages) */} - {!msg.isUser && isTracingEnabled && ( - handleShowLogs(idx)}> - Show logs - + {!msg.isUser && isTracingEnabled && msg.traceId && ( + + handleShowLogs(idx)} title="View trace logs for this message"> + View Logs + + )} ))} diff --git a/workspaces/ballerina/ballerina-visualizer/src/views/AgentChatPanel/Components/ExecutionTimeline.tsx b/workspaces/ballerina/ballerina-visualizer/src/views/AgentChatPanel/Components/ExecutionTimeline.tsx new file mode 100644 index 00000000000..6897432fa53 --- /dev/null +++ b/workspaces/ballerina/ballerina-visualizer/src/views/AgentChatPanel/Components/ExecutionTimeline.tsx @@ -0,0 +1,257 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { useState } from "react"; +import styled from "@emotion/styled"; +import { Codicon, Icon } from "@wso2/ui-toolkit"; +import { ExecutionStep } from "@wso2/ballerina-core"; + +interface ExecutionTimelineProps { + steps: ExecutionStep[]; + traceId: string; + onViewInTrace: (traceId: string, spanId: string) => void; +} + +const TimelineContainer = styled.div` + max-width: 600px; + margin: 12px 0 0 36px; +`; + +const TimelineTitle = styled.div` + font-size: 11px; + color: var(--vscode-descriptionForeground); + letter-spacing: 0.5px; +`; + +const TimelineHeader = styled.button` + display: flex; + align-items: center; + gap: 2px; + background: transparent; + border: none; + padding: 0; + cursor: pointer; +`; + +const ToggleIcon = styled.span<{ isOpen: boolean }>` + color: var(--vscode-descriptionForeground); + display: inline-flex; + align-items: center; + justify-content: center; + transition: transform 0.15s ease; + transform: ${(props: { isOpen: boolean }) => (props.isOpen ? "rotate(90deg)" : "rotate(0deg)")}; +`; + +const TimelineList = styled.div` + margin-top: 8px; + margin-bottom: 4px; + display: flex; + flex-direction: column; + gap: 0; +`; + +const TimelineItem = styled.div` + display: flex; + align-items: flex-start; + position: relative; + margin-bottom: 8px; + + &:last-of-type { + margin-bottom: 0; + } +`; + +const ConnectorColumn = styled.div<{ isLast: boolean }>` + width: 20px; + display: flex; + flex-direction: column; + align-items: center; + position: relative; + flex-shrink: 0; + padding-top: 4px; + + &::after { + content: ''; + position: absolute; + top: 14px; + left: 50%; + transform: translateX(-50%); + width: 1px; + height: calc(100% + 8px); + background-color: var(--vscode-panel-border); + display: ${(props: { isLast: boolean }) => props.isLast ? 'none' : 'block'}; + } +`; + +const Dot = styled.div<{ operationType: string }>` + width: 8px; + height: 8px; + border-radius: 50%; + background-color: var(--vscode-panel-border); + z-index: 1; + flex-shrink: 0; +`; + +const ContentCard = styled.div` + width: 60%; + background: var(--vscode-input-background); + border: 1px solid var(--vscode-panel-border); + border-radius: 4px; + padding: 8px 12px; + cursor: pointer; + transition: background-color 0.15s ease; + + &:hover { + background: var(--vscode-list-hoverBackground); + } +`; + +const CardContent = styled.div` + display: flex; + align-items: center; + gap: 8px; +`; + +const IconBadge = styled.div<{ operationType: string }>` + display: flex; + align-items: center; + justify-content: center; + color: ${(props: { operationType: string; }) => { + switch (props.operationType) { + case 'invoke': return 'var(--vscode-terminal-ansiCyan)'; + case 'chat': return 'var(--vscode-terminalSymbolIcon-optionForeground)'; + case 'tool': return 'var(--vscode-terminal-ansiBrightMagenta)'; + default: return 'var(--vscode-badge-foreground)'; + } + }}; + flex-shrink: 0; +`; + +const OperationLabel = styled.span<{ operationType: string }>` + font-size: 10px; + font-weight: 600; + flex-shrink: 0; +`; + +const SpanName = styled.span` + font-size: 12px; + color: var(--vscode-foreground); + flex: 1; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +`; + +const Duration = styled.span` + font-size: 11px; + color: var(--vscode-descriptionForeground); + flex-shrink: 0; + margin-left: auto; +`; + +export function ExecutionTimeline({ steps, traceId, onViewInTrace }: ExecutionTimelineProps) { + const [open, setOpen] = useState(false); + + // Filter out steps with invoke operation type + const filteredSteps = steps.filter(step => step.operationType !== 'invoke'); + + if (!filteredSteps || filteredSteps.length === 0) { + return null; + } + + const getIconName = (operationType: string) => { + switch (operationType) { + case 'invoke': return 'bi-ai-agent'; + case 'chat': return 'bi-chat'; + case 'tool': return 'bi-wrench'; + default: return 'bi-action'; + } + }; + + const getOperationLabel = (operationType: string) => { + switch (operationType) { + case 'invoke': return 'Invoke Agent'; + case 'chat': return 'Chat'; + case 'tool': return 'Execute Tool'; + default: return 'Other'; + } + }; + + const formatDuration = (ms: number) => { + if (ms < 1000) { + return `${Math.round(ms)}ms`; + } + return `${(ms / 1000).toFixed(2)}s`; + }; + + return ( + + setOpen(!open)} aria-expanded={open}> + Execution Steps ({filteredSteps.length}) + + + + + {open && ( + + {filteredSteps.map((step, index) => ( + + + + + onViewInTrace(traceId, step.spanId)} + title={step.fullName} + > + +
+ + + + + {getOperationLabel(step.operationType)} + +
+ {step.name} + {formatDuration(step.duration)} + +
+
+
+ ))} +
+ )} +
+ ); +} diff --git a/workspaces/ballerina/ballerina-visualizer/src/views/BI/AIChatAgent/AIChatAgentWizard.tsx b/workspaces/ballerina/ballerina-visualizer/src/views/BI/AIChatAgent/AIChatAgentWizard.tsx index 7bbe79a53d7..90c317b83c1 100644 --- a/workspaces/ballerina/ballerina-visualizer/src/views/BI/AIChatAgent/AIChatAgentWizard.tsx +++ b/workspaces/ballerina/ballerina-visualizer/src/views/BI/AIChatAgent/AIChatAgentWizard.tsx @@ -180,58 +180,35 @@ export function AIChatAgentWizard(props: AIChatAgentWizardProps) { console.warn("Unable to resolve Ballerina version; falling back to legacy agent generation.", error); } - // Execute for versions under 2201.13.0, or if version cannot be determined (safety fallback) - const executeForLegacyVersion = !ballerinaVersion || (() => { - const parts = ballerinaVersion.split('.'); - if (parts.length < 2) { - return true; // Can't parse properly, execute for safety - } - const majorVersion = parseInt(parts[0], 10); - const minorVersion = parseInt(parts[1], 10); - if (isNaN(majorVersion) || isNaN(minorVersion)) { - return true; // Can't parse version numbers, execute for safety - } - // Only versions < 2201.13 are legacy - if (majorVersion < 2201) { - return true; - } - if (majorVersion > 2201) { - return false; - } - return minorVersion < 13; - })(); - - if (executeForLegacyVersion) { - // Search for agent node in the current file - const agentSearchResponse = await rpcClient.getBIDiagramRpcClient().search({ - filePath: projectPath.current, - queryMap: { orgName: aiModuleOrg.current }, - searchKind: "AGENT" - }); + // Search for agent node in the current file + const agentSearchResponse = await rpcClient.getBIDiagramRpcClient().search({ + filePath: projectPath.current, + queryMap: { orgName: aiModuleOrg.current }, + searchKind: "AGENT" + }); - // Validate search response structure - if (!agentSearchResponse?.categories?.[0]?.items?.[0]) { - throw new Error('No agent node found in search response'); - } + // Validate search response structure + if (!agentSearchResponse?.categories?.[0]?.items?.[0]) { + throw new Error('No agent node found in search response'); + } - const agentNode = agentSearchResponse.categories[0].items[0] as AvailableNode; - console.log(">>> agentNode", agentNode); + const agentNode = agentSearchResponse.categories[0].items[0] as AvailableNode; + console.log(">>> agentNode", agentNode); - // Generate template from agent node - const agentNodeTemplate = await getNodeTemplate(rpcClient, agentNode.codedata, projectPath.current); + // Generate template from agent node + const agentNodeTemplate = await getNodeTemplate(rpcClient, agentNode.codedata, projectPath.current); - // save the agent node - const systemPromptValue = `{role: string \`\`, instructions: string \`\`}`; - const agentVarName = `${agentName}Agent`; - agentNodeTemplate.properties.systemPrompt.value = systemPromptValue; - agentNodeTemplate.properties.model.value = modelVarName; - agentNodeTemplate.properties.tools.value = []; - agentNodeTemplate.properties.variable.value = agentVarName; + // save the agent node + const systemPromptValue = `{role: string \`\`, instructions: string \`\`}`; + const agentVarName = `${agentName}Agent`; + agentNodeTemplate.properties.systemPrompt.value = systemPromptValue; + agentNodeTemplate.properties.model.value = modelVarName; + agentNodeTemplate.properties.tools.value = []; + agentNodeTemplate.properties.variable.value = agentVarName; - await rpcClient - .getBIDiagramRpcClient() - .getSourceCode({ filePath: projectPath.current, flowNode: agentNodeTemplate }); - } + await rpcClient + .getBIDiagramRpcClient() + .getSourceCode({ filePath: projectPath.current, flowNode: agentNodeTemplate }); setCurrentStep(3); diff --git a/workspaces/ballerina/ballerina-visualizer/src/views/BI/AIEvaluationForm/CardSelector.tsx b/workspaces/ballerina/ballerina-visualizer/src/views/BI/AIEvaluationForm/CardSelector.tsx new file mode 100644 index 00000000000..c2567a12bb1 --- /dev/null +++ b/workspaces/ballerina/ballerina-visualizer/src/views/BI/AIEvaluationForm/CardSelector.tsx @@ -0,0 +1,158 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import styled from "@emotion/styled"; +import { ReactNode } from "react"; + +interface CardOption { + value: string; + title: string; + description: string; + icon: ReactNode; +} + +interface CardSelectorProps { + options: CardOption[]; + value: string; + onChange: (value: string) => void; + title?: string; +} + +const Container = styled.div` + display: flex; + flex-direction: column; + gap: 8px; + margin-top: 4px; +`; + +const Title = styled.label` + font-size: 13px; + color: var(--vscode-foreground); + margin: 0; + margin-bottom: 4px; +`; + +const CardsContainer = styled.div` + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 16px; +`; + +const Card = styled.div<{ selected: boolean }>` + position: relative; + display: flex; + flex-direction: column; + gap: 12px; + padding: 20px; + border: 1px solid ${(props: { selected: boolean; }) => props.selected ? 'var(--vscode-button-background)' : 'var(--vscode-panel-border)'}; + border-radius: 8px; + background-color: ${(props: { selected: boolean; }) => props.selected ? 'color-mix(in srgb, var(--vscode-button-background) 5%, transparent)' : 'transparent'}; + cursor: pointer; + transition: all 0.2s ease; + + &:hover { + border-color: var(--vscode-button-background); + background-color: ${(props: { selected: boolean; }) => props.selected ? 'color-mix(in srgb, var(--vscode-button-background) 7%, transparent)' : 'var(--vscode-list-hoverBackground)'}; + } + + &:focus-within { + outline: 1px solid var(--vscode-contrastActiveBorder); + outline-offset: 2px; + } +`; + +const CardHeader = styled.div` + display: flex; + align-items: center; + justify-content: space-between; +`; + +const IconTitleWrapper = styled.div` + display: flex; + align-items: center; + gap: 12px; +`; + +const IconWrapper = styled.div<{ selected: boolean }>` + display: flex; + align-items: center; + justify-content: center; + padding: 8px; + border-radius: 8px; + background-color: ${(props: { selected: boolean; }) => props.selected ? 'var(--vscode-button-background)' : 'var(--vscode-editorWidget-background)'}; + color: ${(props: { selected: boolean; }) => props.selected ? 'var(--vscode-button-foreground)' : 'var(--vscode-description-foreground)'}; + flex-shrink: 0; +`; + +const CardTitle = styled.h4` + font-size: 13px; + font-weight: 600; + color: var(--vscode-foreground); + margin: 0; +`; + +const RadioButton = styled.input` + width: 16px; + height: 16px; + cursor: pointer; + accent-color: var(--vscode-contrastActiveBorder, #1976d2); +`; + +const Description = styled.p` + font-size: 13px; + color: var(--vscode-descriptionForeground); + margin: 0; +`; + +export function CardSelector({ options, value, onChange, title }: CardSelectorProps) { + return ( + + {title && {title}} + + {options.map((option) => { + const isSelected = value === option.value; + return ( + onChange(option.value)} + > + + + + {option.icon} + + {option.title} + + onChange(option.value)} + onClick={(e) => e.stopPropagation()} + /> + + {option.description} + + ); + })} + + + ); +} diff --git a/workspaces/ballerina/ballerina-visualizer/src/views/BI/AIEvaluationForm/index.tsx b/workspaces/ballerina/ballerina-visualizer/src/views/BI/AIEvaluationForm/index.tsx new file mode 100644 index 00000000000..e63665ba2c3 --- /dev/null +++ b/workspaces/ballerina/ballerina-visualizer/src/views/BI/AIEvaluationForm/index.tsx @@ -0,0 +1,843 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { useEffect, useState } from "react"; +import { Icon, View, ViewContent } from "@wso2/ui-toolkit"; +import styled from "@emotion/styled"; +import { useRpcContext } from "@wso2/ballerina-rpc-client"; +import { FormField, FormImports, FormValues, Parameter } from "@wso2/ballerina-side-panel"; +import { LineRange, FunctionParameter, TestFunction, ValueProperty, Annotation, getPrimaryInputType, EvalsetItem } from "@wso2/ballerina-core"; +import { EVENT_TYPE } from "@wso2/ballerina-core"; +import { TitleBar } from "../../../components/TitleBar"; +import { TopNavigationBar } from "../../../components/TopNavigationBar"; +import { FormHeader } from "../../../components/FormHeader"; +import FormGeneratorNew from "../Forms/FormGeneratorNew"; +import { getImportsForProperty } from "../../../utils/bi"; +import { CardSelector } from "./CardSelector"; + +const FormContainer = styled.div` + display: flex; + flex-direction: column; + max-width: 600px; + margin-bottom: 20px; + + .side-panel-body { + overflow: visible; + overflow-y: hidden; + } + + .radio-button-group { + margin-top: 8px; + margin-bottom: -12px; + } + + .dropdown-container { + margin-top: 12px; + } +`; + +const Container = styled.div` + display: "flex"; + flex-direction: "column"; + gap: 10px; +`; + +const FullHeightView = styled(View)` + display: flex; + flex-direction: column; + height: 100vh; +`; + +const FullHeightViewContent = styled(ViewContent)` + display: flex; + flex: 1; +`; + +const UpgradeMessageContainer = styled.div` + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + flex: 1; + width: 100%; + padding: 40px; + text-align: center; +`; + +const UpgradeTitle = styled.h2` + color: var(--vscode-foreground); + font-size: 18px; + font-weight: 500; + margin: 0 0 12px 0; + line-height: 1.4; +`; + +const UpgradeMessage = styled.p` + color: var(--vscode-descriptionForeground); + font-size: 13px; + margin: 0; + max-width: 500px; + line-height: 1.6; +`; + +interface TestFunctionDefProps { + projectPath: string; + functionName?: string; + filePath?: string; + serviceType?: string; + isVersionSupported?: boolean; +} + +export function AIEvaluationForm(props: TestFunctionDefProps) { + const { projectPath, functionName, filePath, serviceType, isVersionSupported = true } = props; + const { rpcClient } = useRpcContext(); + const [formFields, setFormFields] = useState([]); + const [testFunction, setTestFunction] = useState(); + const [formTitle, setFormTitle] = useState('Create New AI Evaluation'); + const [formSubtitle, setFormSubtitle] = useState('Create a new AI evaluation for your integration'); + const [targetLineRange, setTargetLineRange] = useState(); + const [dataProviderMode, setDataProviderMode] = useState('evalSet'); + const [evalsetOptions, setEvalsetOptions] = useState>([]); + + // Helper function to apply field visibility rules based on data provider mode + const applyFieldVisibility = (fields: FormField[], mode: string): FormField[] => { + return fields.map(field => { + if (field.key === 'dataProvider') { + return { ...field, hidden: mode !== 'function' }; + } + if (field.key === 'evalSetFile') { + return { ...field, hidden: mode !== 'evalSet' }; + } + if (field.key === 'runs') { + return { ...field, hidden: mode === 'evalSet' }; + } + return field; + }); + }; + + const handleFieldChange = (fieldKey: string, value: any) => { + if (fieldKey === 'dataProviderMode') { + setDataProviderMode(value); + updateFieldVisibility(value); + } + }; + + const updateFieldVisibility = (mode: string) => { + setFormFields(prevFields => applyFieldVisibility(prevFields, mode)); + }; + + const updateTargetLineRange = () => { + rpcClient + .getBIDiagramRpcClient() + .getEndOfFile({ filePath }) + .then((linePosition) => { + setTargetLineRange({ + startLine: linePosition, + endLine: linePosition + }); + }); + } + + useEffect(() => { + loadEvalsets(); + }, []); + + useEffect(() => { + if (serviceType === 'UPDATE_TEST') { + setFormTitle('Update AI Evaluation'); + setFormSubtitle('Update an existing AI evaluation'); + loadFunction(); + } else { + setFormTitle('Create New AI Evaluation'); + setFormSubtitle('Create a new AI evaluation for your integration'); + loadEmptyForm(); + } + + updateTargetLineRange(); + }, [functionName]); + + // Regenerate form fields when evalsetOptions changes + useEffect(() => { + if (testFunction && evalsetOptions.length > 0) { + let formFields = generateFormFields(testFunction); + + // Get the dataProviderMode value to initialize field visibility + const modeField = formFields.find(f => f.key === 'dataProviderMode'); + const mode = String(modeField?.value || 'evalSet'); + setDataProviderMode(mode); + + // Set field visibility based on mode + formFields = applyFieldVisibility(formFields, mode); + + setFormFields(formFields); + } + }, [evalsetOptions]); + + const loadEvalsets = async () => { + try { + const res = await rpcClient.getTestManagerRpcClient().getEvalsets({ projectPath }); + const options = res.evalsets.map((evalset: EvalsetItem) => ({ + value: evalset.filePath, + content: `${evalset.name}` + })); + setEvalsetOptions(options); + } catch (error) { + console.error('Failed to load evalsets:', error); + setEvalsetOptions([]); + } + }; + + const loadFunction = async () => { + const res = await rpcClient.getTestManagerRpcClient().getTestFunction({ functionName, filePath }); + setTestFunction(res.function); + let formFields = generateFormFields(res.function); + + // Get the dataProviderMode value to initialize field visibility + const modeField = formFields.find(f => f.key === 'dataProviderMode'); + const mode = String(modeField?.value || 'evalSet'); + setDataProviderMode(mode); + + // Set initial field visibility + formFields = applyFieldVisibility(formFields, mode); + + setFormFields(formFields); + } + + const loadEmptyForm = async () => { + const emptyTestFunction = getEmptyTestFunctionModel(); + setTestFunction(emptyTestFunction); + let formFields = generateFormFields(emptyTestFunction); + + // Get the dataProviderMode value to initialize field visibility + const modeField = formFields.find(f => f.key === 'dataProviderMode'); + const mode = String(modeField?.value || 'evalSet'); + setDataProviderMode(mode); + + // Set initial field visibility (default is 'evalSet' mode) + formFields = applyFieldVisibility(formFields, mode); + + setFormFields(formFields); + } + + const onFormSubmit = async (data: FormValues, formImports: FormImports) => { + // Include the dataProviderMode from CardSelector state + const formData = { + ...data, + dataProviderMode: dataProviderMode + }; + const updatedTestFunction = fillFunctionModel(formData, formImports); + if (serviceType === 'UPDATE_TEST') { + await rpcClient.getTestManagerRpcClient().updateTestFunction({ function: updatedTestFunction, filePath }); + } else { + await rpcClient.getTestManagerRpcClient().addTestFunction({ function: updatedTestFunction, filePath }); + } + const res = await rpcClient.getTestManagerRpcClient().getTestFunction( + { functionName: updatedTestFunction.functionName.value, filePath }); + const nodePosition = { + startLine: res.function.codedata.lineRange.startLine.line, + startColumn: res.function.codedata.lineRange.startLine.offset, + endLine: res.function.codedata.lineRange.endLine.line, + endColumn: res.function.codedata.lineRange.endLine.offset + }; + rpcClient.getVisualizerRpcClient().openView( + { type: EVENT_TYPE.OPEN_VIEW, location: { position: nodePosition, documentUri: filePath } }) + }; + + // Helper function to modify and set the visual information + const handleParamChange = (param: Parameter) => { + const name = `${param.formValues['variable']}`; + const type = `${param.formValues['type']}`; + const defaultValue = Object.keys(param.formValues).indexOf('defaultable') > -1 && `${param.formValues['defaultable']}`; + let value = `${type} ${name}`; + if (defaultValue) { + value += ` = ${defaultValue}`; + } + return { + ...param, + key: name, + value: value + } + }; + + const generateFormFields = (testFunction: TestFunction): FormField[] => { + const fields: FormField[] = []; + if (testFunction.functionName) { + fields.push(generateFieldFromProperty('functionName', testFunction.functionName)); + } + if (testFunction.parameters) { + fields.push({ + key: `params`, + label: 'Parameters', + type: 'PARAM_MANAGER', + optional: true, + editable: true, + enabled: true, + advanced: true, + hidden: true, + documentation: '', + value: '', + paramManagerProps: { + paramValues: generateParamFields(testFunction.parameters), + formFields: paramFields, + handleParameter: handleParamChange + }, + types: [{ fieldType: "PARAM_MANAGER", selected: false }] + }); + } + if (testFunction.annotations) { + const configAnnotation = getTestConfigAnnotation(testFunction.annotations); + if (configAnnotation && configAnnotation.fields) { + const minPassRateField = configAnnotation.fields.find(f => f.originalName === 'minPassRate'); + if (minPassRateField) { + const generatedField = generateFieldFromProperty('minPassRate', minPassRateField); + fields.push({ + ...generatedField, + type: 'SLIDER', + sliderProps: { + min: 0, + max: 100, + step: 1, + showValue: true, + showMarkers: true, + valueFormatter: (value: number) => `${value}%` + } + }); + } + + const evalSetFileField = configAnnotation.fields.find(f => f.originalName === 'evalSetFile'); + if (evalSetFileField) { + fields.push({ + ...generateFieldFromProperty('evalSetFile', evalSetFileField), + type: 'SINGLE_SELECT', + itemOptions: evalsetOptions + }); + } + + for (const field of configAnnotation.fields) { + // Skip fields already processed + if (field.originalName === 'dataProviderMode' || + field.originalName === 'minPassRate' || + field.originalName === 'evalSetFile') { + continue; + } + + // Special handling for groups and dependsOn - use EXPRESSION_SET + if (field.originalName === 'groups' || field.originalName === 'dependsOn') { + fields.push({ + ...generateFieldFromProperty(field.originalName, field), + type: 'EXPRESSION_SET', + advanced: true, + types: [{ fieldType: 'EXPRESSION_SET', selected: false }] + }); + continue; + } + + // Special handling for expression fields - ensure they use EXPRESSION type + if (field.originalName === 'before' || field.originalName === 'after' || + field.originalName === 'runs' || field.originalName === 'dataProvider') { + fields.push({ + ...generateFieldFromProperty(field.originalName, field), + type: 'EXPRESSION', + advanced: true, + types: [{ fieldType: 'EXPRESSION', selected: false }] + }); + continue; + } + + // Special handling for enabled - use FLAG + if (field.originalName === 'enabled') { + fields.push({ + ...generateFieldFromProperty(field.originalName, field), + type: 'FLAG', + advanced: true, + types: [{ fieldType: 'FLAG', selected: false }] + }); + continue; + } + + fields.push(generateFieldFromProperty(field.originalName, field)); + } + } + } + return fields; + } + + const getTestConfigAnnotation = (annotations: Annotation[]): Annotation | undefined => { + for (const annotation of annotations) { + if (annotation.name === 'Config') { + return annotation; + } + } + return; + } + + const generateParamFields = (parameters: FunctionParameter[]): Parameter[] => { + const params: Parameter[] = []; + let id = 0; + for (const param of parameters) { + const key = param.variable.value; + const type = param.type.value; + + const value = `${type} ${key}`; + params.push({ + id: id, + formValues: { + variable: key, + type: type, + defaultable: param.defaultValue ? param.defaultValue.value : '' + }, + key: key, + value: value, + icon: '', + identifierEditable: param.variable?.editable, + identifierRange: param.variable?.codedata?.lineRange + }); + + id++; + } + return params + } + + const generateFieldFromProperty = (key: string, property: ValueProperty): FormField => { + const fieldType = getPrimaryInputType(property.types)?.fieldType; + + // Convert decimal (0-1) to percentage (0-100) for minPassRate display + let displayValue = property.value; + if (key === 'minPassRate') { + const decimalValue = parseFloat(property.value); + displayValue = String(Math.round((isNaN(decimalValue) ? 1 : decimalValue) * 100)); + } + + const baseField: FormField = { + key: key, + label: property.metadata.label, + type: fieldType, + optional: property.optional, + editable: property.editable, + advanced: property.advanced, + enabled: true, + documentation: property.metadata.description, + value: displayValue, + types: [{ fieldType: fieldType, selected: false }] + }; + + // Add slider-specific configuration for minPassRate + if (key === 'minPassRate' && fieldType === 'SLIDER') { + baseField.sliderProps = { + min: 0, + max: 100, + step: 1, + showValue: true, + showMarkers: true, + valueFormatter: (value: number) => `${value}%` + }; + } + + return baseField; + } + + const fillFunctionModel = (formValues: FormValues, formImports: FormImports): TestFunction => { + let tmpTestFunction = testFunction; + if (!tmpTestFunction) { + tmpTestFunction = {}; + } + + if (formValues['functionName']) { + tmpTestFunction.functionName.value = formValues['functionName']; + } + + if (formValues['returnType']) { + tmpTestFunction.returnType.value = formValues['returnType']; + tmpTestFunction.returnType.imports = getImportsForProperty('returnType', formImports); + } + + if (formValues['params']) { + const params = formValues['params']; + const paramList: FunctionParameter[] = []; + for (const param of params) { + const paramFormValues = param.formValues; + const variable = paramFormValues['variable']; + const type = paramFormValues['type']; + const typeImports = getImportsForProperty('params', formImports); + const defaultValue = paramFormValues['defaultable']; + let emptyParam = getEmptyParamModel(); + emptyParam.variable.value = variable; + emptyParam.type.value = type; + emptyParam.type.imports = typeImports; + emptyParam.defaultValue.value = defaultValue; + paramList.push(emptyParam); + } + tmpTestFunction.parameters = paramList; + } + + let annots = tmpTestFunction.annotations; + for (const annot of annots) { + if (annot.name == 'Config') { + let configAnnot = annot; + let fields = configAnnot.fields; + for (const field of fields) { + if (field.originalName == 'groups') { + field.value = formValues['groups']; + } + if (field.originalName == 'enabled') { + field.value = formValues['enabled']; + } + if (field.originalName == 'dependsOn') { + field.value = formValues['dependsOn'] || []; + } + if (field.originalName == 'before') { + field.value = formValues['before'] || ""; + } + if (field.originalName == 'after') { + field.value = formValues['after'] || ""; + } + if (field.originalName == 'runs') { + field.value = formValues['runs'] || "1"; + } + if (field.originalName == 'minPassRate') { + // Convert percentage (0-100) to decimal (0-1) + const percentageValue = formValues['minPassRate'] ?? 100; + field.value = String(Number(percentageValue) / 100); + } + if (field.originalName == 'dataProviderMode') { + field.value = formValues['dataProviderMode'] || "function"; + } + if (field.originalName == 'dataProvider') { + if (formValues['dataProviderMode'] === 'function') { + field.value = formValues['dataProvider'] || ""; + } + // Preserve existing dataProvider value when in evalSet mode + // (backend creates it from evalSetFile) + } + if (field.originalName == 'evalSetFile') { + if (formValues['dataProviderMode'] === 'evalSet') { + field.value = formValues['evalSetFile'] || ""; + } + // Preserve existing evalSetFile value when in function mode + } + } + } + } + + return tmpTestFunction; + } + + const getEmptyParamModel = (): FunctionParameter => { + return { + type: { + value: "string", + optional: false, + editable: true, + advanced: false, + types: [{ fieldType: "TYPE", selected: false }] + }, + variable: { + value: "b", + optional: false, + editable: true, + advanced: false, + types: [{ fieldType: "IDENTIFIER", selected: false }] + }, + defaultValue: { + value: "\"default\"", + optional: false, + editable: true, + advanced: false, + types: [{ fieldType: "EXPRESSION", selected: false }] + }, + optional: false, + editable: true, + advanced: false + } + + } + + const getEmptyTestFunctionModel = (): TestFunction => { + return { + functionName: { + metadata: { + label: "AI Evaluation Name", + description: "Name of the AI evaluation" + }, + value: "", + optional: false, + editable: true, + advanced: false, + types: [{ fieldType: "IDENTIFIER", selected: false }] + }, + returnType: { + metadata: { + label: "Return Type", + description: "Return type of the function" + }, + optional: true, + editable: true, + advanced: true, + types: [{ fieldType: "TYPE", selected: false }], + }, + parameters: [], + annotations: [ + { + metadata: { + label: "Config", + description: "AI Evaluation Configurations" + }, + org: "ballerina", + module: "test", + name: "Config", + fields: [ + { + metadata: { + label: "Enabled", + description: "Enable/Disable the evaluation" + }, + originalName: "enabled", + value: true, + optional: true, + editable: true, + advanced: true, + types: [{ fieldType: "FLAG", selected: false }] + }, + { + metadata: { + label: "Groups", + description: "Groups to run" + }, + types: [{ fieldType: "EXPRESSION_SET", selected: false }], + originalName: "groups", + value: ["evaluations"], + optional: true, + editable: true, + advanced: true + }, + { + metadata: { + label: "Depends On", + description: "List of test function names that this test depends on" + }, + types: [{ fieldType: "EXPRESSION_SET", selected: false }], + originalName: "dependsOn", + value: [], + optional: true, + editable: true, + advanced: true + }, + { + metadata: { + label: "Before Function", + description: "Function to execute before this test" + }, + types: [{ fieldType: "EXPRESSION", selected: false }], + originalName: "before", + value: "", + optional: true, + editable: true, + advanced: true + }, + { + metadata: { + label: "After Function", + description: "Function to execute after this test" + }, + types: [{ fieldType: "EXPRESSION", selected: false }], + originalName: "after", + value: "", + optional: true, + editable: true, + advanced: true + }, + { + metadata: { + label: "Runs", + description: "Number of times to execute this test" + }, + types: [{ fieldType: "EXPRESSION", selected: false }], + originalName: "runs", + value: "1", + optional: true, + editable: true, + advanced: true + }, + { + metadata: { + label: "Minimum Pass Rate (%)", + description: "Minimum percentage of runs that must pass (0-100)" + }, + types: [{ fieldType: "SLIDER", selected: false }], + originalName: "minPassRate", + value: "1.0", + optional: true, + editable: true, + advanced: false + }, + { + metadata: { + label: "", + description: "Choose how to provide test data" + }, + types: [{ fieldType: "STRING", selected: false }], + originalName: "dataProviderMode", + value: "function", + optional: true, + editable: true, + advanced: true + }, + { + metadata: { + label: "Data Provider", + description: "Function that provides test data" + }, + types: [{ fieldType: "EXPRESSION", selected: false }], + originalName: "dataProvider", + value: "", + optional: true, + editable: true, + advanced: true + }, + { + metadata: { + label: "Evalset File", + description: "Select an evalset for test data" + }, + types: [{ fieldType: "STRING", selected: false }], + originalName: "evalSetFile", + value: "", + optional: true, + editable: true, + advanced: false + } + ] + } + ], + editable: true + } + } + + const paramFields: FormField[] = [ + { + key: `variable`, + label: 'Name', + type: 'string', + optional: false, + editable: true, + enabled: true, + documentation: '', + value: '', + types: [{ fieldType: "IDENTIFIER", selected: false }] + }, + { + key: `type`, + label: 'Type', + type: 'TYPE', + optional: false, + editable: true, + enabled: true, + documentation: '', + value: '', + types: [{ fieldType: "TYPE", selected: false }] + }, + { + key: `defaultable`, + label: 'Default Value', + type: 'string', + optional: true, + advanced: true, + editable: true, + enabled: true, + documentation: '', + value: '', + types: [{ fieldType: "STRING", selected: false }] + } + ]; + + const cardOptions = [ + { + value: 'evalSet', + title: 'From Evalset', + description: 'Use conversation traces from an existing dataset to evaluate your agent.', + icon: + }, + { + value: 'function', + title: 'Standalone/Custom', + description: 'Implement a fully custom logic to evaluate specific behaviors from scratch.', + icon: + } + ]; + + const handleCardSelectorChange = (value: string) => { + setDataProviderMode(value); + updateFieldVisibility(value); + }; + + // Show upgrade message if version is not supported + if (isVersionSupported === false) { + return ( + + + + + + Please upgrade your Ballerina version + + AI Evaluation features require Ballerina version 2201.13.2 or higher. + Please upgrade your Ballerina installation to use this feature. + + + + + ); + } + + return ( + + + + + + + + + {targetLineRange && ( + , + index: 2 + } + ]} + /> + )} + + + + + ); +} + diff --git a/workspaces/ballerina/ballerina-visualizer/src/views/BI/ConfigurationCollector/index.tsx b/workspaces/ballerina/ballerina-visualizer/src/views/BI/ConfigurationCollector/index.tsx new file mode 100644 index 00000000000..c62bfb3cae5 --- /dev/null +++ b/workspaces/ballerina/ballerina-visualizer/src/views/BI/ConfigurationCollector/index.tsx @@ -0,0 +1,282 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React, { useState, useEffect } from "react"; +import styled from "@emotion/styled"; +import { Button, Codicon, ThemeColors } from "@wso2/ui-toolkit"; +import { useRpcContext } from "@wso2/ballerina-rpc-client"; +import { ConfigurationCollectorMetadata, ParentPopupData } from "@wso2/ballerina-core"; +import { + PopupOverlay, + PopupContainer, + PopupHeader, + HeaderTitleContainer, + PopupTitle, + PopupSubtitle, + CloseButton, + PopupContent, + PopupFooter, +} from "../Connection/styles"; + +// Form styled components +const FormSection = styled.div` + display: flex; + flex-direction: column; + gap: 16px; +`; + +const ConfigurationField = styled.div` + display: flex; + flex-direction: column; + gap: 6px; +`; + +const FieldLabel = styled.label` + font-size: 13px; + font-weight: 500; + color: ${ThemeColors.ON_SURFACE}; + display: flex; + align-items: center; + gap: 4px; +`; + +const FieldDescription = styled.span` + font-size: 12px; + color: ${ThemeColors.ON_SURFACE_VARIANT}; + font-style: italic; + font-weight: normal; +`; + +const FieldInput = styled.input<{ hasError: boolean }>` + padding: 10px 12px; + background-color: ${ThemeColors.SURFACE_DIM}; + color: ${ThemeColors.ON_SURFACE}; + border: 1px solid ${(props: { hasError: boolean }) => + props.hasError ? ThemeColors.ERROR : ThemeColors.OUTLINE_VARIANT}; + border-radius: 6px; + font-size: 13px; + + &:focus { + outline: none; + border-color: ${ThemeColors.PRIMARY}; + } + + &::placeholder { + color: ${ThemeColors.ON_SURFACE_VARIANT}; + } +`; + +const FieldError = styled.div` + font-size: 12px; + color: ${ThemeColors.ERROR}; +`; + +const ActionButton = styled(Button)``; + +const LoadingContainer = styled.div` + display: flex; + align-items: center; + justify-content: center; + padding: 40px; + color: ${ThemeColors.ON_SURFACE_VARIANT}; +`; + +interface ConfigurationCollectorProps { + data?: ConfigurationCollectorMetadata; + onClose: (parent?: ParentPopupData) => void; +} + +export const ConfigurationCollector: React.FC = ({ data, onClose }) => { + const { rpcClient } = useRpcContext(); + const [configValues, setConfigValues] = useState>(data?.existingValues || {}); + const [errors, setErrors] = useState>({}); + const [isProcessing, setIsProcessing] = useState(false); + + // Initialize configuration values when data prop changes + useEffect(() => { + if (data?.existingValues) { + setConfigValues(data.existingValues); + } + }, [data]); + + const handleInputChange = (variableName: string, value: string) => { + setConfigValues((prev) => ({ ...prev, [variableName]: value })); + setErrors((prev) => { + const newErrors = { ...prev }; + delete newErrors[variableName]; + return newErrors; + }); + }; + + const handleKeyDown = (e: React.KeyboardEvent) => { + if (e.key === "Enter" && !isProcessing) { + handleSubmit(); + } + }; + + const validateConfiguration = (): boolean => { + const newErrors: Record = {}; + + data?.variables?.forEach((variable) => { + const value = configValues[variable.name]; + if (!value || !value.trim()) { + newErrors[variable.name] = "This field is required"; + } else if (variable.type === "int") { + const intValue = parseInt(value, 10); + if (isNaN(intValue)) { + newErrors[variable.name] = "Please enter a valid number"; + } + } + }); + + setErrors(newErrors); + return Object.keys(newErrors).length === 0; + }; + + const handleSubmit = async () => { + if (!data) return; + + console.log("[ConfigurationCollector] handleSubmit called", { + requestId: data.requestId, + configurationCount: Object.keys(configValues).length, + }); + + if (!validateConfiguration()) { + console.log("[ConfigurationCollector] Validation failed"); + return; + } + + setIsProcessing(true); + + try { + console.log("[ConfigurationCollector] Calling provideConfiguration RPC"); + await rpcClient.getAiPanelRpcClient().provideConfiguration({ + requestId: data.requestId, + configValues: configValues, + }); + console.log("[ConfigurationCollector] RPC call successful"); + onClose(); + } catch (error: any) { + console.error("[ConfigurationCollector] Error in handleSubmit:", error); + } finally { + setIsProcessing(false); + } + }; + + const handleCancel = async () => { + if (!data) { + onClose(); + return; + } + + try { + await rpcClient.getAiPanelRpcClient().cancelConfiguration({ + requestId: data.requestId, + }); + } catch (error: any) { + console.error("[ConfigurationCollector] Error in handleCancel:", error); + } + onClose(); + }; + + // Close button (X) just closes the popup without canceling configuration collection + // User can reopen via the Configure button in the chat segment + const handleClose = () => { + onClose(); + }; + + // Prevent overlay clicks from closing the popup + const handleOverlayClick = (e: React.MouseEvent) => { + e.stopPropagation(); + }; + + if (!data) { + return ( + <> + + + Loading... + + + ); + } + + return ( + <> + + + + + + {data.isTestConfig ? "Configure Test Environment" : "Configure Application"} + + {data.message && {data.message}} + + + + + + + + {data.variables?.map((variable) => ( + + + {variable.name} + {variable.description && ( + - {variable.description} + )} + + handleInputChange(variable.name, e.target.value)} + onKeyDown={handleKeyDown} + hasError={!!errors[variable.name]} + /> + {errors[variable.name] && {errors[variable.name]}} + + ))} + + + + + Skip + + + {isProcessing ? "Saving..." : "Save Configuration"} + + + + + ); +}; + +export default ConfigurationCollector; diff --git a/workspaces/ballerina/ballerina-visualizer/src/views/BI/Connection/APIConnectionPopup/index.tsx b/workspaces/ballerina/ballerina-visualizer/src/views/BI/Connection/APIConnectionPopup/index.tsx index 3490eb155d6..c656ca7c1f6 100644 --- a/workspaces/ballerina/ballerina-visualizer/src/views/BI/Connection/APIConnectionPopup/index.tsx +++ b/workspaces/ballerina/ballerina-visualizer/src/views/BI/Connection/APIConnectionPopup/index.tsx @@ -19,7 +19,7 @@ import React, { useMemo, useState } from "react"; import styled from "@emotion/styled"; import { Button, Codicon, Dropdown, Stepper, TextField, ThemeColors, Typography, Icon } from "@wso2/ui-toolkit"; -import { AvailableNode, Category, DataMapperDisplayMode, DIRECTORY_MAP, FlowNode, LinePosition, ParentPopupData } from "@wso2/ballerina-core"; +import { AvailableNode, Category, EditorConfig, DIRECTORY_MAP, FlowNode, LinePosition, ParentPopupData } from "@wso2/ballerina-core"; import { useRpcContext } from "@wso2/ballerina-rpc-client"; import { ExpressionFormField } from "@wso2/ballerina-side-panel"; import ConnectionConfigView from "../ConnectionConfigView"; @@ -404,7 +404,7 @@ export function APIConnectionPopup(props: APIConnectionPopupProps) { ); }; - const handleOnFormSubmit = async (node: FlowNode, _dataMapperMode?: DataMapperDisplayMode, options?: FormSubmitOptions) => { + const handleOnFormSubmit = async (node: FlowNode, _editorConfig?: EditorConfig, options?: FormSubmitOptions) => { console.log(">>> on form submit", node); if (selectedFlowNode) { setIsSavingConnection(true); diff --git a/workspaces/ballerina/ballerina-visualizer/src/views/BI/Connection/AddConnectionWizard/index.tsx b/workspaces/ballerina/ballerina-visualizer/src/views/BI/Connection/AddConnectionWizard/index.tsx index 6c35e879972..a101e81ecee 100644 --- a/workspaces/ballerina/ballerina-visualizer/src/views/BI/Connection/AddConnectionWizard/index.tsx +++ b/workspaces/ballerina/ballerina-visualizer/src/views/BI/Connection/AddConnectionWizard/index.tsx @@ -20,7 +20,7 @@ import { useEffect, useRef, useState } from "react"; import styled from "@emotion/styled"; import { AvailableNode, - DataMapperDisplayMode, + EditorConfig, DIRECTORY_MAP, EVENT_TYPE, FlowNode, @@ -235,7 +235,7 @@ export function AddConnectionWizard(props: AddConnectionWizardProps) { setCurrentStep(WizardStep.GENERATE_CONNECTOR); }; - const handleOnFormSubmit = async (node: FlowNode, _dataMapperMode?: DataMapperDisplayMode, options?: FormSubmitOptions) => { + const handleOnFormSubmit = async (node: FlowNode, _editorConfig?: EditorConfig, options?: FormSubmitOptions) => { console.log(">>> on form submit", node); if (selectedNodeRef.current) { setSavingFormStatus(SavingFormStatus.SAVING); diff --git a/workspaces/ballerina/ballerina-visualizer/src/views/BI/Connection/ConnectionConfigView/index.tsx b/workspaces/ballerina/ballerina-visualizer/src/views/BI/Connection/ConnectionConfigView/index.tsx index 0e1b636ce1d..f474bccfeb4 100644 --- a/workspaces/ballerina/ballerina-visualizer/src/views/BI/Connection/ConnectionConfigView/index.tsx +++ b/workspaces/ballerina/ballerina-visualizer/src/views/BI/Connection/ConnectionConfigView/index.tsx @@ -19,7 +19,7 @@ import React, { ReactNode, useEffect, useState } from "react"; import styled from "@emotion/styled"; import { ExpressionFormField } from "@wso2/ballerina-side-panel"; -import { DataMapperDisplayMode, FlowNode, LineRange, SubPanel } from "@wso2/ballerina-core"; +import { EditorConfig, FlowNode, LineRange, SubPanel } from "@wso2/ballerina-core"; import FormGenerator from "../../Forms/FormGenerator"; import { useRpcContext } from "@wso2/ballerina-rpc-client"; import { SidePanelView } from "../../FlowDiagram/PanelManager"; @@ -58,7 +58,7 @@ interface ConnectionConfigViewProps { submitText?: string; isSaving?: boolean; selectedNode: FlowNode; - onSubmit: (updatedNode?: FlowNode, dataMapperMode?: DataMapperDisplayMode, options?: FormSubmitOptions) => void; + onSubmit: (updatedNode?: FlowNode, editorConfig?: EditorConfig, options?: FormSubmitOptions) => void; openSubPanel?: (subPanel: SubPanel) => void; updatedExpressionField?: ExpressionFormField; resetUpdatedExpressionField?: () => void; diff --git a/workspaces/ballerina/ballerina-visualizer/src/views/BI/Connection/ConnectionConfigurationPopup/index.tsx b/workspaces/ballerina/ballerina-visualizer/src/views/BI/Connection/ConnectionConfigurationPopup/index.tsx index 966c385116b..0c5e94a2708 100644 --- a/workspaces/ballerina/ballerina-visualizer/src/views/BI/Connection/ConnectionConfigurationPopup/index.tsx +++ b/workspaces/ballerina/ballerina-visualizer/src/views/BI/Connection/ConnectionConfigurationPopup/index.tsx @@ -21,7 +21,7 @@ import styled from "@emotion/styled"; import { AvailableNode, Category, - DataMapperDisplayMode, + EditorConfig, DIRECTORY_MAP, FlowNode, LinePosition, @@ -287,7 +287,7 @@ export function ConnectionConfigurationPopup(props: ConnectionConfigurationPopup fetchNodeTemplate(); }, [selectedConnector, fileName, target, rpcClient]); - const handleOnFormSubmit = async (node: FlowNode, _dataMapperMode?: DataMapperDisplayMode, options?: FormSubmitOptions) => { + const handleOnFormSubmit = async (node: FlowNode, _editorConfig?: EditorConfig, options?: FormSubmitOptions) => { console.log(">>> on form submit", node); if (selectedNodeRef.current) { setSavingFormStatus(SavingFormStatus.SAVING); diff --git a/workspaces/ballerina/ballerina-visualizer/src/views/BI/Connection/styles.ts b/workspaces/ballerina/ballerina-visualizer/src/views/BI/Connection/styles.ts index 9533291f0f1..a4b1c31711e 100644 --- a/workspaces/ballerina/ballerina-visualizer/src/views/BI/Connection/styles.ts +++ b/workspaces/ballerina/ballerina-visualizer/src/views/BI/Connection/styles.ts @@ -81,4 +81,19 @@ export const CloseButton = styled(Button)` padding: 4px; `; +export const PopupContent = styled.div` + flex: 1; + overflow-y: auto; + padding: 16px 20px; + display: flex; + flex-direction: column; + gap: 16px; +`; +export const PopupFooter = styled.div` + padding: 16px 20px; + display: flex; + justify-content: flex-end; + gap: 8px; + border-top: 1px solid ${ThemeColors.OUTLINE_VARIANT}; +`; diff --git a/workspaces/ballerina/ballerina-visualizer/src/views/BI/DiagramWrapper/index.tsx b/workspaces/ballerina/ballerina-visualizer/src/views/BI/DiagramWrapper/index.tsx index a634ecfc6e2..2acbacb6ee1 100644 --- a/workspaces/ballerina/ballerina-visualizer/src/views/BI/DiagramWrapper/index.tsx +++ b/workspaces/ballerina/ballerina-visualizer/src/views/BI/DiagramWrapper/index.tsx @@ -394,22 +394,21 @@ export function DiagramWrapper(param: DiagramWrapperProps) { ) } {/* This is for editing a http resource */} - {functionModel && isResource && functionModel.kind === "RESOURCE" && ( - + - - - )} + /> + ); } diff --git a/workspaces/ballerina/ballerina-visualizer/src/views/BI/FlowDiagram/PanelManager.tsx b/workspaces/ballerina/ballerina-visualizer/src/views/BI/FlowDiagram/PanelManager.tsx index 04ee0f4069f..c88f89cd868 100644 --- a/workspaces/ballerina/ballerina-visualizer/src/views/BI/FlowDiagram/PanelManager.tsx +++ b/workspaces/ballerina/ballerina-visualizer/src/views/BI/FlowDiagram/PanelManager.tsx @@ -25,7 +25,7 @@ import { FUNCTION_TYPE, ToolData, NodeMetadata, - DataMapperDisplayMode, + EditorConfig } from "@wso2/ballerina-core"; import { HelperView } from "../HelperView"; import FormGenerator from "../Forms/FormGenerator"; @@ -78,6 +78,7 @@ export enum SidePanelView { CONNECTION_CREATE = "CONNECTION_CREATE", AGENT_MEMORY_MANAGER = "AGENT_MEMORY_MANAGER", AGENT_CONFIG = "AGENT_CONFIG", + AGENT_LIST = "AGENT_LIST" } interface PanelManagerProps { @@ -117,7 +118,7 @@ interface PanelManagerProps { onAddVectorKnowledgeBase?: () => void; onAddDataLoader?: () => void; onAddChunker?: () => void; - onSubmitForm: (updatedNode?: FlowNode, dataMapperMode?: DataMapperDisplayMode, options?: FormSubmitOptions) => void; + onSubmitForm: (updatedNode?: FlowNode, editorConfig?: EditorConfig, options?: FormSubmitOptions) => void; onDiscardSuggestions: () => void; onSubPanel: (subPanel: SubPanel) => void; onUpdateExpressionField: (updatedExpressionField: ExpressionFormField) => void; @@ -130,6 +131,7 @@ interface PanelManagerProps { onSearchVectorKnowledgeBase?: (searchText: string, functionType: FUNCTION_TYPE) => void; onSearchDataLoader?: (searchText: string, functionType: FUNCTION_TYPE) => void; onSearchChunker?: (searchText: string, functionType: FUNCTION_TYPE) => void; + onAddAgent?: () => void; onEditAgent?: () => void; onNavigateToPanel?: (targetPanel: SidePanelView, connectionKind?: ConnectionKind) => void; setSidePanelView: (view: SidePanelView) => void; @@ -176,6 +178,7 @@ export function PanelManager(props: PanelManagerProps) { onAddFunction, onAddNPFunction, onAddDataMapper, + onAddAgent, onAddModelProvider, onAddVectorStore, onAddEmbeddingProvider, @@ -358,6 +361,20 @@ export function PanelManager(props: PanelManagerProps) { /> ); + case SidePanelView.AGENT_LIST: + return ( + + ); + case SidePanelView.MODEL_PROVIDER_LIST: return ( (undefined); const [targetLineRange, setTargetLineRange] = useState(targetRef?.current); + const isCreatingAgent = useRef(false); const isCreatingNewModelProvider = useRef(false); const isCreatingNewVectorStore = useRef(false); const isCreatingNewEmbeddingProvider = useRef(false); @@ -1103,6 +1105,29 @@ export function BIFlowDiagram(props: BIFlowDiagramProps) { }); break; + case "AGENTS": + setShowProgressIndicator(true); + rpcClient + .getBIDiagramRpcClient() + .getAvailableAgents({ + position: targetRef.current.startLine, + filePath: model?.fileName || fileName, + }) + .then((response) => { + setCategories( + convertFunctionCategoriesToSidePanelCategories( + response.categories as Category[], + FUNCTION_TYPE.REGULAR + ) + ); + setSidePanelView(SidePanelView.AGENT_LIST); + setShowSidePanel(true); + }) + .finally(() => { + setShowProgressIndicator(false); + }); + break; + case "MODEL_PROVIDERS": setShowProgressIndicator(true); rpcClient @@ -1281,7 +1306,7 @@ export function BIFlowDiagram(props: BIFlowDiagramProps) { const handleOnFormSubmit = ( updatedNode?: FlowNode, - dataMapperMode?: DataMapperDisplayMode, + editorConfig?: EditorConfig, options?: FormSubmitOptions ) => { if (!updatedNode) { @@ -1318,7 +1343,11 @@ export function BIFlowDiagram(props: BIFlowDiagramProps) { updatedNode.codedata.lineRange.endLine = targetLine; } - if (dataMapperMode && dataMapperMode !== DataMapperDisplayMode.NONE) { + if ( + editorConfig && + editorConfig.view === MACHINE_VIEW.InlineDataMapper && + editorConfig.displayMode !== EditorDisplayMode.NONE + ) { rpcClient .getDataMapperRpcClient() .getInitialIDMSource({ @@ -1348,12 +1377,12 @@ export function BIFlowDiagram(props: BIFlowDiagramProps) { codeData: response.codedata, } }, - isPopup: dataMapperMode === DataMapperDisplayMode.POPUP + isPopup: editorConfig.displayMode === EditorDisplayMode.POPUP }); } }) .finally(() => { - if (dataMapperMode !== DataMapperDisplayMode.POPUP) setShowSidePanel(false); + if (editorConfig.displayMode !== EditorDisplayMode.POPUP) setShowSidePanel(false); if (options?.postUpdateCallBack) { options.postUpdateCallBack(); } @@ -1361,16 +1390,30 @@ export function BIFlowDiagram(props: BIFlowDiagramProps) { }); return; } + rpcClient .getBIDiagramRpcClient() .getSourceCode({ filePath: model.fileName, flowNode: updatedNode, - isFunctionNodeUpdate: dataMapperMode !== DataMapperDisplayMode.NONE, + isFunctionNodeUpdate: editorConfig?.displayMode !== EditorDisplayMode.NONE, isHelperPaneChange: options?.isChangeFromHelperPane, + artifactData: editorConfig && + editorConfig.displayMode !== EditorDisplayMode.NONE && + editorConfig.view === MACHINE_VIEW.DataMapper ? + { artifactType: DIRECTORY_MAP.DATA_MAPPER } : undefined, }) .then(async (response) => { if (response.artifacts.length > 0) { + + if (editorConfig && editorConfig.displayMode !== EditorDisplayMode.NONE) { + const newArtifact = response.artifacts.find(res => res.isNew); + if (newArtifact) { + rpcClient.getVisualizerRpcClient().openView({ type: EVENT_TYPE.OPEN_VIEW, location: { documentUri: newArtifact.path, position: newArtifact.position } }); + return; + } + } + if (updatedNode?.codedata?.symbol === GET_DEFAULT_MODEL_PROVIDER || (updatedNode?.codedata?.node === "AGENT_CALL" && updatedNode?.properties?.model?.value === "")) { await rpcClient.getAIAgentRpcClient().configureDefaultModelProvider(); @@ -1452,16 +1495,6 @@ export function BIFlowDiagram(props: BIFlowDiagramProps) { console.error(">>> Error updating source code", deleteNodeResponse); } - if (node.codedata.node === "AGENT_CALL") { - const agentNodeDeleteResponse = await removeAgentNode(node, rpcClient); - if (!agentNodeDeleteResponse) { - console.error(">>> Error deleting agent node", node); - setShowProgressIndicator(false); - debouncedGetFlowModel(); - return; - } - } - await updateArtifactLocation(deleteNodeResponse); selectedNodeRef.current = undefined; @@ -1665,14 +1698,26 @@ export function BIFlowDiagram(props: BIFlowDiagramProps) { }; const handleOnAddFunction = () => { - rpcClient.getVisualizerRpcClient().openView({ - type: EVENT_TYPE.OPEN_VIEW, - location: { - view: MACHINE_VIEW.BIFunctionForm, - artifactType: DIRECTORY_MAP.FUNCTION, - }, - isPopup: true, - }); + setShowProgressIndicator(true); + pushToNavigationStack(sidePanelView, categories, selectedNodeRef.current, selectedClientName.current); + + rpcClient + .getBIDiagramRpcClient() + .getNodeTemplate({ + position: targetRef.current.startLine, + filePath: model?.fileName, + id: { node: "FUNCTION_CREATION" }, + }) + .then((response) => { + selectedNodeRef.current = response.flowNode; + nodeTemplateRef.current = response.flowNode; + showEditForm.current = false; + setSidePanelView(SidePanelView.FORM); + setShowSidePanel(true); + }) + .finally(() => { + setShowProgressIndicator(false); + }); }; const handleOnAddNPFunction = () => { @@ -1687,14 +1732,27 @@ export function BIFlowDiagram(props: BIFlowDiagramProps) { }; const handleOnAddDataMapper = () => { - rpcClient.getVisualizerRpcClient().openView({ - type: EVENT_TYPE.OPEN_VIEW, - location: { - view: MACHINE_VIEW.BIDataMapperForm, - artifactType: DIRECTORY_MAP.DATA_MAPPER, - }, - isPopup: true, - }); + + setShowProgressIndicator(true); + pushToNavigationStack(sidePanelView, categories, selectedNodeRef.current, selectedClientName.current); + + rpcClient + .getBIDiagramRpcClient() + .getNodeTemplate({ + position: targetRef.current.startLine, + filePath: model?.fileName, + id: { node: "DATA_MAPPER_CREATION" }, + }) + .then((response) => { + selectedNodeRef.current = response.flowNode; + nodeTemplateRef.current = response.flowNode; + showEditForm.current = false; + setSidePanelView(SidePanelView.FORM); + setShowSidePanel(true); + }) + .finally(() => { + setShowProgressIndicator(false); + }); }; // Common function to handle progress message with timeout @@ -1712,6 +1770,41 @@ export function BIFlowDiagram(props: BIFlowDiagramProps) { setProgressMessage(LOADING_MESSAGE); }; + const handleOnAddNewAgent = () => { + isCreatingAgent.current = true; + setShowProgressIndicator(true); + setShowProgressSpinner(true); + + // Push current state to navigation stack + pushToNavigationStack(sidePanelView, categories, selectedNodeRef.current, selectedClientName.current); + + rpcClient + .getBIDiagramRpcClient() + .getNodeTemplate({ + position: targetRef.current.startLine, + filePath: model?.fileName, + id: { + node: "AGENT_CALL", + org: "ballerina", + symbol: "run", + module: "ai", + packageName: "ai", + object: "Agent" + }, + }) + .then((response) => { + selectedNodeRef.current = response.flowNode; + nodeTemplateRef.current = response.flowNode; + showEditForm.current = false; + setSidePanelView(SidePanelView.FORM); + setShowSidePanel(true); + }) + .finally(() => { + setShowProgressIndicator(false); + setShowProgressSpinner(false); + }); + }; + const handleOnAddNewModelProvider = () => { isCreatingNewModelProvider.current = true; setShowProgressIndicator(true); @@ -2468,6 +2561,7 @@ export function BIFlowDiagram(props: BIFlowDiagramProps) { onSearchChunker={handleSearchChunker} onUpdateNodeWithConnection={updateNodeWithConnection} // AI Agent specific callbacks + onAddAgent={handleOnAddNewAgent} onEditAgent={handleEditAgent} onSelectTool={handleOnSelectTool} onDeleteTool={handleOnDeleteTool} diff --git a/workspaces/ballerina/ballerina-visualizer/src/views/BI/Forms/FormGenerator/index.tsx b/workspaces/ballerina/ballerina-visualizer/src/views/BI/Forms/FormGenerator/index.tsx index ff669f4be60..b0c63ebb0d1 100644 --- a/workspaces/ballerina/ballerina-visualizer/src/views/BI/Forms/FormGenerator/index.tsx +++ b/workspaces/ballerina/ballerina-visualizer/src/views/BI/Forms/FormGenerator/index.tsx @@ -39,7 +39,7 @@ import { Member, TypeNodeKind, NodeKind, - DataMapperDisplayMode, + EditorConfig, InputType, getPrimaryInputType } from "@wso2/ballerina-core"; @@ -123,7 +123,7 @@ interface FormProps { editForm?: boolean; isGraphql?: boolean; submitText?: string; - onSubmit: (node?: FlowNode, dataMapperMode?: DataMapperDisplayMode, formImports?: FormImports, rawFormValues?: FormValues) => void; + onSubmit: (node?: FlowNode, editorConfig?: EditorConfig, formImports?: FormImports, rawFormValues?: FormValues) => void; showProgressIndicator?: boolean; subPanelView?: SubPanelView; openSubPanel?: (subPanel: SubPanel) => void; @@ -135,7 +135,7 @@ interface FormProps { description?: string; // Optional description explaining what the action button does callback: () => void; }; - handleOnFormSubmit?: (updatedNode?: FlowNode, dataMapperMode?: DataMapperDisplayMode, options?: FormSubmitOptions) => void; + handleOnFormSubmit?: (updatedNode?: FlowNode, editorConfig?: EditorConfig, options?: FormSubmitOptions) => void; isInModal?: boolean; scopeFieldAddon?: React.ReactNode; onChange?: (fieldKey: string, value: any, allValues: FormValues) => void; @@ -260,14 +260,17 @@ export const FormGenerator = forwardRef(func const skipFormValidation = useMemo(() => { const isAgentNode = node && ( - node.codedata.node === "AGENT_CALL" && + (node.codedata.node === "AGENT_CALL" || node.codedata.node === "AGENT_RUN") && node.codedata.org === "ballerina" && node.codedata.module === "ai" && node.codedata.packageName === "ai" && node.codedata.object === "Agent" && node.codedata.symbol === "run" ); - return isAgentNode; + const isDataMapperCreationNode = node && node.codedata.node === "DATA_MAPPER_CREATION"; + const isFunctionCreationNode = node && node.codedata.node === "FUNCTION_CREATION"; + + return isAgentNode || isDataMapperCreationNode || isFunctionCreationNode; }, [node]); const importsCodedataRef = useRef(null); // To store codeData for getVisualizableFields @@ -318,6 +321,10 @@ export const FormGenerator = forwardRef(func if (stack.length === 0) return; setStack((prev) => { const newStack = [...prev]; + //preserve fieldIndex if exists + if (newStack[newStack.length - 1].fieldIndex) { + item.fieldIndex = newStack[newStack.length - 1].fieldIndex; + } newStack[newStack.length - 1] = item; return newStack; }); @@ -444,7 +451,7 @@ export const FormGenerator = forwardRef(func const recordTypeFields = Object.entries(formProperties) .filter(([_, property]) => { const primaryInputType = getPrimaryInputType(property?.types); - + return primaryInputType?.typeMembers && primaryInputType?.typeMembers.some(member => member.kind === "RECORD_TYPE"); }) @@ -490,8 +497,8 @@ export const FormGenerator = forwardRef(func console.log(">>> FormGenerator handleOnSubmit", data); if (node && targetLineRange) { const updatedNode = mergeFormDataWithFlowNode(data, targetLineRange, dirtyFields); - const dataMapperMode = data["openInDataMapper"] ? DataMapperDisplayMode.VIEW : DataMapperDisplayMode.NONE; - onSubmit(updatedNode, dataMapperMode, formImports); + const editorConfig = data["editorConfig"]; + onSubmit(updatedNode, editorConfig, formImports); } }; @@ -1079,8 +1086,28 @@ export const FormGenerator = forwardRef(func const onSaveType = (type: Type | string) => { handleValueTypeConstChange(typeof type === 'string' ? type : (type as Type).name); if (stack.length > 0) { + if (stack.length > 1) { + const newStack = [...stack] + const currentTop = newStack[newStack.length - 1]; + const newTop = newStack[newStack.length - 2]; + const fieldIndex = newTop.fieldIndex; + if (fieldIndex === undefined) { + return; + } + if (newTop.type.codedata.node === "CLASS") { + const fn = newTop.type.functions?.[fieldIndex]; + if (!fn) { return; } + fn.returnType = currentTop!.type.name; + } else { + const member = newTop.type.members?.[fieldIndex]; + if (!member) { return; } + member.type = currentTop!.type.name; + } + newStack[newStack.length - 2] = newTop; + newStack.pop(); + setStack(newStack); + } setRefetchForCurrentModal(true); - popTypeStack(); } handleSelectedTypeChange(typeof type === 'string' ? type : (type as Type).name); setTypeEditorState({ ...typeEditorState, isOpen: stack.length !== 1 }); @@ -1288,7 +1315,12 @@ export const FormGenerator = forwardRef(func }) } - const getNewTypeCreateForm = (typeName?: string) => { + const getNewTypeCreateForm = (fieldIndex?: number, typeName?: string) => { + const currentTopItem = peekTypeStack(); + if (currentTopItem) { + currentTopItem.fieldIndex = fieldIndex; + replaceTop(currentTopItem); + } pushTypeStack(getDefaultValue(typeName)); } diff --git a/workspaces/ballerina/ballerina-visualizer/src/views/BI/Forms/FormGeneratorNew/index.tsx b/workspaces/ballerina/ballerina-visualizer/src/views/BI/Forms/FormGeneratorNew/index.tsx index d9083dfe928..e74b4282e07 100644 --- a/workspaces/ballerina/ballerina-visualizer/src/views/BI/Forms/FormGeneratorNew/index.tsx +++ b/workspaces/ballerina/ballerina-visualizer/src/views/BI/Forms/FormGeneratorNew/index.tsx @@ -285,6 +285,10 @@ export function FormGeneratorNew(props: FormProps) { if (stack.length === 0) return; setStack((prev) => { const newStack = [...prev]; + //preserve fieldIndex if exists + if (newStack[newStack.length - 1].fieldIndex) { + item.fieldIndex = newStack[newStack.length - 1].fieldIndex; + } newStack[newStack.length - 1] = item; return newStack; }); @@ -630,7 +634,7 @@ export function FormGeneratorNew(props: FormProps) { shouldUpdateNode?: boolean, variableType?: string ) => { - if (!showDiagnostics || isDataMapperEditor) { + if (!showDiagnostics) { setDiagnosticsInfo({ key, diagnostics: [] }); return; } @@ -853,17 +857,37 @@ export function FormGeneratorNew(props: FormProps) { setTypeEditorState({ ...typeEditorState, isOpen: state }); } - const getNewTypeCreateForm = (typeName?: string) => { + const getNewTypeCreateForm = (fieldIndex?: number, typeName?: string) => { + const currentTopItem = peekTypeStack(); + if (currentTopItem) { + currentTopItem.fieldIndex = fieldIndex; + replaceTop(currentTopItem); + } pushTypeStack({ type: defaultType(typeName), isDirty: false }) } - const onSaveType = () => { + + const onSaveType = (type: Type | string) => { + handleValueTypeConstChange(typeof type === 'string' ? type : (type as Type).name); if (stack.length > 0) { + if (stack.length > 1) { + const newStack = [...stack] + const currentTop = newStack[newStack.length - 1]; + const newTop = newStack[newStack.length - 2]; + if (newTop.type.codedata.node === "CLASS") { + newTop.type.functions[newTop.fieldIndex!].returnType = currentTop!.type.name; + } + else { + newTop.type.members[newTop.fieldIndex!].type = currentTop!.type.name; + } + newStack[newStack.length - 2] = newTop; + newStack.pop(); + setStack(newStack); + } setRefetchForCurrentModal(true); - popTypeStack(); } setTypeEditorState({ ...typeEditorState, isOpen: stack.length !== 1 }); } diff --git a/workspaces/ballerina/ballerina-visualizer/src/views/BI/Forms/KnowledgeBaseForm/index.tsx b/workspaces/ballerina/ballerina-visualizer/src/views/BI/Forms/KnowledgeBaseForm/index.tsx index f7bc6c5f663..a32cee765a2 100644 --- a/workspaces/ballerina/ballerina-visualizer/src/views/BI/Forms/KnowledgeBaseForm/index.tsx +++ b/workspaces/ballerina/ballerina-visualizer/src/views/BI/Forms/KnowledgeBaseForm/index.tsx @@ -20,7 +20,7 @@ import { useEffect, useRef, useState } from "react"; import { Codicon } from "@wso2/ui-toolkit"; import styled from "@emotion/styled"; -import { DataMapperDisplayMode, FlowNode, LineRange, SubPanel, SubPanelView } from "@wso2/ballerina-core"; +import { EditorConfig, FlowNode, LineRange, SubPanel, SubPanelView } from "@wso2/ballerina-core"; import { FormValues, ExpressionFormField, @@ -83,7 +83,7 @@ interface KnowledgeBaseFormProps { showProgressIndicator?: boolean; onSubmit: ( node?: FlowNode, - dataMapperMode?: DataMapperDisplayMode, + editorConfig?: EditorConfig, formImports?: FormImports, rawFormValues?: FormValues ) => void; @@ -200,7 +200,7 @@ export function KnowledgeBaseForm(props: KnowledgeBaseFormProps) { try { setSaving(true); const knowledgeBaseNode = mergeFormDataWithFlowNode(knowledgeBaseFormValues, targetLineRange); - onSubmit(knowledgeBaseNode, DataMapperDisplayMode.NONE, formImports); + onSubmit(knowledgeBaseNode, undefined, formImports); } catch (error) { console.error("Error creating vector knowledge base:", error); } finally { diff --git a/workspaces/ballerina/ballerina-visualizer/src/views/BI/FunctionForm/index.tsx b/workspaces/ballerina/ballerina-visualizer/src/views/BI/FunctionForm/index.tsx index 07b44fb2603..1263930ecb9 100644 --- a/workspaces/ballerina/ballerina-visualizer/src/views/BI/FunctionForm/index.tsx +++ b/workspaces/ballerina/ballerina-visualizer/src/views/BI/FunctionForm/index.tsx @@ -112,7 +112,7 @@ export function FunctionForm(props: FunctionFormProps) { fields.forEach((field) => { const primaryInputType = getPrimaryInputType(field.types) if (field.key === "functionNameDescription" || field.key === "typeDescription") { - field.type = "TEXTAREA"; + field.type = "DOC_TEXT"; } if (field.key === "parameters" && primaryInputType && isTemplateType(primaryInputType)) { if ((primaryInputType.template as any).value.parameterDescription) { diff --git a/workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/RecordConfigModal.tsx b/workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/RecordConfigModal.tsx index e80be8c7cc2..f8dba954704 100644 --- a/workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/RecordConfigModal.tsx +++ b/workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/RecordConfigModal.tsx @@ -22,7 +22,7 @@ import styled from "@emotion/styled"; import { useEffect, useRef, useState, RefObject } from "react"; import { useRpcContext } from "@wso2/ballerina-rpc-client"; import { RecordConfigView } from "./RecordConfigView"; -import { ChipExpressionEditorComponent, Context as FormContext, HelperpaneOnChangeOptions, FieldProvider, FormField, FormExpressionEditorProps, getPropertyFromFormField } from "@wso2/ballerina-side-panel"; +import { ChipExpressionEditorComponent, Context as FormContext, HelperpaneOnChangeOptions, FieldProvider, FormField, FormExpressionEditorProps, getPropertyFromFormField, RecordConfigExpressionEditorConfig } from "@wso2/ballerina-side-panel"; import { useForm } from "react-hook-form"; import { debounce } from "lodash"; import ReactMarkdown from "react-markdown"; @@ -704,7 +704,7 @@ export function ConfigureRecordPage(props: ConfigureRecordPageProps) { extractArgsFromFunction={wrappedExtractArgsFromFunction} getHelperPane={wrappedGetHelperPane} sx={{ height: "350px" }} - configuration={new ChipExpressionEditorDefaultConfiguration()} + configuration={new RecordConfigExpressionEditorConfig()} isExpandedVersion={false} /> {formDiagnostics && formDiagnostics.length > 0 && ( diff --git a/workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/Variables.tsx b/workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/Variables.tsx index 2cae01fde03..e2417085433 100644 --- a/workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/Variables.tsx +++ b/workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/Variables.tsx @@ -19,7 +19,7 @@ import { ExpandableList } from "../Components/ExpandableList" import { TypeIndicator } from "../Components/TypeIndicator" import { useRpcContext } from "@wso2/ballerina-rpc-client" -import { DataMapperDisplayMode, ExpressionProperty, FlowNode, LineRange, RecordTypeField } from "@wso2/ballerina-core" +import { EditorConfig, EditorDisplayMode, ExpressionProperty, FlowNode, LineRange, RecordTypeField } from "@wso2/ballerina-core" import { Codicon, CompletionItem, Divider, HelperPaneCustom, SearchBox, ThemeColors, Tooltip, Typography } from "@wso2/ui-toolkit" import { useEffect, useMemo, useRef, useState } from "react" import { getPropertyFromFormField, useFieldContext, InputMode } from "@wso2/ballerina-side-panel" @@ -42,7 +42,7 @@ type VariablesPageProps = { onChange: (value: string, isRecordConfigureChange: boolean, shouldKeepHelper?: boolean) => void; targetLineRange: LineRange; anchorRef: React.RefObject; - handleOnFormSubmit?: (updatedNode?: FlowNode, dataMapperMode?: DataMapperDisplayMode, options?: FormSubmitOptions, openDMInPopup?: boolean) => void; + handleOnFormSubmit?: (updatedNode?: FlowNode, editorConfig?: EditorConfig, options?: FormSubmitOptions, openDMInPopup?: boolean) => void; selectedType?: CompletionItem; filteredCompletions: CompletionItem[]; currentValue: string; @@ -150,7 +150,7 @@ export const Variables = (props: VariablesPageProps) => { setProjectPathUri(URI.file(visualizerContext.projectPath).fsPath); } - const handleSubmit = (updatedNode?: FlowNode, dataMapperMode?: DataMapperDisplayMode) => { + const handleSubmit = (updatedNode?: FlowNode, editorConfig?: EditorConfig) => { newNodeNameRef.current = ""; // Safely extract the variable name as a string, fallback to empty string if not available const varName = typeof updatedNode?.properties?.variable?.value === "string" @@ -159,7 +159,10 @@ export const Variables = (props: VariablesPageProps) => { newNodeNameRef.current = varName; handleOnFormSubmit?.( updatedNode, - dataMapperMode === DataMapperDisplayMode.VIEW ? DataMapperDisplayMode.POPUP : DataMapperDisplayMode.NONE, + { + view: editorConfig?.view, + displayMode: editorConfig?.displayMode === EditorDisplayMode.VIEW ? EditorDisplayMode.POPUP : EditorDisplayMode.NONE + }, { closeSidePanel: false, isChangeFromHelperPane: true, postUpdateCallBack: () => { onClose() diff --git a/workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/index.tsx b/workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/index.tsx index b7d8701783a..756aabe4a5b 100644 --- a/workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/index.tsx +++ b/workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/index.tsx @@ -23,7 +23,7 @@ import { Variables } from './Views/Variables'; import { Inputs } from './Views/Inputs'; import { Documents } from './Views/Documents'; import { DocumentConfig } from './Views/DocumentConfig'; -import { CompletionInsertText, DataMapperDisplayMode, ExpressionProperty, FlowNode, getPrimaryInputType, InputType, LineRange, RecordTypeField } from '@wso2/ballerina-core'; +import { CompletionInsertText, EditorConfig, ExpressionProperty, FlowNode, getPrimaryInputType, InputType, LineRange, RecordTypeField } from '@wso2/ballerina-core'; import { CompletionItem, HelperPaneCustom, HelperPaneHeight, Typography } from '@wso2/ui-toolkit'; import { SlidingPane, SlidingPaneHeader, SlidingPaneNavContainer, SlidingWindow } from '@wso2/ui-toolkit'; import { CreateValue } from './Views/CreateValue'; @@ -59,7 +59,7 @@ export type HelperPaneNewProps = { isAssignIdentifier?: boolean; completions: CompletionItem[], projectPath?: string, - handleOnFormSubmit?: (updatedNode?: FlowNode, dataMapperMode?: DataMapperDisplayMode, options?: FormSubmitOptions) => void + handleOnFormSubmit?: (updatedNode?: FlowNode, editorConfig?: EditorConfig, options?: FormSubmitOptions) => void selectedType?: CompletionItem; filteredCompletions?: CompletionItem[]; isInModal?: boolean; diff --git a/workspaces/ballerina/ballerina-visualizer/src/views/BI/ImportIntegration/ConfigureProjectForm.tsx b/workspaces/ballerina/ballerina-visualizer/src/views/BI/ImportIntegration/ConfigureProjectForm.tsx index 046a80b5ba3..8a7cd5f159f 100644 --- a/workspaces/ballerina/ballerina-visualizer/src/views/BI/ImportIntegration/ConfigureProjectForm.tsx +++ b/workspaces/ballerina/ballerina-visualizer/src/views/BI/ImportIntegration/ConfigureProjectForm.tsx @@ -18,14 +18,17 @@ import { ActionButtons, Typography } from "@wso2/ui-toolkit"; import { useState } from "react"; +import { useRpcContext } from "@wso2/ballerina-rpc-client"; +import { ValidateProjectFormErrorField } from "@wso2/ballerina-core"; import { BodyText } from "../../styles"; import { ProjectFormData, ProjectFormFields } from "../ProjectForm/ProjectFormFields"; -import { isFormValid } from "../ProjectForm/utils"; +import { validatePackageName } from "../ProjectForm/utils"; import { MultiProjectFormData, MultiProjectFormFields } from "./components/MultiProjectFormFields"; import { ButtonWrapper } from "./styles"; import { ConfigureProjectFormProps } from "./types"; export function ConfigureProjectForm({ isMultiProject, onNext, onBack }: ConfigureProjectFormProps) { + const { rpcClient } = useRpcContext(); const [singleProjectData, setSingleProjectData] = useState({ integrationName: "", packageName: "", @@ -44,48 +47,163 @@ export function ConfigureProjectForm({ isMultiProject, onNext, onBack }: Configu createDirectory: true, }); + const [isValidating, setIsValidating] = useState(false); + const [pathError, setPathError] = useState(null); + const [folderNameError, setFolderNameError] = useState(null); + const [singleProjectIntegrationNameError, setSingleProjectIntegrationNameError] = useState(null); + const [singleProjectPathError, setSingleProjectPathError] = useState(null); + const [singleProjectPackageNameError, setSingleProjectPackageNameError] = useState(null); + const handleSingleProjectFormChange = (data: Partial) => { setSingleProjectData(prev => ({ ...prev, ...data })); + // Clear validation errors when form data changes + if (singleProjectIntegrationNameError) { + setSingleProjectIntegrationNameError(null); + } + if (singleProjectPathError) { + setSingleProjectPathError(null); + } + if (singleProjectPackageNameError) { + setSingleProjectPackageNameError(null); + } }; const handleMultiProjectFormChange = (data: Partial) => { setMultiProjectData(prev => ({ ...prev, ...data })); + // Clear validation errors when form data changes + if (pathError) { + setPathError(null); + } + if (folderNameError) { + setFolderNameError(null); + } }; - const handleCreateSingleProject = () => { - onNext({ - projectName: singleProjectData.integrationName, - packageName: singleProjectData.packageName, - projectPath: singleProjectData.path, - createDirectory: singleProjectData.createDirectory, - createAsWorkspace: singleProjectData.createAsWorkspace, - workspaceName: singleProjectData.workspaceName, - orgName: singleProjectData.orgName || undefined, - version: singleProjectData.version || undefined, - isLibrary: singleProjectData.isLibrary, - }); - }; + const handleCreateSingleProject = async () => { + setIsValidating(true); + setSingleProjectIntegrationNameError(null); + setSingleProjectPathError(null); + setSingleProjectPackageNameError(null); + + // Validate required fields first + let hasError = false; + + if (singleProjectData.integrationName.length < 2) { + setSingleProjectIntegrationNameError("Integration name must be at least 2 characters"); + hasError = true; + } + + if (singleProjectData.packageName.length < 2) { + setSingleProjectPackageNameError("Package name must be at least 2 characters"); + hasError = true; + } else { + const packageNameError = validatePackageName(singleProjectData.packageName, singleProjectData.integrationName); + if (packageNameError) { + setSingleProjectPackageNameError(packageNameError); + hasError = true; + } + } + + if (singleProjectData.path.length < 2) { + setSingleProjectPathError("Please select a path for your project"); + hasError = true; + } - const handleCreateMultiProject = () => { - onNext({ - projectName: multiProjectData.rootFolderName, - packageName: multiProjectData.rootFolderName, - projectPath: multiProjectData.path, - createDirectory: multiProjectData.createDirectory, - createAsWorkspace: false, - }); + if (hasError) { + setIsValidating(false); + return; + } + + try { + // Validate the project path + const validationResult = await rpcClient.getBIDiagramRpcClient().validateProjectPath({ + projectPath: singleProjectData.path, + projectName: singleProjectData.createAsWorkspace ? singleProjectData.workspaceName : singleProjectData.packageName, + createDirectory: singleProjectData.createDirectory, + }); + + if (!validationResult.isValid) { + // Show error on the appropriate field + if (validationResult.errorField === ValidateProjectFormErrorField.PATH) { + setSingleProjectPathError(validationResult.errorMessage || "Invalid project path"); + } else if (validationResult.errorField === ValidateProjectFormErrorField.NAME) { + setSingleProjectPackageNameError(validationResult.errorMessage || "Invalid project name"); + } + setIsValidating(false); + return; + } + + // If validation passes, proceed + onNext({ + projectName: singleProjectData.integrationName, + packageName: singleProjectData.packageName, + projectPath: singleProjectData.path, + createDirectory: singleProjectData.createDirectory, + createAsWorkspace: singleProjectData.createAsWorkspace, + workspaceName: singleProjectData.workspaceName, + orgName: singleProjectData.orgName || undefined, + version: singleProjectData.version || undefined, + }); + } catch (error) { + setSingleProjectPathError("An error occurred during validation"); + setIsValidating(false); + } }; - const isMultiProjectFormValid = () => { - // Path is always required - if (!multiProjectData.path.trim()) { - return false; + const handleCreateMultiProject = async () => { + setIsValidating(true); + setPathError(null); + setFolderNameError(null); + + // Validate required fields first + let hasError = false; + + if (!multiProjectData.path.trim() || multiProjectData.path.length < 2) { + setPathError("Please select a path for your project"); + hasError = true; } - // Folder name is only required if creating a new directory - if (multiProjectData.createDirectory && !multiProjectData.rootFolderName.trim()) { - return false; + + if (multiProjectData.createDirectory && (!multiProjectData.rootFolderName.trim() || multiProjectData.rootFolderName.length < 1)) { + setFolderNameError("Folder name is required when creating a new directory"); + hasError = true; + } + + if (hasError) { + setIsValidating(false); + return; + } + + try { + // Validate the project path + const validationResult = await rpcClient.getBIDiagramRpcClient().validateProjectPath({ + projectPath: multiProjectData.path, + projectName: multiProjectData.rootFolderName, + createDirectory: multiProjectData.createDirectory, + }); + + if (!validationResult.isValid) { + // Show error on the appropriate field + if (validationResult.errorField === ValidateProjectFormErrorField.PATH) { + setPathError(validationResult.errorMessage || "Invalid project path"); + } else if (validationResult.errorField === ValidateProjectFormErrorField.NAME) { + setFolderNameError(validationResult.errorMessage || "Invalid folder name"); + } + setIsValidating(false); + return; + } + + // If validation passes, proceed + onNext({ + projectName: multiProjectData.rootFolderName, + packageName: multiProjectData.rootFolderName, + projectPath: multiProjectData.path, + createDirectory: multiProjectData.createDirectory, + createAsWorkspace: false, + }); + } catch (error) { + setPathError("An error occurred during validation"); + setIsValidating(false); } - return true; }; return ( @@ -98,14 +216,16 @@ export function ConfigureProjectForm({ isMultiProject, onNext, onBack }: Configu >({}); - - const isImportDisabled = importSourcePath.length < 2 || !selectedIntegration; + const [sourcePathError, setSourcePathError] = useState(null); + const [integrationSelectionError, setIntegrationSelectionError] = useState(null); const handleIntegrationSelection = (integration: MigrationTool) => { // Reset state when a new integration is selected setImportSourcePath(""); + setSourcePathError(null); + setIntegrationSelectionError(null); onSelectIntegration(integration); const defaultParams = integration.parameters.reduce((acc, param) => { acc[param.key] = param.defaultValue; @@ -66,23 +68,43 @@ export function ImportIntegrationForm({ const result = await rpcClient.getCommonRpcClient().selectFileOrFolderPath(); if (result?.path) { setImportSourcePath(result.path); + setSourcePathError(null); } }; const handleImportIntegration = () => { - if (!selectedIntegration || !importSourcePath) return; + setSourcePathError(null); + setIntegrationSelectionError(null); + + // Validate required fields + let hasError = false; + + if (!selectedIntegration) { + setIntegrationSelectionError("Please select an integration platform"); + hasError = true; + } + + if (!importSourcePath || importSourcePath.trim().length === 0) { + setSourcePathError("Please select your project folder"); + hasError = true; + } + + if (hasError) { + return; + } + // Proceed with import - backend will validate the project structure const finalParams: FinalIntegrationParams = { importSourcePath, - type: selectedIntegration.title, + type: selectedIntegration!.title, parameters: integrationParams, }; setImportParams(finalParams); - if (selectedIntegration.needToPull) { - pullIntegrationTool(selectedIntegration.commandName, selectedIntegration.requiredVersion); + if (selectedIntegration!.needToPull) { + pullIntegrationTool(selectedIntegration!.commandName, selectedIntegration!.requiredVersion); } else { - handleStartImport(finalParams, selectedIntegration, toolPullProgress); + handleStartImport(finalParams, selectedIntegration!, toolPullProgress); } }; @@ -99,10 +121,15 @@ export function ImportIntegrationForm({ This wizard converts an external integration project from MuleSoft or TIBCO into a ready-to-use BI project. - + Choose the source platform Select the integration platform that your current project uses: + {integrationSelectionError && ( +
+ {integrationSelectionError} +
+ )} {migrationTools.map((tool) => { return ( @@ -121,13 +148,18 @@ export function ImportIntegrationForm({ {selectedIntegration && ( - Select Your Project Folder + Select Your Project Folder {selectedIntegration.description} - { + setImportSourcePath(value); + setSourcePathError(null); + }} + errorMsg={sourcePathError || undefined} /> )} @@ -151,8 +183,7 @@ export function ImportIntegrationForm({ primaryButton={{ text: "Start Migration", onClick: handleImportIntegration, - disabled: isImportDisabled, - tooltip: getImportTooltip(selectedIntegration, importSourcePath) + disabled: false }} secondaryButton={{ text: "Back", diff --git a/workspaces/ballerina/ballerina-visualizer/src/views/BI/ImportIntegration/components/MultiProjectFormFields.tsx b/workspaces/ballerina/ballerina-visualizer/src/views/BI/ImportIntegration/components/MultiProjectFormFields.tsx index 2cc6df93072..24d42e3dcce 100644 --- a/workspaces/ballerina/ballerina-visualizer/src/views/BI/ImportIntegration/components/MultiProjectFormFields.tsx +++ b/workspaces/ballerina/ballerina-visualizer/src/views/BI/ImportIntegration/components/MultiProjectFormFields.tsx @@ -17,7 +17,7 @@ */ import { useEffect } from "react"; -import { LocationSelector, TextField, CheckBox } from "@wso2/ui-toolkit"; +import { DirectorySelector, TextField, CheckBox } from "@wso2/ui-toolkit"; import styled from "@emotion/styled"; import { useRpcContext } from "@wso2/ballerina-rpc-client"; @@ -44,9 +44,11 @@ export interface MultiProjectFormData { export interface MultiProjectFormFieldsProps { formData: MultiProjectFormData; onFormDataChange: (data: Partial) => void; + pathError?: string; + folderNameError?: string; } -export function MultiProjectFormFields({ formData, onFormDataChange }: MultiProjectFormFieldsProps) { +export function MultiProjectFormFields({ formData, onFormDataChange, pathError, folderNameError }: MultiProjectFormFieldsProps) { const { rpcClient } = useRpcContext(); const handleIntegrationName = (value: string) => { @@ -70,11 +72,14 @@ export function MultiProjectFormFields({ formData, onFormDataChange }: MultiProj return ( <> - onFormDataChange({ path: value })} + errorMsg={pathError} /> @@ -97,6 +102,7 @@ export function MultiProjectFormFields({ formData, onFormDataChange }: MultiProj placeholder="Enter folder name" autoFocus={true} required={true} + errorMsg={folderNameError || ""} /> This folder will contain all migrated packages from this integration. diff --git a/workspaces/ballerina/ballerina-visualizer/src/views/BI/ImportIntegration/utils.ts b/workspaces/ballerina/ballerina-visualizer/src/views/BI/ImportIntegration/utils.ts index 4767545d4a5..f66fd1a7f1b 100644 --- a/workspaces/ballerina/ballerina-visualizer/src/views/BI/ImportIntegration/utils.ts +++ b/workspaces/ballerina/ballerina-visualizer/src/views/BI/ImportIntegration/utils.ts @@ -16,24 +16,11 @@ * under the License. */ -import { ImportIntegrationResponse, MigrationTool, ProjectMigrationResult } from "@wso2/ballerina-core"; +import { ImportIntegrationResponse, ProjectMigrationResult } from "@wso2/ballerina-core"; import { CoverageLevel, MigrationDisplayState } from "./types"; import { BallerinaRpcClient } from "@wso2/ballerina-rpc-client"; export const SELECTION_TEXT = "To begin, choose a source platform from the options above."; -const IMPORT_DISABLED_TOOLTIP = "Please select a source platform to continue."; -const PATH_SELECTION_TOOLTIP = "Please select a project folder to continue."; -const IMPORT_ENABLED_TOOLTIP = "Begin converting your selected project and view the progress."; - -export const getImportTooltip = (selectedIntegration: MigrationTool, importSourcePath: string) => { - if (!selectedIntegration) { - return IMPORT_DISABLED_TOOLTIP; - } - if (importSourcePath.length < 2) { - return PATH_SELECTION_TOOLTIP; - } - return IMPORT_ENABLED_TOOLTIP; -}; export const sanitizeProjectName = (name: string): string => { return name.replace(/[^a-z0-9]/gi, "_").toLowerCase(); diff --git a/workspaces/ballerina/ballerina-visualizer/src/views/BI/ProjectForm/AddProjectForm.tsx b/workspaces/ballerina/ballerina-visualizer/src/views/BI/ProjectForm/AddProjectForm.tsx index 30e81cc3739..b304fb52f82 100644 --- a/workspaces/ballerina/ballerina-visualizer/src/views/BI/ProjectForm/AddProjectForm.tsx +++ b/workspaces/ballerina/ballerina-visualizer/src/views/BI/ProjectForm/AddProjectForm.tsx @@ -30,6 +30,7 @@ import { import { AddProjectFormFields } from "./AddProjectFormFields"; import { AddProjectFormData } from "./types"; import { isFormValidAddProject } from "./utils"; +import { ValidateProjectFormErrorField } from "@wso2/ballerina-core"; export function AddProjectForm() { const { rpcClient } = useRpcContext(); @@ -44,9 +45,18 @@ export function AddProjectForm() { const [isInWorkspace, setIsInWorkspace] = useState(false); const [path, setPath] = useState(""); const [isLoading, setIsLoading] = useState(false); + const [pathValidationError, setPathValidationError] = useState(null); + const [packageNameValidationError, setPackageNameValidationError] = useState(null); const handleFormDataChange = (data: Partial) => { setFormData(prev => ({ ...prev, ...data })); + // Clear validation errors when form data changes + if (pathValidationError) { + setPathValidationError(null); + } + if (packageNameValidationError) { + setPackageNameValidationError(null); + } }; useEffect(() => { @@ -59,18 +69,45 @@ export function AddProjectForm() { }); }, []); - const handleAddProject = () => { + const handleAddProject = async () => { setIsLoading(true); - rpcClient.getBIDiagramRpcClient().addProjectToWorkspace({ - projectName: formData.integrationName, - packageName: formData.packageName, - convertToWorkspace: !isInWorkspace, - path: path, - workspaceName: formData.workspaceName, - orgName: formData.orgName || undefined, - version: formData.version || undefined, - isLibrary: formData.isLibrary, - }); + setPathValidationError(null); + setPackageNameValidationError(null); + + try { + // Validate the project path + const validationResult = await rpcClient.getBIDiagramRpcClient().validateProjectPath({ + projectPath: path, + projectName: formData.packageName, + createDirectory: true, + }); + + if (!validationResult.isValid) { + // Show error on the appropriate field + if (validationResult.errorField === ValidateProjectFormErrorField.PATH) { + setPathValidationError(validationResult.errorMessage || "Invalid project path"); + } else if (validationResult.errorField === ValidateProjectFormErrorField.NAME) { + setPackageNameValidationError(validationResult.errorMessage || "Invalid project name"); + } + setIsLoading(false); + return; + } + + // If validation passes, add the project + rpcClient.getBIDiagramRpcClient().addProjectToWorkspace({ + projectName: formData.integrationName, + packageName: formData.packageName, + convertToWorkspace: !isInWorkspace, + path: path, + workspaceName: formData.workspaceName, + orgName: formData.orgName || undefined, + version: formData.version || undefined, + isLibrary: formData.isLibrary, + }); + } catch (error) { + setPathValidationError("An error occurred during validation"); + setIsLoading(false); + } }; const goBack = () => { @@ -96,10 +133,23 @@ export function AddProjectForm() { formData={formData} onFormDataChange={handleFormDataChange} isInWorkspace={isInWorkspace} + packageNameValidationError={packageNameValidationError || undefined} /> + {pathValidationError && ( + + {pathValidationError} + + )} diff --git a/workspaces/ballerina/ballerina-visualizer/src/views/BI/ProjectForm/utils.ts b/workspaces/ballerina/ballerina-visualizer/src/views/BI/ProjectForm/utils.ts index 8bcf3ff9442..2a4c37c0407 100644 --- a/workspaces/ballerina/ballerina-visualizer/src/views/BI/ProjectForm/utils.ts +++ b/workspaces/ballerina/ballerina-visualizer/src/views/BI/ProjectForm/utils.ts @@ -62,15 +62,6 @@ export const validatePackageName = (name: string, integrationName: string): stri return null; // No error }; -export const isFormValid = (formData: ProjectFormData): boolean => { - return ( - formData.integrationName.length >= 2 && - formData.packageName.length >= 2 && - formData.path.length >= 2 && - validatePackageName(formData.packageName, formData.integrationName) === null - ); -}; - export const isFormValidAddProject = (formData: AddProjectFormData, isInWorkspace: boolean): boolean => { return ( formData.integrationName.length >= 2 && diff --git a/workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/ResourceForm/ResourceResponse/ResponseItem.tsx b/workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/ResourceForm/ResourceResponse/ResponseItem.tsx index 430b467a37e..0e962894031 100644 --- a/workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/ResourceForm/ResourceResponse/ResponseItem.tsx +++ b/workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/ResourceForm/ResourceResponse/ResponseItem.tsx @@ -45,11 +45,7 @@ export function ResponseItem(props: ParamItemProps) { }; const getFormattedResponse = (response: StatusCodeResponse, method: HTTP_METHOD) => { - if (response.statusCode.value && (Number(response.statusCode.value) === 200 || Number(response.statusCode.value) === 201)) { - return getDefaultResponse(method); - } else { - return response.statusCode.value || getDefaultResponse(method); - } + return response.statusCode.value || getDefaultResponse(method); }; return ( diff --git a/workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/ServiceConfigureView.tsx b/workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/ServiceConfigureView.tsx index b8cae4bb390..1bac8837c8b 100644 --- a/workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/ServiceConfigureView.tsx +++ b/workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/ServiceConfigureView.tsx @@ -18,7 +18,7 @@ import { useEffect, useState, useRef } from "react"; import styled from "@emotion/styled"; -import { ConfigVariable, DIRECTORY_MAP, getPrimaryInputType, LineRange, ListenerModel, NodePosition, ProjectStructureArtifactResponse, ServiceModel } from "@wso2/ballerina-core"; +import { ConfigProperties, ConfigVariable, DIRECTORY_MAP, getPrimaryInputType, LineRange, ListenerModel, NodePosition, ProjectStructureArtifactResponse, ServiceModel } from "@wso2/ballerina-core"; import { useRpcContext } from "@wso2/ballerina-rpc-client"; import { Button, Codicon, Icon, LinkButton, ProgressRing, SidePanelBody, SplitView, TabPanel, ThemeColors, TreeView, TreeViewItem, Typography, View, ViewContent } from "@wso2/ui-toolkit"; import { TopNavigationBar } from "../../../components/TopNavigationBar"; @@ -202,6 +202,7 @@ export function ServiceConfigureView(props: ServiceConfigureProps) { const [isSaving, setIsSaving] = useState(false); const [hasChanges, setHasChanges] = useState(false); + const [existingListenerType, setExistingListenerType] = useState(""); // Example: "Listener", "CdcListener" const [selectedListener, setSelectedListener] = useState(null); @@ -558,6 +559,12 @@ export function ServiceConfigureView(props: ServiceConfigureProps) { setIsSaving(false); } + const handleSetListenerType = (type: string) => { + if (!existingListenerType) { + setExistingListenerType(type); + } + } + return ( @@ -733,6 +740,7 @@ export function ServiceConfigureView(props: ServiceConfigureProps) { filePath={listener.path} position={listener.position} onChange={handleListenerChange} + setListenerType={handleSetListenerType} /> @@ -747,6 +755,7 @@ export function ServiceConfigureView(props: ServiceConfigureProps) { packageName={serviceModel.packageName} version={serviceModel.version} moduleName={serviceModel.moduleName} + type={existingListenerType} onAttachListener={handleOnAttachListener} attachedListeners={listeners.map(listener => listener.name)} /> @@ -776,10 +785,11 @@ interface ServiceConfigureListenerEditViewProps { filePath: string; position: NodePosition; onChange?: (data: ListenerModel, filePath: string, position: NodePosition) => void; + setListenerType?: (type: string) => void; } function ServiceConfigureListenerEditView(props: ServiceConfigureListenerEditViewProps) { - const { filePath, position, onChange } = props; + const { filePath, position, onChange, setListenerType } = props; const { rpcClient } = useRpcContext(); const [listenerModel, setListenerModel] = useState(undefined); @@ -792,9 +802,23 @@ function ServiceConfigureListenerEditView(props: ServiceConfigureListenerEditVie rpcClient.getServiceDesignerRpcClient().getListenerModelFromCode({ filePath, codedata: { lineRange } }).then(res => { console.log("Editing Listener Model: ", res.listener) setListenerModel(res.listener); + setListenerTypeFromProperties(res.listener.properties); }) }, [position]); + const setListenerTypeFromProperties = (properties: ConfigProperties) => { + // The canonical key for the listener type property in config is "listenerType" + // Find the object key where the property is for listenerType or label "Listener Type" + const listenerTypeKey = Object.keys(properties).find( + key => + (properties[key] as any).name === "listenerType" || + (properties[key] as any).metadata?.label === "Listener Type" + ); + if (listenerTypeKey && properties[listenerTypeKey]?.value) { + setListenerType(properties[listenerTypeKey].value); + } + }; + const onSubmit = async (value: ListenerModel) => { setSaving(true); const res = await rpcClient.getServiceDesignerRpcClient().updateListenerSourceCode({ filePath, listener: value }); @@ -858,6 +882,7 @@ interface AttachListenerModalProps { moduleName: string; packageName: string; version: string; + type: string; attachedListeners: string[]; onAttachListener: (listenerName: string) => void; } @@ -895,6 +920,7 @@ function AttachListenerModal(props: AttachListenerModalProps) { packageName: props.packageName, moduleName: props.moduleName, version: props.version, + type: props.type, }, filePath: props.filePath }; diff --git a/workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/components/ResourceAccordion.tsx b/workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/components/ResourceAccordion.tsx index c10e6634961..e1649567c49 100644 --- a/workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/components/ResourceAccordion.tsx +++ b/workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/components/ResourceAccordion.tsx @@ -20,6 +20,7 @@ import React, { useState } from 'react'; import styled from '@emotion/styled'; import { Button, Codicon, Confirm, Icon } from '@wso2/ui-toolkit'; import { FunctionModel } from '@wso2/ballerina-core'; +import { ResourceAccordionSkeleton } from '../../../../components/Skeletons'; import { canDataBind } from '../utils'; @@ -141,6 +142,7 @@ export function ResourceAccordion(params: ResourceAccordionProps) { const [isOpen, setIsOpen] = useState(false); const [isConfirmOpen, setConfirmOpen] = useState(false); const [confirmEl, setConfirmEl] = React.useState(null); + const [isDeleting, setIsDeleting] = useState(false); const toggleAccordion = () => { @@ -169,7 +171,12 @@ export function ResourceAccordion(params: ResourceAccordionProps) { const handleConfirm = (status: boolean) => { if (status) { - onDeleteResource && onDeleteResource(functionModel); + setIsDeleting(true); + try { + onDeleteResource && onDeleteResource(functionModel); + } catch (error) { + setIsDeleting(false); + } } setConfirmOpen(false); setConfirmEl(null); @@ -179,6 +186,10 @@ export function ResourceAccordion(params: ResourceAccordionProps) { onResourceImplement(functionModel) } + if (isDeleting) { + return ; + } + return ( diff --git a/workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/components/ResourceAccordionV2.tsx b/workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/components/ResourceAccordionV2.tsx index bc45603995c..54ade9d0e3f 100644 --- a/workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/components/ResourceAccordionV2.tsx +++ b/workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/components/ResourceAccordionV2.tsx @@ -21,6 +21,7 @@ import styled from '@emotion/styled'; import { Button, Codicon, Confirm, Icon } from '@wso2/ui-toolkit'; import { CodeData, FunctionModel, ProjectStructureArtifactResponse } from '@wso2/ballerina-core'; import { useRpcContext } from '@wso2/ballerina-rpc-client'; +import { ResourceAccordionSkeleton } from '../../../../components/Skeletons'; type MethodProp = { color: string; @@ -96,6 +97,7 @@ const MethodBox = styled.div` const MethodSection = styled.div` display: flex; + align-items: center; gap: 4px; `; @@ -141,7 +143,6 @@ const ActionButton = styled(Button)` } `; - export interface ResourceAccordionPropsV2 { resource: ProjectStructureArtifactResponse; onEditResource: (resource: FunctionModel) => void; @@ -158,6 +159,7 @@ export function ResourceAccordionV2(params: ResourceAccordionPropsV2) { const [isOpen, setIsOpen] = useState(false); const [isConfirmOpen, setConfirmOpen] = useState(false); const [confirmEl, setConfirmEl] = React.useState(null); + const [isDeleting, setIsDeleting] = useState(false); const { rpcClient } = useRpcContext(); @@ -195,8 +197,13 @@ export function ResourceAccordionV2(params: ResourceAccordionPropsV2) { const handleConfirm = async (status: boolean) => { if (status) { - const functionModel = await getFunctionModel(); - onDeleteResource && onDeleteResource(functionModel.function); + setIsDeleting(true); + try { + const functionModel = await getFunctionModel(); + onDeleteResource && onDeleteResource(functionModel.function); + } catch (error) { + setIsDeleting(false); + } } setConfirmOpen(false); setConfirmEl(null); @@ -228,6 +235,10 @@ export function ResourceAccordionV2(params: ResourceAccordionPropsV2) { } } + if (isDeleting) { + return ; + } + return ( diff --git a/workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/index.tsx b/workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/index.tsx index 8e6b5f7b1a9..2edc88460ba 100644 --- a/workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/index.tsx +++ b/workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/index.tsx @@ -248,11 +248,14 @@ export function ServiceDesigner(props: ServiceDesignerProps) { const onCreateFunctions = serviceModel.functions.filter(fn => fn.metadata?.label === 'onCreate'); const onDeleteFunctions = serviceModel.functions.filter(fn => fn.metadata?.label === 'onDelete'); + const deprecatedFunctions = serviceModel.functions.filter(fn => fn.metadata?.label === 'EVENT'); const hasAvailableOnCreate = onCreateFunctions.length > 0 && onCreateFunctions.some(fn => !fn.enabled); const hasAvailableOnDelete = onDeleteFunctions.length > 0 && onDeleteFunctions.some(fn => !fn.enabled); + const hasDeprecatedFunctions = deprecatedFunctions.length > 0 && deprecatedFunctions.some(fn => fn.enabled); - return hasAvailableOnCreate || hasAvailableOnDelete; + // Remove the add handler option if deprecated APIs present + return (hasAvailableOnCreate || hasAvailableOnDelete) && !hasDeprecatedFunctions; }; useEffect(() => { @@ -818,7 +821,7 @@ export function ServiceDesigner(props: ServiceDesignerProps) { /> Configure { - serviceModel && (isHttpService || isMcpService || isFtpService) && ( + serviceModel && (isHttpService || isMcpService) && ( <> + + + + + ); +}; diff --git a/workspaces/ballerina/ballerina-visualizer/src/views/EvalsetViewer/EditableTraceMessage.tsx b/workspaces/ballerina/ballerina-visualizer/src/views/EvalsetViewer/EditableTraceMessage.tsx new file mode 100644 index 00000000000..c74f2fa8240 --- /dev/null +++ b/workspaces/ballerina/ballerina-visualizer/src/views/EvalsetViewer/EditableTraceMessage.tsx @@ -0,0 +1,272 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React, { useState, useRef, useEffect } from "react"; +import styled from "@emotion/styled"; +import { MessageBubble, preprocessLatex } from "../AgentChatPanel/Components/ChatInterface"; +import { Icon } from "@wso2/ui-toolkit"; +import ReactMarkdown from "react-markdown"; +import remarkMath from 'remark-math'; +import remarkGfm from 'remark-gfm'; +import rehypeKatex from 'rehype-katex'; + +const EditableContainer = styled.div<{ isUser: boolean }>` + position: relative; +`; + +const EditIconButton = styled.button<{ isUser: boolean }>` + position: absolute; + top: -10px; + ${(props: { isUser: boolean; }) => props.isUser ? 'left: -10px;' : 'right: -10px;'} + background: var(--vscode-editor-background); + color: var(--vscode-foreground); + border: 1px solid var(--vscode-panel-border); + border-radius: 8px; + padding: 4px; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + z-index: 10; + + opacity: 0; + transform: ${(props: { isUser: boolean; }) => props.isUser ? 'translate(-4px, -4px)' : 'translate(4px, -4px)'}; + + transition: + opacity 0.2s ease, + transform 0.2s ease, + background-color 0.15s ease, + border-color 0.15s ease; + + &:hover { + background-color: var(--vscode-list-hoverBackground); + border-color: var(--vscode-focusBorder); + } + + &:active { + transform: translate(0, 0) scale(0.95); + } +`; + +const EditableContent = styled.div` + min-height: 20px; + outline: none; + font-family: var(--vscode-font-family); + font-size: inherit; + line-height: inherit; + white-space: pre-wrap; + word-wrap: break-word; + + &:empty:before { + content: attr(data-placeholder); + color: var(--vscode-input-placeholderForeground); + } +`; + +const EditActions = styled.div<{ isUser: boolean }>` + display: flex; + gap: 4px; + margin-top: 16px; + justify-content: flex-end; +`; + +const EditingMessageBubble = styled(MessageBubble)` + display: flex; + flex-direction: column; + flex-shrink: 1; + min-width: 200px; + padding: 12px 14px; +`; + +const SaveButton = styled.button` + background-color: var(--vscode-button-background); + color: var(--vscode-button-foreground); + border: none; + border-radius: 4px; + padding: 4px 8px; + cursor: pointer; + font-size: 13px; + font-weight: 500; + white-space: nowrap; + + &:hover { + background-color: var(--vscode-button-hoverBackground); + } +`; + +const CancelButton = styled.button` + background-color: var(--vscode-button-secondaryBackground); + color: var(--vscode-button-secondaryForeground); + border: none; + border-radius: 4px; + padding: 4px 8px; + cursor: pointer; + font-size: 13px; + white-space: nowrap; + + &:hover { + background-color: var(--vscode-button-secondaryHoverBackground); + } +`; + +interface EditableTraceMessageProps { + traceId: string; + isUser: boolean; + content: unknown; + isEditMode: boolean; + onSave: (traceId: string, content: string) => void; +} + +export const EditableTraceMessage: React.FC = ({ + traceId, + isUser, + content, + isEditMode, + onSave, +}) => { + const [isEditing, setIsEditing] = useState(false); + const [editValue, setEditValue] = useState(""); + const editableRef = useRef(null); + + const contentString = typeof content === 'string' ? content : JSON.stringify(content, null, 2); + + useEffect(() => { + if (isEditing && editableRef.current) { + // Set initial content + editableRef.current.textContent = editValue; + editableRef.current.focus(); + // Move cursor to end + const range = document.createRange(); + const selection = window.getSelection(); + range.selectNodeContents(editableRef.current); + range.collapse(false); + selection?.removeAllRanges(); + selection?.addRange(range); + } + }, [isEditing]); + + // Reset editing state when edit mode is exited + useEffect(() => { + if (!isEditMode && isEditing) { + setIsEditing(false); + setEditValue(""); + } + }, [isEditMode, isEditing]); + + const handleStartEdit = () => { + setEditValue(contentString); + setIsEditing(true); + }; + + const handleSave = () => { + const content = editableRef.current?.textContent || ""; + onSave(traceId, content); + setIsEditing(false); + }; + + const handleCancel = () => { + setIsEditing(false); + setEditValue(""); + }; + + const handleInput = () => { + if (editableRef.current) { + setEditValue(editableRef.current.textContent || ""); + } + }; + + const handleKeyDown = (e: React.KeyboardEvent) => { + if (e.key === 'Enter' && (e.ctrlKey || e.metaKey)) { + e.preventDefault(); + handleSave(); + } else if (e.key === 'Escape') { + e.preventDefault(); + handleCancel(); + } + }; + + const handlePaste = (e: React.ClipboardEvent) => { + e.preventDefault(); + const text = e.clipboardData.getData('text/plain'); + const selection = window.getSelection(); + if (selection && selection.rangeCount > 0) { + const range = selection.getRangeAt(0); + range.deleteContents(); + range.insertNode(document.createTextNode(text)); + range.collapse(false); + selection.removeAllRanges(); + selection.addRange(range); + } + + if (editableRef.current) { + setEditValue(editableRef.current.textContent || ""); + } + }; + + if (isEditing) { + return ( + + + + Cancel + Save + + + ); + } + + return ( + + + + {preprocessLatex(contentString)} + + + {isEditMode && ( + + + + )} + + ); +}; diff --git a/workspaces/ballerina/ballerina-visualizer/src/views/EvalsetViewer/EvalThreadViewer.tsx b/workspaces/ballerina/ballerina-visualizer/src/views/EvalsetViewer/EvalThreadViewer.tsx new file mode 100644 index 00000000000..d97b56dadba --- /dev/null +++ b/workspaces/ballerina/ballerina-visualizer/src/views/EvalsetViewer/EvalThreadViewer.tsx @@ -0,0 +1,917 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React, { useState } from "react"; +import styled from "@emotion/styled"; +import { EvalThread, EvalSet, EvalFunctionCall, EvalsetTrace, EvalToolSchema, AvailableNode } from "@wso2/ballerina-core"; +import { MessageContainer, ProfilePic } from "../AgentChatPanel/Components/ChatInterface"; +import { Button, Icon } from "@wso2/ui-toolkit"; +import { TopNavigationBar } from "../../components/TopNavigationBar"; +import { useRpcContext } from "@wso2/ballerina-rpc-client"; +import { EditableTraceMessage } from "./EditableTraceMessage"; +import { ToolCallsList } from "./ToolCallsList"; +import { ToolEditorModal } from "./ToolEditorModal"; +import { ConfirmationModal } from "./ConfirmationModal"; +import { + DndContext, + closestCenter, + KeyboardSensor, + PointerSensor, + useSensor, + useSensors, + DragEndEvent, +} from '@dnd-kit/core'; +import { + arrayMove, + SortableContext, + sortableKeyboardCoordinates, + useSortable, + verticalListSortingStrategy, +} from '@dnd-kit/sortable'; +import { CSS } from '@dnd-kit/utilities'; +import { + cloneEvalThread, + updateTraceUserMessage, + updateTraceAgentOutput, + updateToolCallsInTrace, + getContentType, + deserializeContent, + generateToolCallId, + createNewTrace, + getToolCallsFromTrace +} from "./utils/traceAdapters"; + +// --- LAYOUT COMPONENTS --- + +const PageWrapper = styled.div` + height: 100%; + width: 100%; + display: flex; + flex-direction: column; +`; + +const Container = styled.div` + flex: 1; + width: 100%; + background-color: var(--vscode-editor-background); + color: var(--vscode-editor-foreground); + display: flex; + flex-direction: column; + overflow: hidden; + + *, *::before, *::after { + box-sizing: border-box; + } +`; + +const Header = styled.div` + top: 0; + padding: 16px 24px; + position: sticky; + background-color: var(--vscode-editorWidget-background); + border-top: 1px solid var(--vscode-panel-border); + border-bottom: 1px solid var(--vscode-panel-border); + z-index: 10; + display: flex; + align-items: flex-start; + justify-content: space-between; +`; + +const EditModeBanner = styled.div<{ $isVisible: boolean }>` + background-color: var(--vscode-textBlockQuote-background); + border-left: 3px solid var(--vscode-editorInfo-foreground); + display: flex; + align-items: flex-start; + gap: 12px; + + overflow: hidden; + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + + max-height: ${(props: { $isVisible: any; }) => (props.$isVisible ? '100px' : '0px')}; + opacity: ${(props: { $isVisible: any; }) => (props.$isVisible ? 1 : 0)}; + padding: ${(props: { $isVisible: any; }) => (props.$isVisible ? '12px 24px' : '0px 24px')}; + border-bottom: 1px solid ${(props: { $isVisible: any; }) => (props.$isVisible ? 'var(--vscode-panel-border)' : 'transparent')}; + margin-bottom: ${(props: { $isVisible: any; }) => (props.$isVisible ? '0px' : '-1px')}; +`; + +const BannerContent = styled.div` + flex: 1; + display: flex; + align-items: center; +`; + +const BannerDescription = styled.div` + font-size: 13px; + color: var(--vscode-descriptionForeground); +`; + +const HeaderLeft = styled.div` + flex: 1; + display: flex; + align-items: center; + gap: 12px; +`; + +const HeaderRight = styled.div` + display: flex; + align-items: center; + gap: 12px; +`; + +const IconButton = styled.div` + padding: 4px; + cursor: pointer; + border-radius: 4px; + display: flex; + align-items: center; + justify-content: center; + + &:hover { + background-color: var(--vscode-toolbar-hoverBackground); + } +`; + +const UnsavedIndicator = styled.div` + display: flex; + align-items: center; + gap: 8px; + font-size: 13px; + color: var(--vscode-descriptionForeground); + margin-right: 8px; +`; + +const Dot = styled.span` + width: 8px; + height: 8px; + border-radius: 50%; + background-color: var(--vscode-notificationsWarningIcon-foreground); +`; + +const Title = styled.h2` + font-size: 1.3em; + font-weight: 600; + margin: 0 0 6px 0; + color: var(--vscode-foreground); + letter-spacing: -0.01em; +`; + +const Subtitle = styled.p` + font-size: 14px; + font-weight: 500; + color: var(--vscode-descriptionForeground); + margin: 0; +`; + +export const Messages = styled.div` + display: flex; + flex-direction: column; + flex: 1; + overflow-y: auto; + gap: 0; + position: relative; + z-index: 1; + padding: 22px 20px 60px; + + @media (min-width: 800px) { + padding-left: 10%; + padding-right: 10%; + } + + @media (min-width: 1200px) { + padding-left: 15%; + padding-right: 15%; + } +`; + +const TimelineContainer = styled.div` + position: relative; + display: flex; + flex-direction: column; +`; + +// --- SEAMLESS TRANSITION COMPONENTS --- + +// TraceWrapper: Always has a border width (transparent in view mode) to prevent layout shifting +const TraceWrapper = styled.div<{ $isEditMode: boolean; $isDragging?: boolean }>` + display: flex; + flex-direction: row; + align-items: stretch; + + border: 1px solid ${(props: { $isEditMode: any; }) => props.$isEditMode ? 'var(--vscode-panel-border)' : 'transparent'}; + border-radius: 8px; + + position: relative; + background-color: ${(props: { $isEditMode: any; }) => props.$isEditMode ? 'var(--vscode-editor-background)' : 'transparent'}; + margin: 4px 0; + z-index: 2; + opacity: ${(props: { $isDragging: any; }) => props.$isDragging ? 0.5 : 1}; + + transition: border-color 0.3s ease, background-color 0.3s ease, transform 0.2s ease; + + &:hover { + border-color: ${(props: { $isEditMode: any; }) => props.$isEditMode ? 'var(--vscode-focusBorder)' : 'transparent'}; + } +`; + +// TraceHeader: Fixed width container. Icons fade in/out via opacity. +const TraceHeader = styled.div<{ $isEditMode: boolean }>` + display: flex; + flex-direction: column; + align-items: center; + gap: 8px; + + width: 32px; + padding: 0 12px; + flex-shrink: 0; + padding-top: 8px; + + border-right: 1px solid ${(props: { $isEditMode: any; }) => props.$isEditMode ? 'var(--vscode-panel-border)' : 'transparent'}; + transition: border-color 0.3s ease; +`; + +// Helper to fade icons +const TraceHeaderIcons = styled.div<{ $visible: boolean }>` + display: flex; + flex-direction: column; + align-items: center; + gap: 8px; + opacity: ${(props: { $visible: any; }) => props.$visible ? 1 : 0}; + transition: opacity 0.3s ease; + pointer-events: ${(props: { $visible: any; }) => props.$visible ? 'auto' : 'none'}; +`; + +const TraceContent = styled.div` + flex: 1; + display: flex; + flex-direction: column; + min-width: 0; + padding: 12px 16px; +`; + +const TraceDragHandle = styled.div` + cursor: grab; + color: var(--vscode-descriptionForeground); + display: flex; + align-items: center; + justify-content: center; + padding: 6px; + border-radius: 4px; + + &:hover { + background-color: var(--vscode-toolbar-hoverBackground); + } +`; + +const TraceDeleteButton = styled.button` + background: none; + border: none; + padding: 6px; + cursor: pointer; + color: var(--vscode-foreground); + border-radius: 4px; + display: flex; + align-items: center; + justify-content: center; + + &:hover { + background-color: var(--vscode-toolbar-hoverBackground); + color: var(--vscode-errorForeground); + } +`; + +// HoverAddTurnContainer: Animates height from 0 to 32px when entering edit mode +const HoverAddTurnContainer = styled.div<{ $visible: boolean }>` + position: relative; + display: flex; + justify-content: center; + align-items: center; + z-index: 5; + + /* Animation Logic */ + height: ${(props: { $visible: any; }) => props.$visible ? '32px' : '0px'}; + margin: ${(props: { $visible: any; }) => props.$visible ? '-16px 0' : '0px'}; + opacity: ${(props: { $visible: any; }) => props.$visible ? 0 : 0}; + pointer-events: ${(props: { $visible: any; }) => props.$visible ? 'auto' : 'none'}; + + transition: height 0.3s cubic-bezier(0.4, 0, 0.2, 1), margin 0.3s ease, opacity 0.2s ease; + overflow: hidden; + + &:hover { + opacity: ${(props: { $visible: any; }) => props.$visible ? 1 : 0}; + } +`; + +const AddMessageButton = styled.button` + display: flex; + align-items: center; + justify-content: center; + height: 26px; + padding: 0 12px; + border-radius: 8px; + background-color: var(--vscode-editor-background); + color: var(--vscode-foreground); + border: 1px solid var(--vscode-panel-border); + cursor: pointer; + font-size: 12px; + transition: all 0.2s ease; + + &:hover { + border-color: var(--vscode-focusBorder); + } + + .icon-wrapper { + margin-right: 4px; + display: flex; + align-items: center; + } +`; + +const StyledMessageContainer = styled(MessageContainer)` + &:last-child { + margin-bottom: 0; + } + + &:hover .add-tool-button { + opacity: 1; + transform: translateY(0); + max-height: 32px; + padding-top: 4px; + padding-bottom: 4px; + margin-bottom: 8px; + border-width: 1px; + transition-delay: 0.2s; + } + + &:hover .edit-button { + opacity: 1; + transform: translate(0, 0); + transition-delay: 0.2s; + } +`; + +const AgentContentWrapper = styled.div` + display: flex; + flex-direction: column; + gap: 0; + position: relative; +`; + +const AddToolButton = styled.button` + background-color: var(--vscode-editorWidget-background); + color: var(--vscode-descriptionForeground); + border: 1px solid var(--vscode-panel-border); + border-radius: 4px; + padding: 0 12px; + padding-top: 0; + padding-bottom: 0; + margin-bottom: 0; + border-width: 0; + cursor: pointer; + font-size: 12px; + font-weight: 500; + display: flex; + align-items: center; + gap: 6px; + align-self: flex-start; + opacity: 0; + transform: translateY(-4px); + max-height: 0; + overflow: hidden; + transition: all 0.2s ease; + pointer-events: none; + + &:hover { + background-color: var(--vscode-list-hoverBackground); + border-color: var(--vscode-focusBorder); + color: var(--vscode-foreground); + } + + .message-container:hover & { + pointer-events: auto; + } +`; + +interface SortableTraceWrapperProps { + trace: EvalsetTrace; + isEditMode: boolean; + children: React.ReactNode; + onDelete: () => void; +} + +const SortableTraceWrapper: React.FC = ({ + trace, + isEditMode, + children, + onDelete, +}) => { + const { + attributes, + listeners, + setNodeRef, + transform, + transition, + isDragging, + } = useSortable({ id: trace.id, disabled: !isEditMode }); + + const style = { + transform: CSS.Transform.toString(transform), + transition, + width: '100%', + }; + + return ( +
+ + + + + + + + + + + + + {children} + + +
+ ); +}; + +interface EvalThreadViewerProps { + projectPath: string; + filePath: string; + evalSet: EvalSet; + evalThread: EvalThread; +} + +export const EvalThreadViewer: React.FC = ({ projectPath, filePath, evalSet, evalThread }) => { + const { rpcClient } = useRpcContext(); + const [isEditMode, setIsEditMode] = useState(false); + const [originalEvalThread, setOriginalEvalThread] = useState(evalThread); + const [workingEvalThread, setWorkingEvalThread] = useState(evalThread); + const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false); + const [isSaving, setIsSaving] = useState(false); + const [selectedToolCall, setSelectedToolCall] = useState<{ + traceId: string; + toolCallIndex: number; + } | null>(null); + const [showDiscardConfirmation, setShowDiscardConfirmation] = useState(false); + const [deleteTraceIndex, setDeleteTraceIndex] = useState(null); + const [deleteToolCall, setDeleteToolCall] = useState<{ traceId: string; toolCallIndex: number } | null>(null); + const [availableToolsCache, setAvailableToolsCache] = useState(null); + + // Handle back navigation to thread list view + const handleBack = () => { + rpcClient.getCommonRpcClient().executeCommand({ + commands: ['ballerina.openEvalsetViewer', { fsPath: filePath }] + }); + }; + + const sensors = useSensors( + useSensor(PointerSensor), + useSensor(KeyboardSensor, { + coordinateGetter: sortableKeyboardCoordinates, + }) + ); + + const fetchAvailableTools = async (): Promise => { + if (availableToolsCache !== null) { + return availableToolsCache; + } + + try { + const response = await rpcClient.getBIDiagramRpcClient().search({ + filePath: projectPath, + queryMap: { q: "", limit: 50 }, + searchKind: "AGENT_TOOL" + }); + + const tools: EvalToolSchema[] = response.categories + .flatMap(category => category.items as AvailableNode[]) + .map(node => { + const metadataData = node.metadata?.data as any; + const inputParameters = metadataData?.inputParameters || []; + + // Transform inputParameters array to JSON Schema properties format + const properties: { [key: string]: any } = {}; + inputParameters.forEach((param: any) => { + if (param.name) { + properties[param.name] = { + type: param.type === 'int' ? 'number' : param.type, + description: param.description || '' + }; + } + }); + + return { + name: node.metadata?.label || node.codedata?.symbol || 'unknown', + description: node.metadata?.description || '', + parametersSchema: inputParameters.length > 0 ? { properties } : undefined + }; + }); + + setAvailableToolsCache(tools); + return tools; + } catch (error) { + console.error('Error fetching available tools:', error); + return []; + } + }; + + const handleEnterEditMode = () => { + setOriginalEvalThread(cloneEvalThread(evalThread)); + setWorkingEvalThread(cloneEvalThread(evalThread)); + setHasUnsavedChanges(false); + setIsEditMode(true); + }; + + const handleExitEditMode = () => { + setIsEditMode(false); + setHasUnsavedChanges(false); + }; + + const handleSaveUserMessage = (traceId: string, content: string) => { + setWorkingEvalThread(prev => { + const updatedTraces = prev.traces.map(trace => { + if (trace.id === traceId) { + const originalType = getContentType(trace.userMessage.content); + const deserializedContent = deserializeContent(content, originalType); + return updateTraceUserMessage(trace, deserializedContent); + } + return trace; + }); + return { ...prev, traces: updatedTraces }; + }); + setHasUnsavedChanges(true); + }; + + const handleSaveAgentOutput = (traceId: string, content: string) => { + setWorkingEvalThread(prev => { + const updatedTraces = prev.traces.map(trace => { + if (trace.id === traceId) { + const originalType = getContentType(trace.output?.content); + const deserializedContent = deserializeContent(content, originalType); + return updateTraceAgentOutput(trace, deserializedContent); + } + return trace; + }); + return { ...prev, traces: updatedTraces }; + }); + setHasUnsavedChanges(true); + }; + + const handleSave = async () => { + setIsSaving(true); + try { + const updatedEvalSet: EvalSet = { + ...evalSet, + threads: evalSet.threads.map(c => + c.id === workingEvalThread.id ? workingEvalThread : c + ) + }; + + const response = await rpcClient.getVisualizerRpcClient().saveEvalThread({ + filePath, + updatedEvalSet + }); + + if (response.success) { + setHasUnsavedChanges(false); + handleExitEditMode(); + } else { + // Show error when save was unsuccessful + rpcClient.getCommonRpcClient().showErrorMessage({ + message: response.error || 'Failed to save evaluation thread.' + }); + } + } catch (error: any) { + console.error('Error saving evalThread:', error); + // Show error for RPC failures + rpcClient.getCommonRpcClient().showErrorMessage({ + message: error?.message || 'An unexpected error occurred while saving.' + }); + } finally { + setIsSaving(false); + } + }; + + const handleDiscardClick = () => { + if (hasUnsavedChanges) { + setShowDiscardConfirmation(true); + } else { + handleExitEditMode(); + } + }; + + const handleDiscard = () => { + setWorkingEvalThread(cloneEvalThread(originalEvalThread)); + setHasUnsavedChanges(false); + setSelectedToolCall(null); + setIsEditMode(false); + setShowDiscardConfirmation(false); + }; + + const handleUpdateToolCalls = (traceId: string, toolCalls: EvalFunctionCall[]) => { + setWorkingEvalThread(prev => { + const updatedTraces = prev.traces.map(trace => { + if (trace.id === traceId) { + return updateToolCallsInTrace(trace, toolCalls); + } + return trace; + }); + return { ...prev, traces: updatedTraces }; + }); + setHasUnsavedChanges(true); + }; + + const handleEditToolCall = (traceId: string, toolCallIndex: number) => { + setSelectedToolCall({ traceId, toolCallIndex }); + }; + + const handleSaveToolCall = (updates: Partial) => { + if (!selectedToolCall) return; + + const { traceId, toolCallIndex } = selectedToolCall; + const trace = workingEvalThread.traces.find(t => t.id === traceId); + if (!trace) return; + + const currentToolCalls = getToolCallsFromTrace(trace); + let updatedToolCalls: EvalFunctionCall[]; + + if (toolCallIndex === -1) { + const newToolCall: EvalFunctionCall = { + id: generateToolCallId(), + name: updates.name || trace.tools[0]?.name || '', + arguments: updates.arguments, + }; + updatedToolCalls = [...currentToolCalls, newToolCall]; + } else { + updatedToolCalls = currentToolCalls.map((tc, idx) => + idx === toolCallIndex ? { ...tc, ...updates } : tc + ); + } + + handleUpdateToolCalls(traceId, updatedToolCalls); + setSelectedToolCall(null); + }; + + const handleAddTurnAtIndex = async (index: number) => { + const tools = await fetchAvailableTools(); + setWorkingEvalThread(prev => { + const newTraces = [...prev.traces]; + newTraces.splice(index, 0, createNewTrace(tools)); + return { ...prev, traces: newTraces }; + }); + setHasUnsavedChanges(true); + }; + + const handleDragEnd = (event: DragEndEvent) => { + const { active, over } = event; + if (over && active.id !== over.id) { + setWorkingEvalThread(prev => { + const oldIndex = prev.traces.findIndex(trace => trace.id === active.id); + const newIndex = prev.traces.findIndex(trace => trace.id === over.id); + return { ...prev, traces: arrayMove(prev.traces, oldIndex, newIndex) }; + }); + setHasUnsavedChanges(true); + } + }; + + const handleDeleteTraceConfirm = () => { + if (deleteTraceIndex !== null) { + setWorkingEvalThread(prev => ({ + ...prev, + traces: prev.traces.filter((_, i) => i !== deleteTraceIndex) + })); + setHasUnsavedChanges(true); + setDeleteTraceIndex(null); + } + }; + + const handleDeleteToolCallRequest = (traceId: string, toolCallIndex: number) => { + setDeleteToolCall({ traceId, toolCallIndex }); + }; + + const handleDeleteToolCallConfirm = () => { + if (deleteToolCall) { + const { traceId, toolCallIndex } = deleteToolCall; + const trace = workingEvalThread.traces.find(t => t.id === traceId); + if (trace) { + const currentToolCalls = getToolCallsFromTrace(trace); + const updatedToolCalls = currentToolCalls.filter((_, i) => i !== toolCallIndex); + handleUpdateToolCalls(traceId, updatedToolCalls); + } + setDeleteToolCall(null); + } + }; + + const displayCase = isEditMode ? workingEvalThread : evalThread; + + return ( + + + +
+ + + + +
+ {evalSet.name} + {displayCase.name} +
+
+ + {isEditMode ? ( + <> + {hasUnsavedChanges && ( + Unsaved changes + )} + + + + ) : ( + + )} + +
+ + {/* Animated Banner - always rendered, visibility controlled by props */} + + + + Edit Mode - Hover over messages to edit, drag traces to reorder, hover between traces to add turns, or hover over agent messages to add tool executions. + + + + + + + {/* Top Add Turn Button */} + + handleAddTurnAtIndex(0)}> +
+ Add Message Turn +
+
+ + + t.id)} strategy={verticalListSortingStrategy}> + {displayCase.traces.map((trace, traceIdx) => { + const toolCalls = getToolCallsFromTrace(trace); + return ( + + setDeleteTraceIndex(traceIdx)} + > + + + + + + + + + + + + + + {isEditMode && ( + { + const tools = await fetchAvailableTools(); + // Update trace with fetched tools if it has an empty tools array + if (trace.tools.length === 0 && tools.length > 0) { + setWorkingEvalThread(prev => ({ + ...prev, + traces: prev.traces.map(t => + t.id === trace.id ? { ...t, tools } : t + ) + })); + } + handleEditToolCall(trace.id, -1); + }}> + + Add Tool Execution + + )} + + + + + + {/* Inter-trace Add Turn Button */} + + handleAddTurnAtIndex(traceIdx + 1)}> +
+ Add Message Turn +
+
+
+ ); + })} +
+
+
+
+
+ + {selectedToolCall && (() => { + const trace = workingEvalThread.traces.find(t => t.id === selectedToolCall.traceId); + if (!trace) return null; + const toolCall = selectedToolCall.toolCallIndex === -1 + ? { name: trace.tools[0]?.name || '', arguments: {} } + : getToolCallsFromTrace(trace)[selectedToolCall.toolCallIndex]; + + return ( + setSelectedToolCall(null)} + onSave={handleSaveToolCall} + /> + ); + })()} + + {showDiscardConfirmation && ( + setShowDiscardConfirmation(false)} + /> + )} + + {deleteTraceIndex !== null && ( + setDeleteTraceIndex(null)} + /> + )} + + {deleteToolCall !== null && ( + setDeleteToolCall(null)} + /> + )} +
+ ); +}; diff --git a/workspaces/ballerina/ballerina-visualizer/src/views/EvalsetViewer/EvalsetViewer.tsx b/workspaces/ballerina/ballerina-visualizer/src/views/EvalsetViewer/EvalsetViewer.tsx new file mode 100644 index 00000000000..708d1b372a8 --- /dev/null +++ b/workspaces/ballerina/ballerina-visualizer/src/views/EvalsetViewer/EvalsetViewer.tsx @@ -0,0 +1,306 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React, { useState } from "react"; +import styled from "@emotion/styled"; +import { EvalSet, EVENT_TYPE, MACHINE_VIEW } from "@wso2/ballerina-core"; +import { EvalThreadViewer } from "./EvalThreadViewer"; +import { TopNavigationBar } from "../../components/TopNavigationBar"; +import { Button, Icon } from "@wso2/ui-toolkit"; +import { useRpcContext } from "@wso2/ballerina-rpc-client"; + +// --- LAYOUT COMPONENTS --- + +const PageWrapper = styled.div` + height: 100%; + width: 100%; + display: flex; + flex-direction: column; +`; + +const Container = styled.div` + flex: 1; + width: 100%; + background-color: var(--vscode-editor-background); + color: var(--vscode-editor-foreground); + display: flex; + flex-direction: column; + overflow: hidden; + + *, *::before, *::after { + box-sizing: border-box; + } +`; + +const Header = styled.div` + top: 0; + padding: 16px 24px; + position: sticky; + background-color: var(--vscode-editorWidget-background); + border-top: 1px solid var(--vscode-panel-border); + border-bottom: 1px solid var(--vscode-panel-border); + z-index: 10; + display: flex; + align-items: flex-start; + justify-content: space-between; +`; + +const HeaderLeft = styled.div` + display: flex; + flex-direction: column; + gap: 4px; +`; + +const HeaderRight = styled.div` + display: flex; + align-items: center; + gap: 8px; +`; + +const Title = styled.h1` + font-size: 18px; + font-weight: 600; + margin: 0; + color: var(--vscode-foreground); +`; + +const Subtitle = styled.p` + font-size: 12px; + color: var(--vscode-descriptionForeground); + margin: 0; +`; + +const ThreadListContainer = styled.div` + flex: 1; + overflow-y: auto; + padding: 24px; + display: grid; + grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); + gap: 16px; + align-content: start; +`; + +const ThreadCard = styled.div` + padding: 16px; + background-color: var(--vscode-editorWidget-background); + border: 1px solid var(--vscode-panel-border); + border-radius: 6px; + cursor: pointer; + transition: all 0.15s ease; + position: relative; + + &:hover { + border-color: var(--vscode-focusBorder); + background-color: var(--vscode-list-hoverBackground); + } +`; + +const ThreadName = styled.div` + font-size: 14px; + font-weight: 600; + color: var(--vscode-foreground); + margin-bottom: 8px; +`; + +const ThreadMeta = styled.div` + font-size: 12px; + color: var(--vscode-descriptionForeground); + display: flex; + flex-direction: column; + gap: 4px; +`; + +const DeleteIconButton = styled.div` + position: absolute; + top: 8px; + right: 8px; + padding: 4px; + cursor: pointer; + border-radius: 4px; + transition: all 0.15s ease; + display: flex; + align-items: center; + justify-content: center; + + &:hover { + background-color: var(--vscode-toolbar-hoverBackground); + } +`; + +const EmptyState = styled.div` + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 48px 24px; + text-align: center; + color: var(--vscode-descriptionForeground); + gap: 8px; +`; + +const ErrorMessage = styled.div` + padding: 15px; + background-color: var(--vscode-inputValidation-errorBackground); + border: 1px solid var(--vscode-inputValidation-errorBorder); + border-radius: 4px; + color: var(--vscode-errorForeground); + margin: 24px; +`; + +interface EvalsetViewerProps { + projectPath: string; + filePath: string; + content: EvalSet; + threadId?: string; +} + +export const EvalsetViewer: React.FC = ({ projectPath, filePath, content, threadId }) => { + const { rpcClient } = useRpcContext(); + const [isAddingThread, setIsAddingThread] = useState(false); + + // If a specific thread is selected, delegate to EvalThreadViewer + if (threadId) { + const evalThread = content.threads.find(c => c.id === threadId); + + if (!evalThread) { + return ( + + + + + Thread with ID "{threadId}" not found in this evalset. + + + + ); + } + + return ; + } + + // Handle thread creation by calling the existing VS Code command + const handleAddThread = async () => { + if (isAddingThread) { return; } + + setIsAddingThread(true); + try { + // Call the existing VS Code command that handles thread creation + // Pass autoRefresh=true to immediately refresh the view (vs waiting for notification) + await rpcClient.getCommonRpcClient().executeCommand({ + commands: [ + 'ballerina.createNewThread', + { uri: { fsPath: filePath } }, + true // autoRefresh parameter + ] + }); + } catch (error) { + console.error('Error adding thread:', error); + } finally { + setIsAddingThread(false); + } + }; + + // Handle clicking on a thread card + const handleThreadClick = (clickedThreadId: string) => { + rpcClient.getVisualizerRpcClient().openView({ + type: EVENT_TYPE.OPEN_VIEW, + location: { + view: MACHINE_VIEW.EvalsetViewer, + evalsetData: { + filePath, + content, + threadId: clickedThreadId + } + } + }); + }; + + // Handle deleting a thread + const handleDeleteThread = async (e: React.MouseEvent, threadId: string) => { + e.stopPropagation(); + + try { + await rpcClient.getCommonRpcClient().executeCommand({ + commands: [ + 'ballerina.deleteThread', + { + parentUri: { fsPath: filePath }, + threadId: threadId + }, + true + ] + }); + } catch (error) { + console.error('Error deleting thread:', error); + } + }; + + // Render thread list view + return ( + + + +
+ + {content.name} + + {content.threads.length} thread{content.threads.length !== 1 ? 's' : ''} + + + + + +
+ {content.threads.length === 0 ? ( + +
No threads yet
+
Click "Add Thread" to create your first thread
+
+ ) : ( + + {content.threads.map((thread) => ( + handleThreadClick(thread.id)}> + handleDeleteThread(e, thread.id)} + title="Delete thread" + > + + + {thread.name} + +
{thread.traces.length} turn{thread.traces.length !== 1 ? 's' : ''}
+ {thread.created_on && ( +
Created: {new Date(thread.created_on).toLocaleDateString()}
+ )} +
+
+ ))} +
+ )} +
+
+ ); +}; diff --git a/workspaces/ballerina/ballerina-visualizer/src/views/EvalsetViewer/ToolCallsList.tsx b/workspaces/ballerina/ballerina-visualizer/src/views/EvalsetViewer/ToolCallsList.tsx new file mode 100644 index 00000000000..71d8a6407de --- /dev/null +++ b/workspaces/ballerina/ballerina-visualizer/src/views/EvalsetViewer/ToolCallsList.tsx @@ -0,0 +1,384 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React, { useState } from 'react'; +import styled from '@emotion/styled'; +import { + DndContext, + closestCenter, + KeyboardSensor, + PointerSensor, + useSensor, + useSensors, + DragEndEvent, +} from '@dnd-kit/core'; +import { + arrayMove, + SortableContext, + sortableKeyboardCoordinates, + useSortable, + verticalListSortingStrategy, +} from '@dnd-kit/sortable'; +import { CSS } from '@dnd-kit/utilities'; +import { EvalFunctionCall, EvalToolSchema } from '@wso2/ballerina-core'; +import { Codicon, Icon } from '@wso2/ui-toolkit'; + +// --- STYLES --- + +const TimelineContainer = styled.div` + max-width: 600px; + margin: 4px 0 2px; + position: relative; + padding-left: 0; +`; + +const TimelineTrack = styled.div<{ $isVisible: boolean }>` + position: absolute; + left: 15px; + top: 24px; + bottom: -2px; + width: 2px; + background-color: var(--vscode-button-background); + opacity: ${(props: { $isVisible: any; }) => props.$isVisible ? 0.3 : 0}; + z-index: 0; + transition: opacity 0.4s cubic-bezier(0.4, 0, 0.2, 1); +`; + +const TimelineHeader = styled.button` + display: flex; + align-items: center; + gap: 4px; + background: transparent; + border: none; + padding: 0 0 8px 4px; + cursor: pointer; + margin-bottom: 0; +`; + +const HeaderTitle = styled.div` + font-size: 11px; + font-weight: 600; + color: var(--vscode-descriptionForeground); +`; + +const ToggleIcon = styled.span<{ $isOpen: boolean }>` + color: var(--vscode-descriptionForeground); + display: inline-flex; + align-items: center; + justify-content: center; + transition: transform 0.4s cubic-bezier(0.4, 0, 0.2, 1); + transform: ${(props: { $isOpen: any; }) => props.$isOpen ? "rotate(90deg)" : "rotate(0deg)"}; +`; + +const TimelineList = styled.div<{ $isCollapsed: boolean }>` + display: flex; + flex-direction: column; + max-height: ${(props: { $isCollapsed: any; }) => props.$isCollapsed ? '0px' : '2000px'}; + opacity: ${(props: { $isCollapsed: any; }) => props.$isCollapsed ? 0 : 1}; + overflow: hidden; + transition: max-height 0.6s cubic-bezier(0.4, 0, 0.2, 1), + opacity 0.2s cubic-bezier(0.4, 0, 0.2, 1); +`; + +const ToolCard = styled.div<{ $isDragging?: boolean; $isEditMode: boolean }>` + background-color: var(--vscode-textBlockQuote-background); + border: 1px solid var(--vscode-panel-border); + border-radius: 6px; + padding: 8px 6px; + display: flex; + align-items: center; + gap: 12px; + position: relative; + z-index: 1; + margin-bottom: 8px; + + opacity: ${(props: { $isDragging: any; }) => props.$isDragging ? 0.5 : 1}; + transition: border-color 0.2s, background-color 0.2s; + + &:hover { + background-color: var(--vscode-list-hoverBackground); + border-color: ${(props: { $isEditMode: any; }) => props.$isEditMode ? 'var(--vscode-focusBorder)' : 'var(--vscode-panel-border)'}; + } +`; + +const IconBadgeWrapper = styled.div` + display: flex; + align-items: center; + justify-content: center; + width: 28px; + height: 28px; + background-color: var(--vscode-editor-background); + border: 1px solid var(--vscode-panel-border); + border-radius: 50%; + color: var(--vscode-terminal-ansiBrightMagenta); + flex-shrink: 0; + z-index: 2; +`; + +const DragHandle = styled.div` + cursor: grab; + color: var(--vscode-descriptionForeground); + display: flex; + align-items: center; + opacity: 0.5; + + &:hover { + opacity: 1; + } + + &:active { + cursor: grabbing; + } +`; + +const ToolInfo = styled.div<{ $isClickable: boolean }>` + flex: 1; + min-width: 0; + display: flex; + flex-direction: column; + gap: 2px; + padding-top: 2px; + cursor: ${(props: { $isClickable: any; }) => props.$isClickable ? 'pointer' : 'default'}; +`; + +const ToolName = styled.div` + font-size: 13px; + font-weight: 600; + color: var(--vscode-foreground); +`; + +const ArgumentsPreview = styled.code` + font-size: 12px; + color: var(--vscode-descriptionForeground); + font-family: var(--vscode-editor-font-family); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + opacity: 0.8; + display: block; +`; + +const Actions = styled.div` + display: flex; + align-items: center; + gap: 2px; + opacity: 0; + transition: opacity 0.2s; + + .tool-card-row:hover & { + opacity: 1; + } +`; + +const ActionButton = styled.button<{ $danger?: boolean }>` + background: transparent; + border: none; + padding: 6px; + cursor: pointer; + border-radius: 4px; + color: ${(props: { $danger: any; }) => props.$danger ? 'var(--vscode-errorForeground)' : 'var(--vscode-icon-foreground)'}; + display: flex; + align-items: center; + justify-content: center; + + &:hover { + background-color: var(--vscode-toolbar-hoverBackground); + color: ${(props: { $danger: any; }) => props.$danger ? 'var(--vscode-testing-iconFailed)' : 'var(--vscode-foreground)'}; + } +`; + +// --- HELPER --- + +const formatArgs = (args: any) => { + if (!args) return "()"; + if (typeof args === 'string') return args; + try { + return JSON.stringify(args).replace(/"/g, '').replace(/:/g, ': ').replace(/,/g, ', '); + } catch (e) { + return "Invalid arguments"; + } +}; + +// --- COMPONENTS --- + +interface SortableToolCallItemProps { + toolCall: EvalFunctionCall; + index: number; + isEditMode: boolean; + onEdit?: () => void; + onDelete?: () => void; +} + +const SortableToolCallItem: React.FC = ({ + toolCall, + index, + isEditMode, + onEdit, + onDelete, +}) => { + const sortableId = `${toolCall.id ?? toolCall.name}-${index}`; + const { + attributes, + listeners, + setNodeRef, + transform, + transition, + isDragging, + } = useSortable({ id: sortableId, disabled: !isEditMode }); + + const style = { + transform: CSS.Transform.toString(transform), + transition, + }; + + return ( +
+ + {isEditMode && ( + + + + )} + + + + + + + {toolCall.name} + + {formatArgs(toolCall.arguments)} + + + + {isEditMode && onDelete && ( + + { e.stopPropagation(); onDelete(); }} title="Delete"> + + + + )} + +
+ ); +}; + +interface ToolCallsListProps { + traceId?: string; + toolCalls: EvalFunctionCall[]; + availableTools?: EvalToolSchema[]; + isEditMode: boolean; + onUpdate?: (traceId: string, toolCalls: EvalFunctionCall[]) => void; + onEditToolCall?: (traceId: string, toolCallIndex: number) => void; + onDeleteRequest?: (traceId: string, toolCallIndex: number) => void; +} + +export const ToolCallsList: React.FC = ({ + traceId = '', + toolCalls, + isEditMode, + onUpdate, + onEditToolCall, + onDeleteRequest, +}) => { + const [isOpen, setIsOpen] = useState(false); + + const sensors = useSensors( + useSensor(PointerSensor), + useSensor(KeyboardSensor, { + coordinateGetter: sortableKeyboardCoordinates, + }) + ); + + const handleDragEnd = (event: DragEndEvent) => { + if (!isEditMode || !onUpdate) return; + + const { active, over } = event; + + if (over && active.id !== over.id) { + const oldIndex = toolCalls.findIndex( + (tc, idx) => `${tc.id ?? tc.name}-${idx}` === active.id + ); + const newIndex = toolCalls.findIndex( + (tc, idx) => `${tc.id ?? tc.name}-${idx}` === over.id + ); + + const reorderedToolCalls = arrayMove(toolCalls, oldIndex, newIndex); + onUpdate(traceId, reorderedToolCalls); + } + }; + + if (toolCalls.length === 0) { + return null; + } + + const headerTitle = isEditMode ? "Tool Execution Chain" : `Tool Executions (${toolCalls.length})`; + const showHeader = !isEditMode || toolCalls.length > 0; + const isCollapsed = !isEditMode && !isOpen; + + return ( + + {showHeader && ( + <> + {!isEditMode ? ( + setIsOpen(!isOpen)} aria-expanded={isOpen}> + {headerTitle} + + + + + ) : ( + {headerTitle} + )} + + )} + + + + + + `${tc.id ?? tc.name}-${idx}`)} + strategy={verticalListSortingStrategy} + > + {toolCalls.map((toolCall, index) => { + const sortableId = `${toolCall.id ?? toolCall.name}-${index}`; + return ( + onEditToolCall(traceId, index) : undefined} + onDelete={isEditMode && onDeleteRequest ? () => onDeleteRequest(traceId, index) : undefined} + /> + ); + })} + + + + + ); +}; diff --git a/workspaces/ballerina/ballerina-visualizer/src/views/EvalsetViewer/ToolEditorModal.tsx b/workspaces/ballerina/ballerina-visualizer/src/views/EvalsetViewer/ToolEditorModal.tsx new file mode 100644 index 00000000000..c10e66b1fee --- /dev/null +++ b/workspaces/ballerina/ballerina-visualizer/src/views/EvalsetViewer/ToolEditorModal.tsx @@ -0,0 +1,356 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React, { useState, useEffect, useRef } from 'react'; +import styled from '@emotion/styled'; +import { motion } from 'framer-motion'; +import { EvalFunctionCall, EvalToolSchema } from '@wso2/ballerina-core'; +import { Button, Icon } from '@wso2/ui-toolkit'; + +const Overlay = styled.div` + position: fixed; + inset: 0; + background-color: rgba(0, 0, 0, 0.4); + z-index: 1000; + display: flex; + align-items: center; + justify-content: center; + padding: 16px; +`; + +const ModalContainer = styled(motion.div)` + background-color: var(--vscode-editorWidget-background); + border-radius: 6px; + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3); + width: 100%; + max-width: 600px; + overflow: hidden; + border: 1px solid var(--vscode-widget-border); +`; + +const ModalHeader = styled.div` + padding: 16px 20px; + border-bottom: 1px solid var(--vscode-widget-border); + display: flex; + align-items: center; + justify-content: space-between; + background-color: var(--vscode-editorWidget-background); +`; + +const HeaderTitle = styled.div` + display: flex; + align-items: center; + gap: 8px; +`; + +const Title = styled.h2` + font-size: 14px; + font-weight: 600; + margin: 0; + color: var(--vscode-foreground); +`; + +const CloseButton = styled.button` + background: none; + border: none; + padding: 4px; + cursor: pointer; + color: var(--vscode-foreground); + opacity: 0.7; + border-radius: 3px; + + &:hover { + background-color: var(--vscode-toolbar-hoverBackground); + opacity: 1; + } +`; + +const ModalBody = styled.div` + padding: 20px; + max-height: 60vh; + overflow-y: auto; +`; + +const FormSection = styled.div` + margin-bottom: 20px; + + &:last-child { + margin-bottom: 0; + } +`; + +const Label = styled.label` + display: block; + font-size: 13px; + font-weight: 600; + color: var(--vscode-descriptionForeground); + margin-bottom: 8px; +`; + +const Select = styled.select` + width: 100%; + background-color: var(--vscode-input-background); + color: var(--vscode-input-foreground); + border: 1px solid var(--vscode-input-border); + border-radius: 3px; + padding: 8px 12px; + font-size: 13px; + outline: none; + + &:focus { + border-color: var(--vscode-focusBorder); + } +`; + +const ArgumentsContainer = styled.div` + display: flex; + flex-direction: column; + gap: 12px; +`; + +const ArgumentField = styled.div` + display: flex; + align-items: center; + gap: 8px; +`; + +const FieldLabel = styled.label` + font-size: 13px; + color: var(--vscode-foreground); + min-width: 100px; +`; + +const Input = styled.input` + flex: 1; + background-color: var(--vscode-input-background); + color: var(--vscode-input-foreground); + border: 1px solid var(--vscode-input-border); + border-radius: 3px; + padding: 8px 12px; + font-size: 13px; + outline: none; + + &:focus { + border-color: var(--vscode-focusBorder); + } +`; + +const Textarea = styled.textarea` + flex: 1; + background-color: var(--vscode-input-background); + color: var(--vscode-input-foreground); + border: 1px solid var(--vscode-input-border); + border-radius: 3px; + padding: 8px 12px; + font-size: 13px; + min-height: 80px; + resize: vertical; + outline: none; + + &:focus { + border-color: var(--vscode-focusBorder); + } +`; + +const ModalFooter = styled.div` + padding: 16px 20px; + background-color: var(--vscode-editorWidget-background); + border-top: 1px solid var(--vscode-widget-border); + display: flex; + align-items: center; + justify-content: flex-end; + gap: 6px; +`; + +interface ToolEditorModalProps { + toolCall: EvalFunctionCall; + availableTools: EvalToolSchema[]; + onClose: () => void; + onSave: (updates: Partial) => void; +} + +export const ToolEditorModal: React.FC = ({ + toolCall, + availableTools, + onClose, + onSave, +}) => { + const [name, setName] = useState(toolCall.name); + const [argumentsValue, setArgumentsValue] = useState>( + toolCall.arguments || {} + ); + const isInitialMount = useRef(true); + + const selectedTool = availableTools.find(t => t.name === name); + const parametersSchema = selectedTool?.parametersSchema; + + // Reset arguments when the selected tool changes (but not on initial mount) + useEffect(() => { + // Skip reset on initial mount to preserve existing argument values + if (isInitialMount.current) { + isInitialMount.current = false; + return; + } + + // When tool changes, initialize with defaults from schema + const newArguments: Record = {}; + + if (parametersSchema?.properties) { + Object.entries(parametersSchema.properties).forEach(([fieldName, fieldSchema]: [string, any]) => { + if (fieldSchema.default !== undefined) { + newArguments[fieldName] = fieldSchema.default; + } + }); + } + + setArgumentsValue(newArguments); + }, [name, selectedTool, parametersSchema]); + + const handleArgumentChange = (fieldName: string, value: any) => { + setArgumentsValue(prev => ({ ...prev, [fieldName]: value })); + }; + + const renderField = ( + fieldName: string, + fieldSchema: any, + value: any, + onChange: (val: any) => void + ) => { + const fieldType = fieldSchema?.type || 'string'; + + // Handle complex objects as JSON textarea + if (fieldType === 'object' || fieldType === 'array') { + return ( + + {fieldName}: +