diff --git a/eslint.config.js b/eslint.config.js index 169bbd17..a1194df7 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -34,6 +34,7 @@ export default tseslint.config( 'packages/server/dist/**', 'packages/vscode-ide-companion/dist/**', 'bundle/**', + 'package/bundle/**', ], }, eslint.configs.recommended, @@ -203,6 +204,21 @@ export default tseslint.config( '@typescript-eslint/no-require-imports': 'off', }, }, + // extra settings for scripts that we run directly with node + { + files: ['packages/vscode-ide-companion/scripts/**/*.js'], + languageOptions: { + globals: { + ...globals.node, + process: 'readonly', + console: 'readonly', + }, + }, + rules: { + 'no-restricted-syntax': 'off', + '@typescript-eslint/no-require-imports': 'off', + }, + }, // Prettier config must be last prettierConfig, // extra settings for scripts that we run directly with node diff --git a/packages/vscode-ide-companion/.vscodeignore b/packages/vscode-ide-companion/.vscodeignore index be532ef9..e74d0536 100644 --- a/packages/vscode-ide-companion/.vscodeignore +++ b/packages/vscode-ide-companion/.vscodeignore @@ -3,4 +3,5 @@ ../ ../../ !LICENSE +!NOTICES.txt !assets/ diff --git a/packages/vscode-ide-companion/NOTICES.txt b/packages/vscode-ide-companion/NOTICES.txt new file mode 100644 index 00000000..56f3d4f3 --- /dev/null +++ b/packages/vscode-ide-companion/NOTICES.txt @@ -0,0 +1,114 @@ +This file contains third-party software notices and license terms. + +============================================================ +@modelcontextprotocol/sdk@^1.15.1 +(git+https://github.com/modelcontextprotocol/typescript-sdk.git) + +MIT License + +Copyright (c) 2024 Anthropic, PBC + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +============================================================ +cors@^2.8.5 +(No repository found) + +(The MIT License) + +Copyright (c) 2013 Troy Goode + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +============================================================ +express@^5.1.0 +(No repository found) + +(The MIT License) + +Copyright (c) 2009-2014 TJ Holowaychuk +Copyright (c) 2013-2014 Roman Shtylman +Copyright (c) 2014-2015 Douglas Christopher Wilson + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +============================================================ +zod@^3.25.76 +(git+https://github.com/colinhacks/zod.git) + +MIT License + +Copyright (c) 2025 Colin McDonnell + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + diff --git a/packages/vscode-ide-companion/esbuild.js b/packages/vscode-ide-companion/esbuild.js index 522542db..060be7c6 100644 --- a/packages/vscode-ide-companion/esbuild.js +++ b/packages/vscode-ide-companion/esbuild.js @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -const esbuild = require('esbuild'); +import esbuild from 'esbuild'; const production = process.argv.includes('--production'); const watch = process.argv.includes('--watch'); @@ -40,7 +40,7 @@ async function main() { sourcemap: !production, sourcesContent: false, platform: 'node', - outfile: 'dist/extension.js', + outfile: 'dist/extension.cjs', external: ['vscode'], logLevel: 'silent', plugins: [ diff --git a/packages/vscode-ide-companion/package.json b/packages/vscode-ide-companion/package.json index c4ff2b68..254d8ac2 100644 --- a/packages/vscode-ide-companion/package.json +++ b/packages/vscode-ide-companion/package.json @@ -35,18 +35,24 @@ { "command": "gemini-cli.runGeminiCLI", "title": "Gemini CLI: Run" + }, + { + "command": "gemini-cli.showNotices", + "title": "Gemini CLI: View Third-Party Notices" } ] }, - "main": "./dist/extension.js", + "main": "./dist/extension.cjs", + "type": "module", "scripts": { - "vscode:prepublish": "npm run check-types && npm run lint && node esbuild.js --production", + "vscode:prepublish": "npm run generate:notices && npm run check-types && npm run lint && node esbuild.js --production", "build": "npm run compile", "compile": "npm run check-types && npm run lint && node esbuild.js", "watch": "npm-run-all -p watch:*", "watch:esbuild": "node esbuild.js --watch", "watch:tsc": "tsc --noEmit --watch --project tsconfig.json", "package": "vsce package --no-dependencies", + "generate:notices": "node ./scripts/generate-notices.js", "check-types": "tsc --noEmit", "lint": "eslint src", "test": "vitest run", diff --git a/packages/vscode-ide-companion/scripts/generate-notices.js b/packages/vscode-ide-companion/scripts/generate-notices.js new file mode 100644 index 00000000..55dc3108 --- /dev/null +++ b/packages/vscode-ide-companion/scripts/generate-notices.js @@ -0,0 +1,105 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import fs from 'fs/promises'; +import path from 'path'; +import { fileURLToPath } from 'url'; + +const projectRoot = path.resolve( + path.join(path.dirname(fileURLToPath(import.meta.url)), '..', '..', '..'), +); +const packagePath = path.join(projectRoot, 'packages', 'vscode-ide-companion'); +const noticeFilePath = path.join(packagePath, 'NOTICES.txt'); + +async function getDependencyLicense(depName, depVersion) { + let depPackageJsonPath; + let licenseContent = 'License text not found.'; + let repositoryUrl = 'No repository found'; + + try { + depPackageJsonPath = path.join( + projectRoot, + 'node_modules', + depName, + 'package.json', + ); + if (!(await fs.stat(depPackageJsonPath).catch(() => false))) { + depPackageJsonPath = path.join( + packagePath, + 'node_modules', + depName, + 'package.json', + ); + } + + const depPackageJsonContent = await fs.readFile( + depPackageJsonPath, + 'utf-8', + ); + const depPackageJson = JSON.parse(depPackageJsonContent); + + repositoryUrl = depPackageJson.repository?.url || repositoryUrl; + + const licenseFile = depPackageJson.licenseFile + ? path.join(path.dirname(depPackageJsonPath), depPackageJson.licenseFile) + : path.join(path.dirname(depPackageJsonPath), 'LICENSE'); + + try { + licenseContent = await fs.readFile(licenseFile, 'utf-8'); + } catch (e) { + console.warn( + `Warning: Failed to read license file for ${depName}: ${e.message}`, + ); + } + } catch (e) { + console.warn( + `Warning: Could not find package.json for ${depName}: ${e.message}`, + ); + } + + return { + name: depName, + version: depVersion, + repository: repositoryUrl, + license: licenseContent, + }; +} + +async function main() { + try { + const packageJsonPath = path.join(packagePath, 'package.json'); + const packageJsonContent = await fs.readFile(packageJsonPath, 'utf-8'); + const packageJson = JSON.parse(packageJsonContent); + + const dependencies = packageJson.dependencies || {}; + const dependencyEntries = Object.entries(dependencies); + + const licensePromises = dependencyEntries.map(([depName, depVersion]) => + getDependencyLicense(depName, depVersion), + ); + + const dependencyLicenses = await Promise.all(licensePromises); + + let noticeText = + 'This file contains third-party software notices and license terms.\n\n'; + + for (const dep of dependencyLicenses) { + noticeText += + '============================================================\n'; + noticeText += `${dep.name}@${dep.version}\n`; + noticeText += `(${dep.repository})\n\n`; + noticeText += `${dep.license}\n\n`; + } + + await fs.writeFile(noticeFilePath, noticeText); + console.log(`NOTICES.txt generated at ${noticeFilePath}`); + } catch (error) { + console.error('Error generating NOTICES.txt:', error); + process.exit(1); + } +} + +main().catch(console.error); diff --git a/packages/vscode-ide-companion/src/extension.ts b/packages/vscode-ide-companion/src/extension.ts index 637b69e3..73090175 100644 --- a/packages/vscode-ide-companion/src/extension.ts +++ b/packages/vscode-ide-companion/src/extension.ts @@ -5,8 +5,8 @@ */ import * as vscode from 'vscode'; -import { IDEServer } from './ide-server'; -import { createLogger } from './utils/logger'; +import { IDEServer } from './ide-server.js'; +import { createLogger } from './utils/logger.js'; const IDE_WORKSPACE_PATH_ENV_VAR = 'GEMINI_CLI_IDE_WORKSPACE_PATH'; @@ -55,6 +55,13 @@ export async function activate(context: vscode.ExtensionContext) { terminal.show(); terminal.sendText(geminiCmd); }), + vscode.commands.registerCommand('gemini-cli.showNotices', async () => { + const noticePath = vscode.Uri.joinPath( + context.extensionUri, + 'NOTICES.txt', + ); + await vscode.window.showTextDocument(noticePath); + }), ); }