mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-06-13 21:07:00 -07:00
feat(dev-experience): Automate npmrc configuration for dev vs prod
This PR introduces a new, automated workflow for developers to switch between the development (GitHub Packages) and production (npmjs.org) npm registries. - A new script, , now automatically backs up and modifies the user's global file. - has been updated with and scripts to run this new script. - has been updated to reflect this new, simplified, and automated process, removing all manual steps for the user.
This commit is contained in:
@@ -279,6 +279,47 @@ npm run lint
|
||||
- **Imports:** Pay special attention to import paths. The project uses ESLint to
|
||||
enforce restrictions on relative imports between packages.
|
||||
|
||||
### Working with Pre-Release Versions (Development)
|
||||
|
||||
This project uses **GitHub Packages** to host development and pre-release
|
||||
versions of the CLI. To install these versions, you must configure your
|
||||
user-level `~/.npmrc` file to authenticate with the GitHub registry.
|
||||
|
||||
We have created a script to automate this process for you.
|
||||
|
||||
#### Setting Up Your Environment for Development (Recommended)
|
||||
|
||||
To automatically configure your environment to use the GitHub Packages registry,
|
||||
run the following command:
|
||||
|
||||
```bash
|
||||
npm run use-dev
|
||||
```
|
||||
|
||||
This command will:
|
||||
|
||||
1. Check that you have the [GitHub CLI (`gh`)](https://cli.github.com/)
|
||||
installed and that you are logged in.
|
||||
2. **Back up** your existing `~/.npmrc` to `~/.npmrc.bak` if a backup doesn't
|
||||
already exist.
|
||||
3. **Automatically add** the necessary configuration to your `~/.npmrc` file.
|
||||
|
||||
This setup is required for installing pre-release packages with the
|
||||
`@google-gemini` scope, both locally within a project and globally (e.g.,
|
||||
`npm install -g @google-gemini/gemini-cli@<version>`).
|
||||
|
||||
#### Switching Back to the Production Registry
|
||||
|
||||
To automatically remove the development configuration and revert to the public
|
||||
npm registry (`npmjs.org`), you can run:
|
||||
|
||||
```bash
|
||||
npm run use-prod
|
||||
```
|
||||
|
||||
This command will safely remove the lines added by the `use-dev` script from
|
||||
your `~/.npmrc` file.
|
||||
|
||||
### Project Structure
|
||||
|
||||
- `packages/`: Contains the individual sub-packages of the project.
|
||||
|
||||
Generated
+179
@@ -11,6 +11,7 @@
|
||||
"packages/*"
|
||||
],
|
||||
"dependencies": {
|
||||
"@google-gemini/gemini-cli": "^0.11.0-nightly.20251021.0e7b3951",
|
||||
"@testing-library/dom": "^10.4.1",
|
||||
"simple-git": "^3.28.0"
|
||||
},
|
||||
@@ -1457,6 +1458,159 @@
|
||||
"uuid": "dist/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/@google-gemini/gemini-cli": {
|
||||
"version": "0.11.0-nightly.20251021.0e7b3951",
|
||||
"resolved": "https://npm.pkg.github.com/download/@google-gemini/gemini-cli/0.11.0-nightly.20251021.0e7b3951/4dd4a330cc3538ee3a6333f57c55a795634229fe",
|
||||
"integrity": "sha512-qkQ7xfH7ih9kq17IV9lQcuvp6eJxiiBZUgpEm1I2fvRHjFRzzaszcEh6D8lVqoS10sGnuj2OnI4pBZW5a8UzEQ==",
|
||||
"dependencies": {
|
||||
"@google-gemini/gemini-cli-core": "0.11.0-nightly.20251021.0e7b3951"
|
||||
},
|
||||
"bin": {
|
||||
"gemini": "bundle/gemini.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/@google-gemini/gemini-cli-core": {
|
||||
"version": "0.11.0-nightly.20251021.0e7b3951",
|
||||
"resolved": "https://npm.pkg.github.com/download/@google-gemini/gemini-cli-core/0.11.0-nightly.20251021.0e7b3951/612a101caade1e1df620ce84e3cf83fb66f46a12",
|
||||
"integrity": "sha512-pu4KiOrjM5FVCH2LnqhirOWIHodg+giOl0nASROenzFaUD1G7/FYFT9T+OY8pmGtnrfI+dNrVolp3G5mI2Ij/w==",
|
||||
"dependencies": {
|
||||
"@google-cloud/logging": "^11.2.1",
|
||||
"@google-cloud/opentelemetry-cloud-monitoring-exporter": "^0.21.0",
|
||||
"@google-cloud/opentelemetry-cloud-trace-exporter": "^3.0.0",
|
||||
"@google/genai": "1.16.0",
|
||||
"@joshua.litt/get-ripgrep": "^0.0.2",
|
||||
"@modelcontextprotocol/sdk": "^1.11.0",
|
||||
"@opentelemetry/api": "^1.9.0",
|
||||
"@opentelemetry/exporter-logs-otlp-grpc": "^0.203.0",
|
||||
"@opentelemetry/exporter-logs-otlp-http": "^0.203.0",
|
||||
"@opentelemetry/exporter-metrics-otlp-grpc": "^0.203.0",
|
||||
"@opentelemetry/exporter-metrics-otlp-http": "^0.203.0",
|
||||
"@opentelemetry/exporter-trace-otlp-grpc": "^0.203.0",
|
||||
"@opentelemetry/exporter-trace-otlp-http": "^0.203.0",
|
||||
"@opentelemetry/instrumentation-http": "^0.203.0",
|
||||
"@opentelemetry/resource-detector-gcp": "^0.40.0",
|
||||
"@opentelemetry/sdk-node": "^0.203.0",
|
||||
"@types/glob": "^8.1.0",
|
||||
"@types/html-to-text": "^9.0.4",
|
||||
"@xterm/headless": "5.5.0",
|
||||
"ajv": "^8.17.1",
|
||||
"ajv-formats": "^3.0.0",
|
||||
"chardet": "^2.1.0",
|
||||
"diff": "^7.0.0",
|
||||
"dotenv": "^17.1.0",
|
||||
"fast-levenshtein": "^2.0.6",
|
||||
"fast-uri": "^3.0.6",
|
||||
"fdir": "^6.4.6",
|
||||
"fzf": "^0.5.2",
|
||||
"glob": "^10.4.5",
|
||||
"google-auth-library": "^9.11.0",
|
||||
"html-to-text": "^9.0.5",
|
||||
"https-proxy-agent": "^7.0.6",
|
||||
"ignore": "^7.0.0",
|
||||
"marked": "^15.0.12",
|
||||
"mime": "4.0.7",
|
||||
"mnemonist": "^0.40.3",
|
||||
"open": "^10.1.2",
|
||||
"picomatch": "^4.0.1",
|
||||
"shell-quote": "^1.8.3",
|
||||
"simple-git": "^3.28.0",
|
||||
"strip-ansi": "^7.1.0",
|
||||
"tree-sitter-bash": "^0.25.0",
|
||||
"undici": "^7.10.0",
|
||||
"web-tree-sitter": "^0.25.10",
|
||||
"ws": "^8.18.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@lydell/node-pty": "1.1.0",
|
||||
"@lydell/node-pty-darwin-arm64": "1.1.0",
|
||||
"@lydell/node-pty-darwin-x64": "1.1.0",
|
||||
"@lydell/node-pty-linux-x64": "1.1.0",
|
||||
"@lydell/node-pty-win32-arm64": "1.1.0",
|
||||
"@lydell/node-pty-win32-x64": "1.1.0",
|
||||
"node-pty": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@google-gemini/gemini-cli-core/node_modules/ajv": {
|
||||
"version": "8.17.1",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
|
||||
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"fast-uri": "^3.0.1",
|
||||
"json-schema-traverse": "^1.0.0",
|
||||
"require-from-string": "^2.0.2"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/epoberezkin"
|
||||
}
|
||||
},
|
||||
"node_modules/@google-gemini/gemini-cli-core/node_modules/fdir": {
|
||||
"version": "6.5.0",
|
||||
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
|
||||
"integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"picomatch": "^3 || ^4"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"picomatch": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@google-gemini/gemini-cli-core/node_modules/ignore": {
|
||||
"version": "7.0.5",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz",
|
||||
"integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 4"
|
||||
}
|
||||
},
|
||||
"node_modules/@google-gemini/gemini-cli-core/node_modules/json-schema-traverse": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
|
||||
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@google-gemini/gemini-cli-core/node_modules/mime": {
|
||||
"version": "4.0.7",
|
||||
"resolved": "https://registry.npmjs.org/mime/-/mime-4.0.7.tgz",
|
||||
"integrity": "sha512-2OfDPL+e03E0LrXaGYOtTFIYhiuzep94NSsuhrNULq+stylcJedcHdzHtz0atMUuGwJfFYs0YL5xeC/Ca2x0eQ==",
|
||||
"funding": [
|
||||
"https://github.com/sponsors/broofa"
|
||||
],
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"mime": "bin/cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
}
|
||||
},
|
||||
"node_modules/@google-gemini/gemini-cli-core/node_modules/picomatch": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/@google/gemini-cli": {
|
||||
"resolved": "packages/cli",
|
||||
"link": true
|
||||
@@ -5352,6 +5506,15 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/accepts/node_modules/mime-db": {
|
||||
"version": "1.52.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/accepts/node_modules/mime-types": {
|
||||
"version": "2.1.35",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||
@@ -8694,6 +8857,13 @@
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/express/node_modules/ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/express/node_modules/statuses": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
|
||||
@@ -16323,6 +16493,15 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/type-is/node_modules/mime-db": {
|
||||
"version": "1.52.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/type-is/node_modules/mime-types": {
|
||||
"version": "2.1.35",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||
|
||||
+4
-1
@@ -55,7 +55,9 @@
|
||||
"telemetry": "node scripts/telemetry.js",
|
||||
"check:lockfile": "node scripts/check-lockfile.js",
|
||||
"clean": "node scripts/clean.js",
|
||||
"pre-commit": "node scripts/pre-commit.js"
|
||||
"pre-commit": "node scripts/pre-commit.js",
|
||||
"use-dev": "node scripts/configure-registry.js dev",
|
||||
"use-prod": "node scripts/configure-registry.js prod"
|
||||
},
|
||||
"overrides": {
|
||||
"wrap-ansi": "9.0.2",
|
||||
@@ -111,6 +113,7 @@
|
||||
"yargs": "^17.7.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@google-gemini/gemini-cli": "^0.11.0-nightly.20251021.0e7b3951",
|
||||
"@testing-library/dom": "^10.4.1",
|
||||
"simple-git": "^3.28.0"
|
||||
},
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import os from 'node:os';
|
||||
import { execSync } from 'node:child_process';
|
||||
|
||||
const arg = process.argv[2];
|
||||
const homedir = os.homedir();
|
||||
const npmrcPath = path.join(homedir, '.npmrc');
|
||||
const backupPath = path.join(homedir, '.npmrc.bak');
|
||||
|
||||
const GITHUB_REGISTRY_URL = 'https://npm.pkg.github.com/';
|
||||
const GITHUB_SCOPE = '@google-gemini';
|
||||
const REGISTRY_LINE = `${GITHUB_SCOPE}:registry=${GITHUB_REGISTRY_URL}`;
|
||||
|
||||
function checkGhCli() {
|
||||
try {
|
||||
execSync('gh --version', { stdio: 'ignore' });
|
||||
return true;
|
||||
} catch (_e) {
|
||||
console.error(
|
||||
'Error: The GitHub CLI (`gh`) is not installed or not in your PATH.',
|
||||
);
|
||||
console.error('Please install it to continue: https://cli.github.com/');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function getGhAuthStatus() {
|
||||
try {
|
||||
execSync('gh auth status', { stdio: 'ignore' });
|
||||
return true;
|
||||
} catch (_e) {
|
||||
console.error('Error: You are not logged in to the GitHub CLI (`gh`).');
|
||||
console.error(
|
||||
"Please run `gh auth login` and ensure you grant the 'read:packages' and 'write:packages' scopes.",
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function getGhAuthToken() {
|
||||
try {
|
||||
const token = execSync('gh auth token', {
|
||||
encoding: 'utf8',
|
||||
}).trim();
|
||||
if (!token) {
|
||||
throw new Error('No token returned from `gh auth token`');
|
||||
}
|
||||
return token;
|
||||
} catch (_e) {
|
||||
console.error('Error: Failed to retrieve GitHub auth token.');
|
||||
console.error(
|
||||
'Please ensure you are logged in (`gh auth status`) and have the correct permissions.',
|
||||
);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function setupDev() {
|
||||
console.log(
|
||||
'Configuring your global ~/.npmrc for `dev` (GitHub Packages)...',
|
||||
);
|
||||
|
||||
if (!checkGhCli() || !getGhAuthStatus()) {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const token = getGhAuthToken();
|
||||
if (!token) {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const AUTH_LINE = `//npm.pkg.github.com/:_authToken=${token}`;
|
||||
let npmrcContent = '';
|
||||
|
||||
if (fs.existsSync(npmrcPath)) {
|
||||
npmrcContent = fs.readFileSync(npmrcPath, 'utf-8');
|
||||
if (npmrcContent.includes(REGISTRY_LINE)) {
|
||||
console.log('✅ Your ~/.npmrc file is already configured for dev.');
|
||||
return;
|
||||
}
|
||||
// Create a backup if one doesn't already exist
|
||||
if (!fs.existsSync(backupPath)) {
|
||||
fs.copyFileSync(npmrcPath, backupPath);
|
||||
console.log(`Backed up your existing configuration to ${backupPath}`);
|
||||
}
|
||||
}
|
||||
|
||||
const newContent = [
|
||||
npmrcContent,
|
||||
`\n# Added by gemini-cli for dev environment`,
|
||||
REGISTRY_LINE,
|
||||
AUTH_LINE,
|
||||
]
|
||||
.join('\n')
|
||||
.trim();
|
||||
|
||||
fs.writeFileSync(npmrcPath, newContent + '\n');
|
||||
console.log(`✅ Successfully updated your ~/.npmrc file.`);
|
||||
console.log(
|
||||
'You can now install pre-release packages, e.g., `npm install -g @google-gemini/gemini-cli@<version>`',
|
||||
);
|
||||
}
|
||||
|
||||
function setupProd() {
|
||||
console.log('Configuring your global ~/.npmrc for `prod` (npmjs.org)...');
|
||||
if (!fs.existsSync(npmrcPath)) {
|
||||
console.log('No ~/.npmrc file found. Already configured for prod.');
|
||||
return;
|
||||
}
|
||||
|
||||
let npmrcContent = fs.readFileSync(npmrcPath, 'utf-8');
|
||||
const lines = npmrcContent.split('\n');
|
||||
const filteredLines = lines.filter(
|
||||
(line) =>
|
||||
!line.includes('npm.pkg.github.com') &&
|
||||
!line.includes('@google-gemini:registry') &&
|
||||
!line.includes('# Added by gemini-cli'),
|
||||
);
|
||||
|
||||
if (lines.length === filteredLines.length) {
|
||||
console.log('✅ Your ~/.npmrc file is already configured for prod.');
|
||||
return;
|
||||
}
|
||||
|
||||
fs.writeFileSync(npmrcPath, filteredLines.join('\n').trim() + '\n');
|
||||
console.log(`✅ Successfully cleaned dev configuration from ~/.npmrc.`);
|
||||
if (fs.existsSync(backupPath)) {
|
||||
console.log(`Your original configuration was saved to ${backupPath}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (arg === 'dev') {
|
||||
setupDev();
|
||||
} else if (arg === 'prod') {
|
||||
setupProd();
|
||||
} else {
|
||||
console.error('Invalid argument. Please use `dev` or `prod`.');
|
||||
console.error('Usage: node scripts/configure-registry.js <dev|prod>');
|
||||
process.exit(1);
|
||||
}
|
||||
Reference in New Issue
Block a user