diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json new file mode 100644 index 0000000..af2b60f --- /dev/null +++ b/.claude-plugin/plugin.json @@ -0,0 +1,51 @@ +{ + "name": "cloud-sql-postgresql", + "version": "0.1.0", + "description": "Create, connect, and interact with a Cloud SQL for PostgreSQL database and data.", + "repository": "https://github.com/gemini-cli-extensions/cloud-sql-postgresql", + "skills": "./skills/", + "userConfig": { + "cloud_sql_postgres_project": { + "title": "Project ID", + "description": "ID of the Google Cloud project", + "type": "string", + "sensitive": false + }, + "cloud_sql_postgres_region": { + "title": "Region", + "description": "Region of the Cloud SQL instance", + "type": "string", + "sensitive": false + }, + "cloud_sql_postgres_instance": { + "title": "Instance Name", + "description": "Name of the Cloud SQL instance", + "type": "string", + "sensitive": false + }, + "cloud_sql_postgres_database": { + "title": "Database Name", + "description": "Name of the database", + "type": "string", + "sensitive": false + }, + "cloud_sql_postgres_user": { + "title": "Database User", + "description": "(Optional) Username of the database user (Default: IAM user)", + "type": "string", + "sensitive": false + }, + "cloud_sql_postgres_password": { + "title": "Database Password", + "description": "(Optional) Password of the database user (Default: IAM user)", + "type": "string", + "sensitive": false + }, + "cloud_sql_postgres_ip_type": { + "title": "IP Type", + "description": "(Optional) Type of the IP address: PUBLIC, PRIVATE, or PSC (Default: Public)", + "type": "string", + "sensitive": false + } + } +} diff --git a/.github/workflows/package-and-upload-assets.yml b/.github/workflows/package-and-upload-assets.yml index 1c0aff6..4a43f36 100644 --- a/.github/workflows/package-and-upload-assets.yml +++ b/.github/workflows/package-and-upload-assets.yml @@ -35,7 +35,7 @@ jobs: - { os: "linux", arch: "x64", download_path_segment: "linux/amd64", binary_suffix: "", archive_extension: "tar.gz", archive_command: 'tar -czvf "${ARCHIVE_NAME}" -C staging .' } - { os: "darwin", arch: "arm64", download_path_segment: "darwin/arm64", binary_suffix: "", archive_extension: "tar.gz", archive_command: 'tar -czvf "${ARCHIVE_NAME}" -C staging .' } - { os: "darwin", arch: "x64", download_path_segment: "darwin/amd64", binary_suffix: "", archive_extension: "tar.gz", archive_command: 'tar -czvf "${ARCHIVE_NAME}" -C staging .' } - - { os: "win32", arch: "x64", download_path_segment: "windows/amd64", binary_suffix: ".exe", archive_extension: "zip", archive_command: '(cd staging && zip ../"${ARCHIVE_NAME}" *)' } + - { os: "win32", arch: "x64", download_path_segment: "windows/amd64", binary_suffix: ".exe", archive_extension: "zip", archive_command: '(cd staging && zip -r ../"${ARCHIVE_NAME}" *)' } steps: - name: Checkout code at the new tag uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 diff --git a/skills/cloud-sql-postgres-admin/SKILL.md b/skills/cloud-sql-postgres-admin/SKILL.md deleted file mode 100644 index f9256c6..0000000 --- a/skills/cloud-sql-postgres-admin/SKILL.md +++ /dev/null @@ -1,122 +0,0 @@ ---- -name: cloud-sql-postgres-admin -description: Use these skills when you need to provision new Cloud SQL instances, create databases and users, clone existing environments, and monitor the progress of long-running operations. ---- - -## Usage - -All scripts can be executed using Node.js. Replace `` and `` with actual values. - -**Bash:** -`node /scripts/.js '{"": ""}'` - -**PowerShell:** -`node /scripts/.js '{\"\": \"\"}'` - -Note: The scripts automatically load the environment variables from various .env files. Do not ask the user to set vars unless skill executions fails due to env var absence. - -## Scripts - -### clone_instance - -Clone an existing Cloud SQL instance into a new instance. The clone can be a direct copy of the source instance, or a point-in-time-recovery (PITR) clone from a specific timestamp. The call returns a Cloud SQL Operation object. Call wait_for_operation tool after this, make sure to use multiplier as 4 to poll the opertation status till it is marked DONE. - -#### Parameters - -| Name | Type | Description | Required | Default | -| :---------------------- | :----- | :----------------------------------------------------------------------------------------------------------------- | :------- | :------ | -| project | string | The GCP project ID. This is pre-configured; do not ask for it unless the user explicitly provides a different one. | No | | -| sourceInstanceName | string | The name of the instance to be cloned. | Yes | | -| destinationInstanceName | string | The name of the new instance that will be created by cloning the source instance. | Yes | | -| pointInTime | string | The timestamp in RFC 3339 format to which the source instance should be cloned. | No | | -| preferredZone | string | The preferred zone for the new instance. | No | | -| preferredSecondaryZone | string | The preferred secondary zone for the new instance. | No | | - ---- - -### create_database - -#### Parameters - -| Name | Type | Description | Required | Default | -| :------- | :----- | :----------------------------------------------------------------------------------------------------------------- | :------- | :------ | -| project | string | The GCP project ID. This is pre-configured; do not ask for it unless the user explicitly provides a different one. | No | | -| instance | string | The ID of the instance where the database will be created. | Yes | | -| name | string | The name for the new database. Must be unique within the instance. | Yes | | - ---- - -### create_instance - -#### Parameters - -| Name | Type | Description | Required | Default | -| :-------------- | :----- | :------------------------------------------------------------------------------------------------------------------------------------------------------- | :------- | :------------ | -| project | string | The GCP project ID. This is pre-configured; do not ask for it unless the user explicitly provides a different one. | No | | -| name | string | The name of the instance | Yes | | -| databaseVersion | string | The database version for Postgres. If not specified, defaults to the latest available version (e.g., POSTGRES_17). | No | `POSTGRES_17` | -| rootPassword | string | The root password for the instance | Yes | | -| editionPreset | string | The edition of the instance. Can be `Production` or `Development`. This determines the default machine type and availability. Defaults to `Development`. | No | `Development` | - ---- - -### create_user - -#### Parameters - -| Name | Type | Description | Required | Default | -| :------- | :------ | :----------------------------------------------------------------------------------------------------------------- | :------- | :------ | -| project | string | The GCP project ID. This is pre-configured; do not ask for it unless the user explicitly provides a different one. | No | | -| instance | string | The ID of the instance where the user will be created. | Yes | | -| name | string | The name for the new user. Must be unique within the instance. | Yes | | -| password | string | A secure password for the new user. Not required for IAM users. | No | | -| iamUser | boolean | Set to true to create a Cloud IAM user. | Yes | | - ---- - -### get_instance - -#### Parameters - -| Name | Type | Description | Required | Default | -| :--------- | :----- | :----------------------------------------------------------------------------------------------------------------- | :------- | :------ | -| projectId | string | The GCP project ID. This is pre-configured; do not ask for it unless the user explicitly provides a different one. | No | | -| instanceId | string | The instance ID | Yes | | - ---- - -### list_databases - -Lists all databases for a Cloud SQL instance. - -#### Parameters - -| Name | Type | Description | Required | Default | -| :------- | :----- | :----------------------------------------------------------------------------------------------------------------- | :------- | :------ | -| project | string | The GCP project ID. This is pre-configured; do not ask for it unless the user explicitly provides a different one. | No | | -| instance | string | The instance ID | Yes | | - ---- - -### list_instances - -Lists all type of Cloud SQL instances for a project. - -#### Parameters - -| Name | Type | Description | Required | Default | -| :------ | :----- | :----------------------------------------------------------------------------------------------------------------- | :------- | :------ | -| project | string | The GCP project ID. This is pre-configured; do not ask for it unless the user explicitly provides a different one. | No | | - ---- - -### wait_for_operation - -#### Parameters - -| Name | Type | Description | Required | Default | -| :-------- | :----- | :----------------------------------------------------------------------------------------------------------------- | :------- | :------ | -| project | string | The GCP project ID. This is pre-configured; do not ask for it unless the user explicitly provides a different one. | No | | -| operation | string | The operation ID | Yes | | - ---- diff --git a/skills/cloud-sql-postgres-admin/scripts/clone_instance.js b/skills/cloud-sql-postgres-admin/scripts/clone_instance.js deleted file mode 100755 index 5d24ece..0000000 --- a/skills/cloud-sql-postgres-admin/scripts/clone_instance.js +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "clone_instance"; -const configArgs = ["--prebuilt", "cloud-sql-postgres"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -let userAgent = "skills"; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); - userAgent = "skills-geminicli"; -} - -const args = process.argv.slice(2); - -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, "--user-agent-metadata", userAgent, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-admin/scripts/create_backup.js b/skills/cloud-sql-postgres-admin/scripts/create_backup.js deleted file mode 100755 index 905d3be..0000000 --- a/skills/cloud-sql-postgres-admin/scripts/create_backup.js +++ /dev/null @@ -1,93 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - - - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "create_backup"; -const configArgs = ["--prebuilt", "cloud-sql-postgres-admin"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); -} - -const args = process.argv.slice(2); -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-admin/scripts/create_database.js b/skills/cloud-sql-postgres-admin/scripts/create_database.js deleted file mode 100755 index 376a99d..0000000 --- a/skills/cloud-sql-postgres-admin/scripts/create_database.js +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "create_database"; -const configArgs = ["--prebuilt", "cloud-sql-postgres"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -let userAgent = "skills"; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); - userAgent = "skills-geminicli"; -} - -const args = process.argv.slice(2); - -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, "--user-agent-metadata", userAgent, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-admin/scripts/create_instance.js b/skills/cloud-sql-postgres-admin/scripts/create_instance.js deleted file mode 100755 index c66c10e..0000000 --- a/skills/cloud-sql-postgres-admin/scripts/create_instance.js +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "create_instance"; -const configArgs = ["--prebuilt", "cloud-sql-postgres"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -let userAgent = "skills"; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); - userAgent = "skills-geminicli"; -} - -const args = process.argv.slice(2); - -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, "--user-agent-metadata", userAgent, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-admin/scripts/create_user.js b/skills/cloud-sql-postgres-admin/scripts/create_user.js deleted file mode 100755 index a095348..0000000 --- a/skills/cloud-sql-postgres-admin/scripts/create_user.js +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "create_user"; -const configArgs = ["--prebuilt", "cloud-sql-postgres"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -let userAgent = "skills"; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); - userAgent = "skills-geminicli"; -} - -const args = process.argv.slice(2); - -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, "--user-agent-metadata", userAgent, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-admin/scripts/get_instance.js b/skills/cloud-sql-postgres-admin/scripts/get_instance.js deleted file mode 100755 index 216e7e8..0000000 --- a/skills/cloud-sql-postgres-admin/scripts/get_instance.js +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "get_instance"; -const configArgs = ["--prebuilt", "cloud-sql-postgres"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -let userAgent = "skills"; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); - userAgent = "skills-geminicli"; -} - -const args = process.argv.slice(2); - -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, "--user-agent-metadata", userAgent, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-admin/scripts/list_databases.js b/skills/cloud-sql-postgres-admin/scripts/list_databases.js deleted file mode 100755 index cb0729a..0000000 --- a/skills/cloud-sql-postgres-admin/scripts/list_databases.js +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "list_databases"; -const configArgs = ["--prebuilt", "cloud-sql-postgres"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -let userAgent = "skills"; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); - userAgent = "skills-geminicli"; -} - -const args = process.argv.slice(2); - -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, "--user-agent-metadata", userAgent, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-admin/scripts/list_instances.js b/skills/cloud-sql-postgres-admin/scripts/list_instances.js deleted file mode 100755 index b24402c..0000000 --- a/skills/cloud-sql-postgres-admin/scripts/list_instances.js +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "list_instances"; -const configArgs = ["--prebuilt", "cloud-sql-postgres"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -let userAgent = "skills"; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); - userAgent = "skills-geminicli"; -} - -const args = process.argv.slice(2); - -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, "--user-agent-metadata", userAgent, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-admin/scripts/postgres_upgrade_precheck.js b/skills/cloud-sql-postgres-admin/scripts/postgres_upgrade_precheck.js deleted file mode 100755 index 6e96773..0000000 --- a/skills/cloud-sql-postgres-admin/scripts/postgres_upgrade_precheck.js +++ /dev/null @@ -1,93 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - - - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "postgres_upgrade_precheck"; -const configArgs = ["--prebuilt", "cloud-sql-postgres-admin"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); -} - -const args = process.argv.slice(2); -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-admin/scripts/restore_backup.js b/skills/cloud-sql-postgres-admin/scripts/restore_backup.js deleted file mode 100755 index 7ece0bf..0000000 --- a/skills/cloud-sql-postgres-admin/scripts/restore_backup.js +++ /dev/null @@ -1,93 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - - - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "restore_backup"; -const configArgs = ["--prebuilt", "cloud-sql-postgres-admin"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); -} - -const args = process.argv.slice(2); -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-admin/scripts/wait_for_operation.js b/skills/cloud-sql-postgres-admin/scripts/wait_for_operation.js deleted file mode 100755 index 3bd09d9..0000000 --- a/skills/cloud-sql-postgres-admin/scripts/wait_for_operation.js +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "wait_for_operation"; -const configArgs = ["--prebuilt", "cloud-sql-postgres"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -let userAgent = "skills"; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); - userAgent = "skills-geminicli"; -} - -const args = process.argv.slice(2); - -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, "--user-agent-metadata", userAgent, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-data/SKILL.md b/skills/cloud-sql-postgres-data/SKILL.md index f9f6956..13b4d9b 100644 --- a/skills/cloud-sql-postgres-data/SKILL.md +++ b/skills/cloud-sql-postgres-data/SKILL.md @@ -27,104 +27,4 @@ Use this skill to execute sql. | :--- | :----- | :------------------ | :------- | :------ | | sql | string | The sql to execute. | Yes | | ---- - -### list_indexes - -Lists available user indexes in the database, excluding system schemas (pg_catalog, information_schema). For each index, the following properties are returned: schema name, table name, index name, index type (access method), a boolean indicating if it's a unique index, a boolean indicating if it's for a primary key, the index definition, index size in bytes, the number of index scans, the number of index tuples read, the number of table tuples fetched via index scans, and a boolean indicating if the index has been used at least once. - -#### Parameters - -| Name | Type | Description | Required | Default | -| :---------- | :------ | :----------------------------------------------------------------------------------------- | :------- | :------ | -| schema_name | string | Optional: a text to filter results by schema name. The input is used within a LIKE clause. | No | `` | -| table_name | string | Optional: a text to filter results by table name. The input is used within a LIKE clause. | No | `` | -| index_name | string | Optional: a text to filter results by index name. The input is used within a LIKE clause. | No | `` | -| only_unused | boolean | Optional: If true, only returns indexes that have never been used. | No | `false` | -| limit | integer | Optional: The maximum number of rows to return. Default is 50 | No | `50` | - ---- - -### list_schemas - -Lists all schemas in the database ordered by schema name and excluding system and temporary schemas. It returns the schema name, schema owner, grants, number of functions, number of tables and number of views within each schema. - -#### Parameters - -| Name | Type | Description | Required | Default | -| :---------- | :------ | :------------------------------------------------------------ | :------- | :------ | -| schema_name | string | Optional: A specific schema name pattern to search for. | No | `` | -| owner | string | Optional: A specific schema owner name pattern to search for. | No | `` | -| limit | integer | Optional: The maximum number of schemas to return. | No | `10` | - ---- - -### list_sequences - -Lists sequences in the database. Returns sequence name, schema name, sequence owner, data type of the sequence, starting value, minimum value, maximum value of the sequence, the value by which the sequence is incremented, and the last value generated by the sequence in the current session - -#### Parameters - -| Name | Type | Description | Required | Default | -| :------------ | :------ | :------------------------------------------------------------ | :------- | :------ | -| schema_name | string | Optional: A specific schema name pattern to search for. | No | `` | -| sequence_name | string | Optional: A specific sequence name pattern to search for. | No | `` | -| limit | integer | Optional: The maximum number of rows to return. Default is 50 | No | `50` | - ---- - -### list_stored_procedure - -Retrieves stored procedure metadata returning schema name, procedure name, procedure owner, language, definition, and description, filtered by optional role name (procedure owner), schema name, and limit (default 20). - -#### Parameters - -| Name | Type | Description | Required | Default | -| :---------- | :------ | :------------------------------------------------------------------------------ | :------- | :------ | -| role_name | string | Optional: The owner name to filter the stored procedures by. Defaults to NULL. | No | | -| schema_name | string | Optional: The schema name to filter the stored procedures by. Defaults to NULL. | No | | -| limit | integer | Optional: The maximum number of stored procedures to return. Defaults to 20. | No | `20` | - ---- - -### list_tables - -Lists detailed schema information (object type, columns, constraints, indexes, triggers, owner, comment) as JSON for user-created tables (ordinary or partitioned). Filters by a comma-separated list of names. If names are omitted, lists all tables in user schemas. - -#### Parameters - -| Name | Type | Description | Required | Default | -| :------------ | :----- | :------------------------------------------------------------------------------------------------ | :------- | :--------- | -| table_names | string | Optional: A comma-separated list of table names. If empty, details for all tables will be listed. | No | `` | -| output_format | string | Optional: Use 'simple' for names only or 'detailed' for full info. | No | `detailed` | - ---- - -### list_triggers - -Lists all non-internal triggers in a database. Returns trigger name, schema name, table name, whether its enabled or disabled, timing (e.g BEFORE/AFTER of the event), the events that cause the trigger to fire such as INSERT, UPDATE, or DELETE, whether the trigger activates per ROW or per STATEMENT, the handler function executed by the trigger and full definition. - -#### Parameters - -| Name | Type | Description | Required | Default | -| :----------- | :------ | :------------------------------------------------------- | :------- | :------ | -| trigger_name | string | Optional: A specific trigger name pattern to search for. | No | `` | -| schema_name | string | Optional: A specific schema name pattern to search for. | No | `` | -| table_name | string | Optional: A specific table name pattern to search for. | No | `` | -| limit | integer | Optional: The maximum number of rows to return. | No | `50` | - ---- - -### list_views - -Lists views in the database from pg_views with a default limit of 50 rows. Returns schemaname, viewname, ownername and the definition. - -#### Parameters - -| Name | Type | Description | Required | Default | -| :---------- | :------ | :---------------------------------------------- | :------- | :------ | -| view_name | string | Optional: A specific view name to search for. | No | `` | -| schema_name | string | Optional: A specific schema name to search for. | No | `` | -| limit | integer | Optional: The maximum number of rows to return. | No | `50` | - ---- +--- \ No newline at end of file diff --git a/skills/cloud-sql-postgres-data/scripts/execute_sql.js b/skills/cloud-sql-postgres-data/scripts/execute_sql.js index 5e592f7..0bb0cd9 100755 --- a/skills/cloud-sql-postgres-data/scripts/execute_sql.js +++ b/skills/cloud-sql-postgres-data/scripts/execute_sql.js @@ -14,81 +14,116 @@ // See the License for the specific language governing permissions and // limitations under the License. -const { spawn, execSync } = require('child_process'); +const { spawn } = require('child_process'); const path = require('path'); const fs = require('fs'); +const os = require('os'); -const toolName = "execute_sql"; -const configArgs = ["--prebuilt", "cloud-sql-postgres"]; +/** + * Configuration Constants + */ +const TOOL_NAME = "execute_sql"; +const CONFIG_ARGS = ["--prebuilt", "cloud-sql-postgres"]; +const OPTIONAL_VARS_TO_OMIT_IF_EMPTY = [ + 'CLOUD_SQL_POSTGRES_USER', + 'CLOUD_SQL_POSTGRES_PASSWORD', + 'CLOUD_SQL_POSTGRES_IP_TYPE' +]; + +/** + * Merges external variables into the environment based on the current context. + * For GEMINI_CLI, it loads from a .env file. + * For CLAUDE_CODE, it transforms CLAUDE_PLUGIN_ prefixed variables. + * @param {Object} env The environment object to populate. + */ +function mergeContextualVariables(env) { + const env = {}; -function getToolboxPath() { if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; + const envPath = path.resolve(__dirname, '../../../.env'); + if (fs.existsSync(envPath)) { + fs.readFileSync(envPath, 'utf-8').split('\n').forEach(line => { + const trimmed = line.trim(); + if (!trimmed || trimmed.startsWith('#')) return; + const splitIdx = trimmed.indexOf('='); + if (splitIdx === -1) return; + const key = trimmed.slice(0, splitIdx).trim(); + const value = trimmed.slice(splitIdx + 1).trim().replace(/(^['"]|['"]$)/g, ''); + env[key] = value; + }); } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); + } else if (process.env.CLAUDECODE === '1') { + const prefix = 'CLAUDE_PLUGIN_OPTION_'; + for (const key in process.env) { + if (key.startsWith(prefix)) { + env[key.substring(prefix.length)] = process.env[key]; + } } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); } } -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); +/** + * Prepares the environment and determines the user agent. + * @returns {{ env: Object, userAgent: string }} + */ +function prepareEnvironment() { const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); + let userAgent = "skills"; + + if (process.env.GEMINI_CLI === '1') { + userAgent = "skills-geminicli"; + } else if (process.env.CLAUDECODE === '1') { + userAgent = "skills-claudecode"; } - return env; -} -let env = process.env; -let userAgent = "skills"; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); - userAgent = "skills-geminicli"; + mergeContextualVariables(env); + + // Omit optional variables if they are empty strings to avoid misconfiguration + OPTIONAL_VARS_TO_OMIT_IF_EMPTY.forEach(key => { + if (env[key] === '') { + delete env[key]; + } + }); + + return { env, userAgent }; } -const args = process.argv.slice(2); +/** + * Main execution function. + */ +function main() { + const { env, userAgent } = prepareEnvironment(); + const args = process.argv.slice(2); + const npxArgs = ["--yes", "@toolbox-sdk/server", "--log-level", "error", ...CONFIG_ARGS, "invoke", TOOL_NAME, "--user-agent-metadata", userAgent, ...args]; -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, "--user-agent-metadata", userAgent, ...args]; + let command = 'npx'; + let spawnArgs = npxArgs; -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); + // The Windows Dependency-Free Bypass + if (os.platform() === 'win32') { + const nodeDir = path.dirname(process.execPath); + const npxCliJs = path.join(nodeDir, 'node_modules', 'npm', 'bin', 'npx-cli.js'); -child.on('close', (code) => { - process.exit(code); -}); + if (fs.existsSync(npxCliJs)) { + command = process.execPath; + spawnArgs = [npxCliJs, ...npxArgs]; + } else { + console.error("Error: Could not find the npx executable to launch."); + process.exit(1); + } + } + + const child = spawn(command, spawnArgs, { stdio: 'inherit', env }); + + child.on('close', (code) => { + process.exit(code); + }); + + child.on('error', (err) => { + console.error("Error executing toolbox:", err); + process.exit(1); + }); +} -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); +// Start the script +main(); diff --git a/skills/cloud-sql-postgres-data/scripts/list_indexes.js b/skills/cloud-sql-postgres-data/scripts/list_indexes.js deleted file mode 100755 index f1b166c..0000000 --- a/skills/cloud-sql-postgres-data/scripts/list_indexes.js +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "list_indexes"; -const configArgs = ["--prebuilt", "cloud-sql-postgres"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -let userAgent = "skills"; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); - userAgent = "skills-geminicli"; -} - -const args = process.argv.slice(2); - -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, "--user-agent-metadata", userAgent, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-data/scripts/list_schemas.js b/skills/cloud-sql-postgres-data/scripts/list_schemas.js deleted file mode 100755 index 3f56502..0000000 --- a/skills/cloud-sql-postgres-data/scripts/list_schemas.js +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "list_schemas"; -const configArgs = ["--prebuilt", "cloud-sql-postgres"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -let userAgent = "skills"; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); - userAgent = "skills-geminicli"; -} - -const args = process.argv.slice(2); - -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, "--user-agent-metadata", userAgent, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-data/scripts/list_sequences.js b/skills/cloud-sql-postgres-data/scripts/list_sequences.js deleted file mode 100755 index 42a90be..0000000 --- a/skills/cloud-sql-postgres-data/scripts/list_sequences.js +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "list_sequences"; -const configArgs = ["--prebuilt", "cloud-sql-postgres"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -let userAgent = "skills"; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); - userAgent = "skills-geminicli"; -} - -const args = process.argv.slice(2); - -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, "--user-agent-metadata", userAgent, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-data/scripts/list_stored_procedure.js b/skills/cloud-sql-postgres-data/scripts/list_stored_procedure.js deleted file mode 100755 index e43c4e6..0000000 --- a/skills/cloud-sql-postgres-data/scripts/list_stored_procedure.js +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "list_stored_procedure"; -const configArgs = ["--prebuilt", "cloud-sql-postgres"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -let userAgent = "skills"; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); - userAgent = "skills-geminicli"; -} - -const args = process.argv.slice(2); - -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, "--user-agent-metadata", userAgent, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-data/scripts/list_tables.js b/skills/cloud-sql-postgres-data/scripts/list_tables.js deleted file mode 100755 index b90c28e..0000000 --- a/skills/cloud-sql-postgres-data/scripts/list_tables.js +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "list_tables"; -const configArgs = ["--prebuilt", "cloud-sql-postgres"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -let userAgent = "skills"; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); - userAgent = "skills-geminicli"; -} - -const args = process.argv.slice(2); - -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, "--user-agent-metadata", userAgent, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-data/scripts/list_triggers.js b/skills/cloud-sql-postgres-data/scripts/list_triggers.js deleted file mode 100755 index c1e7fff..0000000 --- a/skills/cloud-sql-postgres-data/scripts/list_triggers.js +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "list_triggers"; -const configArgs = ["--prebuilt", "cloud-sql-postgres"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -let userAgent = "skills"; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); - userAgent = "skills-geminicli"; -} - -const args = process.argv.slice(2); - -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, "--user-agent-metadata", userAgent, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-data/scripts/list_views.js b/skills/cloud-sql-postgres-data/scripts/list_views.js deleted file mode 100755 index 373d4f6..0000000 --- a/skills/cloud-sql-postgres-data/scripts/list_views.js +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "list_views"; -const configArgs = ["--prebuilt", "cloud-sql-postgres"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -let userAgent = "skills"; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); - userAgent = "skills-geminicli"; -} - -const args = process.argv.slice(2); - -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, "--user-agent-metadata", userAgent, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-health/SKILL.md b/skills/cloud-sql-postgres-health/SKILL.md deleted file mode 100644 index 13227df..0000000 --- a/skills/cloud-sql-postgres-health/SKILL.md +++ /dev/null @@ -1,203 +0,0 @@ ---- -name: cloud-sql-postgres-health -description: Use these skills when you need to audit database health, identify storage bloat, find invalid indexes, analyze table statistics, and manage maintenance configurations like autovacuum. ---- - -## Usage - -All scripts can be executed using Node.js. Replace `` and `` with actual values. - -**Bash:** -`node /scripts/.js '{"": ""}'` - -**PowerShell:** -`node /scripts/.js '{\"\": \"\"}'` - -Note: The scripts automatically load the environment variables from various .env files. Do not ask the user to set vars unless skill executions fails due to env var absence. - -## Scripts - -### get_query_metrics - -Fetches query level cloudmonitoring data (timeseries metrics) for queries running in Postgres instance using a PromQL query. Take projectID and instanceID from the user for which the metrics timeseries data needs to be fetched. -To use this tool, you must provide the Google Cloud `projectId` and a PromQL `query`. - -Generate PromQL `query` for Postgres query metrics. Use the provided metrics and rules to construct queries, Get the labels like `instance_id`, `query_hash` from user intent. If query_hash is provided then use the per_query metrics. Query hash and query id are same. - -Defaults: - -1. Interval: Use a default interval of `5m` for `_over_time` aggregation functions unless a different window is specified by the user. - -PromQL Query Examples: - -1. Basic Time Series: `avg_over_time({"__name__"="cloudsql.googleapis.com/database/postgresql/insights/aggregate/execution_time","monitored_resource"="cloudsql_instance_database","project_id"="my-projectId","resource_id"="my-projectId:my-instanceId"}[5m])` -2. Top K: `topk(30, avg_over_time({"__name__"="cloudsql.googleapis.com/database/postgresql/insights/aggregate/execution_time","monitored_resource"="cloudsql_instance_database","project_id"="my-projectId","resource_id"="my-projectId:my-instanceId"}[5m]))` -3. Mean: `avg(avg_over_time({"__name__"="cloudsql.googleapis.com/database/postgresql/insights/aggregate/execution_time","monitored_resource"="cloudsql_instance_database","project_id"="my-projectId","resource_id"="my-projectId:my-instanceId"}[5m]))` -4. Minimum: `min(min_over_time({"__name__"="cloudsql.googleapis.com/database/postgresql/insights/aggregate/execution_time","monitored_resource"="cloudsql_instance_database","project_id"="my-projectId","resource_id"="my-projectId:my-instanceId"}[5m]))` -5. Maximum: `max(max_over_time({"__name__"="cloudsql.googleapis.com/database/postgresql/insights/aggregate/execution_time","monitored_resource"="cloudsql_instance_database","project_id"="my-projectId","resource_id"="my-projectId:my-instanceId"}[5m]))` -6. Sum: `sum(avg_over_time({"__name__"="cloudsql.googleapis.com/database/postgresql/insights/aggregate/execution_time","monitored_resource"="cloudsql_instance_database","project_id"="my-projectId","resource_id"="my-projectId:my-instanceId"}[5m]))` -7. Count streams: `count(avg_over_time({"__name__"="cloudsql.googleapis.com/database/postgresql/insights/aggregate/execution_time","monitored_resource"="cloudsql_instance_database","project_id"="my-projectId","resource_id"="my-projectId:my-instanceId"}[5m]))` -8. Percentile with groupby on resource_id, database: `quantile by ("resource_id","database")(0.99,avg_over_time({"__name__"="cloudsql.googleapis.com/database/postgresql/insights/aggregate/execution_time","monitored_resource"="cloudsql_instance_database","project_id"="my-projectId","resource_id"="my-projectId:my-instanceId"}[5m]))` - -Available Metrics List: metricname. description. monitored resource. labels. resource_id label format is `project_id:instance_id` which is actually instance id only. aggregate is the aggregated values for all query stats, Use aggregate metrics if query id is not provided. For perquery metrics do not fetch querystring unless specified by user specifically. Have the aggregation on query hash to avoid fetching the querystring. Do not use latency metrics for anything. - -1. `cloudsql.googleapis.com/database/postgresql/insights/aggregate/latencies`: Aggregated query latency distribution. `cloudsql_instance_database`. `user`, `client_addr`, `project_id`, `resource_id`. -2. `cloudsql.googleapis.com/database/postgresql/insights/aggregate/execution_time`: Accumulated aggregated query execution time since the last sample. `cloudsql_instance_database`. `user`, `client_addr`, `project_id`, `resource_id`. -3. `cloudsql.googleapis.com/database/postgresql/insights/aggregate/io_time`: Accumulated aggregated IO time since the last sample. `cloudsql_instance_database`. `user`, `client_addr`, `io_type`, `project_id`, `resource_id`. -4. `cloudsql.googleapis.com/database/postgresql/insights/aggregate/lock_time`: Accumulated aggregated lock wait time since the last sample. `cloudsql_instance_database`. `user`, `client_addr`, `lock_type`, `project_id`, `resource_id`. -5. `cloudsql.googleapis.com/database/postgresql/insights/aggregate/row_count`: Aggregated number of retrieved or affected rows since the last sample. `cloudsql_instance_database`. `user`, `client_addr`, `project_id`, `resource_id`. -6. `cloudsql.googleapis.com/database/postgresql/insights/aggregate/shared_blk_access_count`: Aggregated shared blocks accessed by statement execution. `cloudsql_instance_database`. `user`, `client_addr`, `access_type`, `project_id`, `resource_id`. -7. `cloudsql.googleapis.com/database/postgresql/insights/perquery/latencies`: Per query latency distribution. `cloudsql_instance_database`. `user`, `client_addr`, `querystring`, `query_hash`, `project_id`, `resource_id`. -8. `cloudsql.googleapis.com/database/postgresql/insights/perquery/execution_time`: Accumulated execution times per user per database per query. `cloudsql_instance_database`. `user`, `client_addr`, `querystring`, `query_hash`, `project_id`, `resource_id`. -9. `cloudsql.googleapis.com/database/postgresql/insights/perquery/io_time`: Accumulated IO time since the last sample per query. `cloudsql_instance_database`. `user`, `client_addr`, `io_type`, `querystring`, `query_hash`, `project_id`, `resource_id`. -10. `cloudsql.googleapis.com/database/postgresql/insights/perquery/lock_time`: Accumulated lock wait time since the last sample per query. `cloudsql_instance_database`. `user`, `client_addr`, `lock_type`, `querystring`, `query_hash`, `project_id`, `resource_id`. -11. `cloudsql.googleapis.com/database/postgresql/insights/perquery/row_count`: The number of retrieved or affected rows since the last sample per query. `cloudsql_instance_database`. `user`, `client_addr`, `querystring`, `query_hash`, `project_id`, `resource_id`. -12. `cloudsql.googleapis.com/database/postgresql/insights/perquery/shared_blk_access_count`: Shared blocks accessed by statement execution per query. `cloudsql_instance_database`. `user`, `client_addr`, `access_type`, `querystring`, `query_hash`, `project_id`, `resource_id`. -13. `cloudsql.googleapis.com/database/postgresql/insights/pertag/latencies`: Query latency distribution. `cloudsql_instance_database`. `user`, `client_addr`, `action`, `application`, `controller`, `db_driver`, `framework`, `route`, `tag_hash`, `project_id`, `resource_id`. -14. `cloudsql.googleapis.com/database/postgresql/insights/pertag/execution_time`: Accumulated execution times since the last sample. `cloudsql_instance_database`. `user`, `client_addr`, `action`, `application`, `controller`, `db_driver`, `framework`, `route`, `tag_hash`, `project_id`, `resource_id`. -15. `cloudsql.googleapis.com/database/postgresql/insights/pertag/io_time`: Accumulated IO time since the last sample per tag. `cloudsql_instance_database`. `user`, `client_addr`, `action`, `application`, `controller`, `db_driver`, `framework`, `route`, `io_type`, `tag_hash`, `project_id`, `resource_id`. -16. `cloudsql.googleapis.com/database/postgresql/insights/pertag/lock_time`: Accumulated lock wait time since the last sample per tag. `cloudsql_instance_database`. `user`, `client_addr`, `action`, `application`, `controller`, `db_driver`, `framework`, `route`, `lock_type`, `tag_hash`, `project_id`, `resource_id`. -17. `cloudsql.googleapis.com/database/postgresql/insights/pertag/shared_blk_access_count`: Shared blocks accessed by statement execution per tag. `cloudsql_instance_database`. `user`, `client_addr`, `action`, `application`, `controller`, `db_driver`, `framework`, `route`, `access_type`, `tag_hash`, `project_id`, `resource_id`. -18. `cloudsql.googleapis.com/database/postgresql/insights/pertag/row_count`: The number of retrieved or affected rows since the last sample per tag. `cloudsql_instance_database`. `user`, `client_addr`, `action`, `application`, `controller`, `db_driver`, `framework`, `route`, `tag_hash`, `project_id`, `resource_id`. - -#### Parameters - -| Name | Type | Description | Required | Default | -| :-------- | :----- | :---------------------------------- | :------- | :------ | -| projectId | string | The Id of the Google Cloud project. | Yes | | -| query | string | The promql query to execute. | Yes | | - ---- - -### get_query_plan - -Generate a PostgreSQL EXPLAIN plan in JSON format for a single SQL statement—without executing it. This returns the optimizer's estimated plan, costs, and rows (no ANALYZE, no extra options). Use in production safely for plan inspection, regression checks, and query tuning workflows. - -#### Parameters - -| Name | Type | Description | Required | Default | -| :---- | :----- | :-------------------------------------------------------------------------------- | :------- | :------ | -| query | string | The SQL statement for which you want to generate plan (omit the EXPLAIN keyword). | Yes | | - ---- - -### get_system_metrics - -Fetches system level cloudmonitoring data (timeseries metrics) for a Postgres instance using a PromQL query. Take projectId and instanceId from the user for which the metrics timeseries data needs to be fetched. -To use this tool, you must provide the Google Cloud `projectId` and a PromQL `query`. - -Generate PromQL `query` for Postgres system metrics. Use the provided metrics and rules to construct queries, Get the labels like `instance_id` from user intent. - -Defaults: - -1. Interval: Use a default interval of `5m` for `_over_time` aggregation functions unless a different window is specified by the user. - -PromQL Query Examples: - -1. Basic Time Series: `avg_over_time({"__name__"="cloudsql.googleapis.com/database/cpu/utilization","monitored_resource"="cloudsql_database","project_id"="my-projectId","database_id"="my-projectId:my-instanceId"}[5m])` -2. Top K: `topk(30, avg_over_time({"__name__"="cloudsql.googleapis.com/database/cpu/utilization","monitored_resource"="cloudsql_database","project_id"="my-projectId","database_id"="my-projectId:my-instanceId"}[5m]))` -3. Mean: `avg(avg_over_time({"__name__"="cloudsql.googleapis.com/database/cpu/utilization","monitored_resource"="cloudsql_database","project_id"="my-projectId","database_id"="my-projectId:my-instanceId"}[5m]))` -4. Minimum: `min(min_over_time({"__name__"="cloudsql.googleapis.com/database/cpu/utilization","monitored_resource"="cloudsql_database","project_id"="my-projectId","database_id"="my-projectId:my-instanceId"}[5m]))` -5. Maximum: `max(max_over_time({"__name__"="cloudsql.googleapis.com/database/cpu/utilization","monitored_resource"="cloudsql_database","project_id"="my-projectId","database_id"="my-projectId:my-instanceId"}[5m]))` -6. Sum: `sum(avg_over_time({"__name__"="cloudsql.googleapis.com/database/cpu/utilization","monitored_resource"="cloudsql_database","project_id"="my-projectId","database_id"="my-projectId:my-instanceId"}[5m]))` -7. Count streams: `count(avg_over_time({"__name__"="cloudsql.googleapis.com/database/cpu/utilization","monitored_resource"="cloudsql_database","project_id"="my-projectId","database_id"="my-projectId:my-instanceId"}[5m]))` -8. Percentile with groupby on database_id: `quantile by ("database_id")(0.99,avg_over_time({"__name__"="cloudsql.googleapis.com/database/cpu/utilization","monitored_resource"="cloudsql_database","project_id"="my-projectId","database_id"="my-projectId:my-instanceId"}[5m]))` - -Available Metrics List: metricname. description. monitored resource. labels. database_id is actually the instance id and the format is `project_id:instance_id`. - -1. `cloudsql.googleapis.com/database/postgresql/new_connection_count`: Count of new connections added to the postgres instance. `cloudsql_database`. `database`, `project_id`, `database_id`. -2. `cloudsql.googleapis.com/database/postgresql/backends_in_wait`: Number of backends in wait in postgres instance. `cloudsql_database`. `backend_type`, `wait_event`, `wait_event_type`, `project_id`, `database_id`. -3. `cloudsql.googleapis.com/database/postgresql/transaction_count`: Delta count of number of transactions. `cloudsql_database`. `database`, `transaction_type`, `project_id`, `database_id`. -4. `cloudsql.googleapis.com/database/memory/components`: Memory stats components in percentage as usage, cache and free memory for the database. `cloudsql_database`. `component`, `project_id`, `database_id`. -5. `cloudsql.googleapis.com/database/postgresql/external_sync/max_replica_byte_lag`: Replication lag in bytes for Postgres External Server (ES) replicas. Aggregated across all DBs on the replica. `cloudsql_database`. `project_id`, `database_id`. -6. `cloudsql.googleapis.com/database/cpu/utilization`: Current CPU utilization represented as a percentage of the reserved CPU that is currently in use. Values are typically numbers between 0.0 and 1.0 (but might exceed 1.0). Charts display the values as a percentage between 0% and 100% (or more). `cloudsql_database`. `project_id`, `database_id`. -7. `cloudsql.googleapis.com/database/disk/bytes_used_by_data_type`: Data utilization in bytes. `cloudsql_database`. `data_type`, `project_id`, `database_id`. -8. `cloudsql.googleapis.com/database/disk/read_ops_count`: Delta count of data disk read IO operations. `cloudsql_database`. `project_id`, `database_id`. -9. `cloudsql.googleapis.com/database/disk/write_ops_count`: Delta count of data disk write IO operations. `cloudsql_database`. `project_id`, `database_id`. -10. `cloudsql.googleapis.com/database/postgresql/num_backends_by_state`: Number of connections to the Cloud SQL PostgreSQL instance, grouped by its state. `cloudsql_database`. `database`, `state`, `project_id`, `database_id`. -11. `cloudsql.googleapis.com/database/postgresql/num_backends`: Number of connections to the Cloud SQL PostgreSQL instance. `cloudsql_database`. `database`, `project_id`, `database_id`. -12. `cloudsql.googleapis.com/database/network/received_bytes_count`: Delta count of bytes received through the network. `cloudsql_database`. `project_id`, `database_id`. -13. `cloudsql.googleapis.com/database/network/sent_bytes_count`: Delta count of bytes sent through the network. `cloudsql_database`. `destination`, `project_id`, `database_id`. -14. `cloudsql.googleapis.com/database/postgresql/deadlock_count`: Number of deadlocks detected for this database. `cloudsql_database`. `database`, `project_id`, `database_id`. -15. `cloudsql.googleapis.com/database/postgresql/blocks_read_count`: Number of disk blocks read by this database. The source field distingushes actual reads from disk versus reads from buffer cache. `cloudsql_database`. `database`, `source`, `project_id`, `database_id`. -16. `cloudsql.googleapis.com/database/postgresql/tuples_processed_count`: Number of tuples(rows) processed for a given database for operations like insert, update or delete. `cloudsql_database`. `operation_type`, `database`, `project_id`, `database_id`. -17. `cloudsql.googleapis.com/database/postgresql/tuple_size`: Number of tuples (rows) in the database. `cloudsql_database`. `database`, `tuple_state`, `project_id`, `database_id`. -18. `cloudsql.googleapis.com/database/postgresql/vacuum/oldest_transaction_age`: Age of the oldest transaction yet to be vacuumed in the Cloud SQL PostgreSQL instance, measured in number of transactions that have happened since the oldest transaction. `cloudsql_database`. `oldest_transaction_type`, `project_id`, `database_id`. -19. `cloudsql.googleapis.com/database/replication/log_archive_success_count`: Number of successful attempts for archiving replication log files. `cloudsql_database`. `project_id`, `database_id`. -20. `cloudsql.googleapis.com/database/replication/log_archive_failure_count`: Number of failed attempts for archiving replication log files. `cloudsql_database`. `project_id`, `database_id`. -21. `cloudsql.googleapis.com/database/postgresql/transaction_id_utilization`: Current utilization represented as a percentage of transaction IDs consumed by the Cloud SQL PostgreSQL instance. Values are typically numbers between 0.0 and 1.0. Charts display the values as a percentage between 0% and 100% . `cloudsql_database`. `project_id`, `database_id`. -22. `cloudsql.googleapis.com/database/postgresql/num_backends_by_application`: Number of connections to the Cloud SQL PostgreSQL instance, grouped by applications. `cloudsql_database`. `application`, `project_id`, `database_id`. -23. `cloudsql.googleapis.com/database/postgresql/tuples_fetched_count`: Total number of rows fetched as a result of queries per database in the PostgreSQL instance. `cloudsql_database`. `database`, `project_id`, `database_id`. -24. `cloudsql.googleapis.com/database/postgresql/tuples_returned_count`: Total number of rows scanned while processing the queries per database in the PostgreSQL instance. `cloudsql_database`. `database`, `project_id`, `database_id`. -25. `cloudsql.googleapis.com/database/postgresql/temp_bytes_written_count`: Total amount of data (in bytes) written to temporary files by the queries per database. `cloudsql_database`. `database`, `project_id`, `database_id`. -26. `cloudsql.googleapis.com/database/postgresql/temp_files_written_count`: Total number of temporary files used for writing data while performing algorithms such as join and sort. `cloudsql_database`. `database`, `project_id`, `database_id`. - -#### Parameters - -| Name | Type | Description | Required | Default | -| :-------- | :----- | :---------------------------------- | :------- | :------ | -| projectId | string | The Id of the Google Cloud project. | Yes | | -| query | string | The promql query to execute. | Yes | | - ---- - -### list_active_queries - -List the top N (default 50) currently running queries (state='active') from pg_stat_activity, ordered by longest-running first. Returns pid, user, database, application_name, client_addr, state, wait_event_type/wait_event, backend/xact/query start times, computed query_duration, and the SQL text. - -#### Parameters - -| Name | Type | Description | Required | Default | -| :------------------------ | :------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------- | :--------- | -| min_duration | string | Optional: Only show queries running at least this long (e.g., '1 minute', '1 second', '2 seconds'). | No | `1 minute` | -| exclude_application_names | string | Optional: A comma-separated list of application names to exclude from the query results. This is useful for filtering out queries from specific applications (e.g., 'psql', 'pgAdmin', 'DBeaver'). The match is case-sensitive. Whitespace around commas and names is automatically handled. If this parameter is omitted, no applications are excluded. | No | `` | -| limit | integer | Optional: The maximum number of rows to return. | No | `50` | - ---- - -### list_database_stats - -#### Parameters - -| Name | Type | Description | Required | Default | -| :----------------- | :------ | :--------------------------------------------------------------------------------- | :------- | :------ | -| database_name | string | Optional: A specific database name pattern to search for. | No | `` | -| include_templates | boolean | Optional: Whether to include template databases in the results. | No | `false` | -| database_owner | string | Optional: A specific database owner name pattern to search for. | No | `` | -| default_tablespace | string | Optional: A specific default tablespace name pattern to search for. | No | `` | -| order_by | string | Optional: The field to order the results by. Valid values are 'size' and 'commit'. | No | `` | -| limit | integer | Optional: The maximum number of rows to return. | No | `10` | - ---- - -### list_locks - -Identifies all locks held by active processes showing the process ID, user, query text, and an aggregated list of all transactions and specific locks (relation, mode, grant status) associated with each process. - ---- - -### list_query_stats - -Lists performance statistics for executed queries ordered by total time, filtering by database name pattern if provided. This skill requires the pg_stat_statements extension to be installed. The skill returns the database name, query text, execution count, timing metrics (total, min, max, mean), rows affected, and buffer cache I/O statistics (hits and reads). - -#### Parameters - -| Name | Type | Description | Required | Default | -| :------------ | :------ | :----------------------------------------------------------------- | :------- | :------ | -| database_name | string | Optional: The database name to list query stats for. | No | `` | -| limit | integer | Optional: The maximum number of results to return. Defaults to 50. | No | `50` | - ---- - -### long_running_transactions - -Identifies and lists database transactions that exceed a specified time limit. For each of the long running transactions, the output contains the process id, database name, user name, application name, client address, state, connection age, transaction age, query age, last activity age, wait event type, wait event, and query string. - -#### Parameters - -| Name | Type | Description | Required | Default | -| :----------- | :------ | :---------------------------------------------------------------------------------------------------------- | :------- | :---------- | -| min_duration | string | Optional: Only show transactions running at least this long (e.g., '1 minute', '15 minutes', '30 seconds'). | No | `5 minutes` | -| limit | integer | Optional: The maximum number of long-running transactions to return. Defaults to 20. | No | `20` | - ---- diff --git a/skills/cloud-sql-postgres-health/scripts/get_query_metrics.js b/skills/cloud-sql-postgres-health/scripts/get_query_metrics.js deleted file mode 100755 index 0fb6e93..0000000 --- a/skills/cloud-sql-postgres-health/scripts/get_query_metrics.js +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "get_query_metrics"; -const configArgs = ["--prebuilt", "cloud-sql-postgres"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -let userAgent = "skills"; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); - userAgent = "skills-geminicli"; -} - -const args = process.argv.slice(2); - -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, "--user-agent-metadata", userAgent, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-health/scripts/get_query_plan.js b/skills/cloud-sql-postgres-health/scripts/get_query_plan.js deleted file mode 100755 index 122f3d0..0000000 --- a/skills/cloud-sql-postgres-health/scripts/get_query_plan.js +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "get_query_plan"; -const configArgs = ["--prebuilt", "cloud-sql-postgres"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -let userAgent = "skills"; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); - userAgent = "skills-geminicli"; -} - -const args = process.argv.slice(2); - -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, "--user-agent-metadata", userAgent, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-health/scripts/get_system_metrics.js b/skills/cloud-sql-postgres-health/scripts/get_system_metrics.js deleted file mode 100755 index 8c759eb..0000000 --- a/skills/cloud-sql-postgres-health/scripts/get_system_metrics.js +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "get_system_metrics"; -const configArgs = ["--prebuilt", "cloud-sql-postgres"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -let userAgent = "skills"; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); - userAgent = "skills-geminicli"; -} - -const args = process.argv.slice(2); - -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, "--user-agent-metadata", userAgent, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-health/scripts/list_active_queries.js b/skills/cloud-sql-postgres-health/scripts/list_active_queries.js deleted file mode 100755 index ea548e1..0000000 --- a/skills/cloud-sql-postgres-health/scripts/list_active_queries.js +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "list_active_queries"; -const configArgs = ["--prebuilt", "cloud-sql-postgres"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -let userAgent = "skills"; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); - userAgent = "skills-geminicli"; -} - -const args = process.argv.slice(2); - -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, "--user-agent-metadata", userAgent, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-health/scripts/list_database_stats.js b/skills/cloud-sql-postgres-health/scripts/list_database_stats.js deleted file mode 100755 index 45f17de..0000000 --- a/skills/cloud-sql-postgres-health/scripts/list_database_stats.js +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "list_database_stats"; -const configArgs = ["--prebuilt", "cloud-sql-postgres"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -let userAgent = "skills"; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); - userAgent = "skills-geminicli"; -} - -const args = process.argv.slice(2); - -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, "--user-agent-metadata", userAgent, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-health/scripts/list_locks.js b/skills/cloud-sql-postgres-health/scripts/list_locks.js deleted file mode 100755 index 1a01686..0000000 --- a/skills/cloud-sql-postgres-health/scripts/list_locks.js +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "list_locks"; -const configArgs = ["--prebuilt", "cloud-sql-postgres"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -let userAgent = "skills"; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); - userAgent = "skills-geminicli"; -} - -const args = process.argv.slice(2); - -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, "--user-agent-metadata", userAgent, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-health/scripts/list_query_stats.js b/skills/cloud-sql-postgres-health/scripts/list_query_stats.js deleted file mode 100755 index 60184d6..0000000 --- a/skills/cloud-sql-postgres-health/scripts/list_query_stats.js +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "list_query_stats"; -const configArgs = ["--prebuilt", "cloud-sql-postgres"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -let userAgent = "skills"; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); - userAgent = "skills-geminicli"; -} - -const args = process.argv.slice(2); - -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, "--user-agent-metadata", userAgent, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-health/scripts/long_running_transactions.js b/skills/cloud-sql-postgres-health/scripts/long_running_transactions.js deleted file mode 100755 index a7d976e..0000000 --- a/skills/cloud-sql-postgres-health/scripts/long_running_transactions.js +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "long_running_transactions"; -const configArgs = ["--prebuilt", "cloud-sql-postgres"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -let userAgent = "skills"; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); - userAgent = "skills-geminicli"; -} - -const args = process.argv.slice(2); - -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, "--user-agent-metadata", userAgent, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-lifecycle/SKILL.md b/skills/cloud-sql-postgres-lifecycle/SKILL.md deleted file mode 100644 index a2e7221..0000000 --- a/skills/cloud-sql-postgres-lifecycle/SKILL.md +++ /dev/null @@ -1,106 +0,0 @@ ---- -name: cloud-sql-postgres-lifecycle -description: Use these skills when you need to manage the lifecycle of your instances, including performing backups and restores, checking major version upgrade compatibility, and monitoring overall instance status. ---- - -## Usage - -All scripts can be executed using Node.js. Replace `` and `` with actual values. - -**Bash:** -`node /scripts/.js '{"": ""}'` - -**PowerShell:** -`node /scripts/.js '{\"\": \"\"}'` - -Note: The scripts automatically load the environment variables from various .env files. Do not ask the user to set vars unless skill executions fails due to env var absence. - -## Scripts - -### create_backup - -Creates a backup on a Cloud SQL instance. - -#### Parameters - -| Name | Type | Description | Required | Default | -| :----------------- | :----- | :----------------------------------------------------------------------------------------------------------------- | :------- | :------ | -| project | string | The GCP project ID. This is pre-configured; do not ask for it unless the user explicitly provides a different one. | No | | -| instance | string | Cloud SQL instance ID. This does not include the project ID. | Yes | | -| location | string | Location of the backup run. | No | | -| backup_description | string | The description of this backup run. | No | | - ---- - -### database_overview - -Fetches the current state of the PostgreSQL server, returning the version, whether it's a replica, uptime duration, maximum connection limit, number of current connections, number of active connections, and the percentage of connections in use. - ---- - -### get_instance - -#### Parameters - -| Name | Type | Description | Required | Default | -| :--------- | :----- | :----------------------------------------------------------------------------------------------------------------- | :------- | :------ | -| projectId | string | The GCP project ID. This is pre-configured; do not ask for it unless the user explicitly provides a different one. | No | | -| instanceId | string | The instance ID | Yes | | - ---- - -### list_instances - -Lists all type of Cloud SQL instances for a project. - -#### Parameters - -| Name | Type | Description | Required | Default | -| :------ | :----- | :----------------------------------------------------------------------------------------------------------------- | :------- | :------ | -| project | string | The GCP project ID. This is pre-configured; do not ask for it unless the user explicitly provides a different one. | No | | - ---- - -### postgres_upgrade_precheck - -Analyzes a Cloud SQL PostgreSQL instance for major version upgrade readiness. Results are provided to guide customer actions: -ERROR: Action Required. These are critical issues blocking the upgrade. Customers must resolve these using the provided actions_required steps before attempting the upgrade. -WARNING: Review Recommended. These are potential issues. Customers should review the message and actions_required. While not blocking, addressing these is advised to prevent future problems or unexpected behavior post-upgrade. -INFO: No Action Needed. Informational messages only. This pre-check helps customers proactively fix problems, preventing upgrade failures and ensuring a smoother transition. - -#### Parameters - -| Name | Type | Description | Required | Default | -| :-------------------- | :----- | :------------------------------------------------------------------------------------------------------------------ | :------- | :------------ | -| project | string | The project ID | Yes | | -| instance | string | The name of the instance to check | Yes | | -| targetDatabaseVersion | string | The target PostgreSQL version for the upgrade (e.g., POSTGRES_18). If not specified, defaults to the PostgreSQL 18. | No | `POSTGRES_18` | - ---- - -### restore_backup - -Restores a backup on a Cloud SQL instance. - -#### Parameters - -| Name | Type | Description | Required | Default | -| :-------------- | :----- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------- | :------ | -| target_project | string | The GCP project ID. This is pre-configured; do not ask for it unless the user explicitly provides a different one. | No | | -| target_instance | string | Cloud SQL instance ID of the target instance. This does not include the project ID. | Yes | | -| backup_id | string | Identifier of the backup being restored. Can be a BackupRun ID, backup name, or BackupDR backup name. Use the full backup ID as provided, do not try to parse it | Yes | | -| source_project | string | GCP project ID of the instance that the backup belongs to. Only required if the backup_id is a BackupRun ID. | No | | -| source_instance | string | Cloud SQL instance ID of the instance that the backup belongs to. Only required if the backup_id is a BackupRun ID. | No | | - ---- - -### wait_for_operation - -#### Parameters - -| Name | Type | Description | Required | Default | -| :-------- | :----- | :----------------------------------------------------------------------------------------------------------------- | :------- | :------ | -| project | string | The GCP project ID. This is pre-configured; do not ask for it unless the user explicitly provides a different one. | No | | -| operation | string | The operation ID | Yes | | - ---- diff --git a/skills/cloud-sql-postgres-lifecycle/scripts/create_backup.js b/skills/cloud-sql-postgres-lifecycle/scripts/create_backup.js deleted file mode 100755 index 11eee7e..0000000 --- a/skills/cloud-sql-postgres-lifecycle/scripts/create_backup.js +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "create_backup"; -const configArgs = ["--prebuilt", "cloud-sql-postgres"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -let userAgent = "skills"; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); - userAgent = "skills-geminicli"; -} - -const args = process.argv.slice(2); - -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, "--user-agent-metadata", userAgent, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-lifecycle/scripts/database_overview.js b/skills/cloud-sql-postgres-lifecycle/scripts/database_overview.js deleted file mode 100755 index 960d20a..0000000 --- a/skills/cloud-sql-postgres-lifecycle/scripts/database_overview.js +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "database_overview"; -const configArgs = ["--prebuilt", "cloud-sql-postgres"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -let userAgent = "skills"; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); - userAgent = "skills-geminicli"; -} - -const args = process.argv.slice(2); - -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, "--user-agent-metadata", userAgent, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-lifecycle/scripts/get_instance.js b/skills/cloud-sql-postgres-lifecycle/scripts/get_instance.js deleted file mode 100755 index 216e7e8..0000000 --- a/skills/cloud-sql-postgres-lifecycle/scripts/get_instance.js +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "get_instance"; -const configArgs = ["--prebuilt", "cloud-sql-postgres"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -let userAgent = "skills"; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); - userAgent = "skills-geminicli"; -} - -const args = process.argv.slice(2); - -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, "--user-agent-metadata", userAgent, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-lifecycle/scripts/list_instances.js b/skills/cloud-sql-postgres-lifecycle/scripts/list_instances.js deleted file mode 100755 index b24402c..0000000 --- a/skills/cloud-sql-postgres-lifecycle/scripts/list_instances.js +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "list_instances"; -const configArgs = ["--prebuilt", "cloud-sql-postgres"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -let userAgent = "skills"; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); - userAgent = "skills-geminicli"; -} - -const args = process.argv.slice(2); - -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, "--user-agent-metadata", userAgent, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-lifecycle/scripts/postgres_upgrade_precheck.js b/skills/cloud-sql-postgres-lifecycle/scripts/postgres_upgrade_precheck.js deleted file mode 100755 index 7b42cfd..0000000 --- a/skills/cloud-sql-postgres-lifecycle/scripts/postgres_upgrade_precheck.js +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "postgres_upgrade_precheck"; -const configArgs = ["--prebuilt", "cloud-sql-postgres"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -let userAgent = "skills"; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); - userAgent = "skills-geminicli"; -} - -const args = process.argv.slice(2); - -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, "--user-agent-metadata", userAgent, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-lifecycle/scripts/restore_backup.js b/skills/cloud-sql-postgres-lifecycle/scripts/restore_backup.js deleted file mode 100755 index a6b2426..0000000 --- a/skills/cloud-sql-postgres-lifecycle/scripts/restore_backup.js +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "restore_backup"; -const configArgs = ["--prebuilt", "cloud-sql-postgres"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -let userAgent = "skills"; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); - userAgent = "skills-geminicli"; -} - -const args = process.argv.slice(2); - -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, "--user-agent-metadata", userAgent, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-lifecycle/scripts/wait_for_operation.js b/skills/cloud-sql-postgres-lifecycle/scripts/wait_for_operation.js deleted file mode 100755 index 3bd09d9..0000000 --- a/skills/cloud-sql-postgres-lifecycle/scripts/wait_for_operation.js +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "wait_for_operation"; -const configArgs = ["--prebuilt", "cloud-sql-postgres"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -let userAgent = "skills"; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); - userAgent = "skills-geminicli"; -} - -const args = process.argv.slice(2); - -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, "--user-agent-metadata", userAgent, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-monitor/SKILL.md b/skills/cloud-sql-postgres-monitor/SKILL.md deleted file mode 100644 index 1d8c4e6..0000000 --- a/skills/cloud-sql-postgres-monitor/SKILL.md +++ /dev/null @@ -1,203 +0,0 @@ ---- -name: cloud-sql-postgres-monitor -description: Use these skills when you need to troubleshoot performance bottlenecks, analyze query execution plans, identify resource-heavy processes, and monitor system-level PromQL metrics. ---- - -## Usage - -All scripts can be executed using Node.js. Replace `` and `` with actual values. - -**Bash:** -`node /scripts/.js '{"": ""}'` - -**PowerShell:** -`node /scripts/.js '{\"\": \"\"}'` - -Note: The scripts automatically load the environment variables from various .env files. Do not ask the user to set vars unless skill executions fails due to env var absence. - -## Scripts - -### get_query_metrics - -Fetches query level cloudmonitoring data (timeseries metrics) for queries running in Postgres instance using a PromQL query. Take projectID and instanceID from the user for which the metrics timeseries data needs to be fetched. -To use this tool, you must provide the Google Cloud `projectId` and a PromQL `query`. - -Generate PromQL `query` for Postgres query metrics. Use the provided metrics and rules to construct queries, Get the labels like `instance_id`, `query_hash` from user intent. If query_hash is provided then use the per_query metrics. Query hash and query id are same. - -Defaults: - -1. Interval: Use a default interval of `5m` for `_over_time` aggregation functions unless a different window is specified by the user. - -PromQL Query Examples: - -1. Basic Time Series: `avg_over_time({"__name__"="cloudsql.googleapis.com/database/postgresql/insights/aggregate/execution_time","monitored_resource"="cloudsql_instance_database","project_id"="my-projectId","resource_id"="my-projectId:my-instanceId"}[5m])` -2. Top K: `topk(30, avg_over_time({"__name__"="cloudsql.googleapis.com/database/postgresql/insights/aggregate/execution_time","monitored_resource"="cloudsql_instance_database","project_id"="my-projectId","resource_id"="my-projectId:my-instanceId"}[5m]))` -3. Mean: `avg(avg_over_time({"__name__"="cloudsql.googleapis.com/database/postgresql/insights/aggregate/execution_time","monitored_resource"="cloudsql_instance_database","project_id"="my-projectId","resource_id"="my-projectId:my-instanceId"}[5m]))` -4. Minimum: `min(min_over_time({"__name__"="cloudsql.googleapis.com/database/postgresql/insights/aggregate/execution_time","monitored_resource"="cloudsql_instance_database","project_id"="my-projectId","resource_id"="my-projectId:my-instanceId"}[5m]))` -5. Maximum: `max(max_over_time({"__name__"="cloudsql.googleapis.com/database/postgresql/insights/aggregate/execution_time","monitored_resource"="cloudsql_instance_database","project_id"="my-projectId","resource_id"="my-projectId:my-instanceId"}[5m]))` -6. Sum: `sum(avg_over_time({"__name__"="cloudsql.googleapis.com/database/postgresql/insights/aggregate/execution_time","monitored_resource"="cloudsql_instance_database","project_id"="my-projectId","resource_id"="my-projectId:my-instanceId"}[5m]))` -7. Count streams: `count(avg_over_time({"__name__"="cloudsql.googleapis.com/database/postgresql/insights/aggregate/execution_time","monitored_resource"="cloudsql_instance_database","project_id"="my-projectId","resource_id"="my-projectId:my-instanceId"}[5m]))` -8. Percentile with groupby on resource_id, database: `quantile by ("resource_id","database")(0.99,avg_over_time({"__name__"="cloudsql.googleapis.com/database/postgresql/insights/aggregate/execution_time","monitored_resource"="cloudsql_instance_database","project_id"="my-projectId","resource_id"="my-projectId:my-instanceId"}[5m]))` - -Available Metrics List: metricname. description. monitored resource. labels. resource_id label format is `project_id:instance_id` which is actually instance id only. aggregate is the aggregated values for all query stats, Use aggregate metrics if query id is not provided. For perquery metrics do not fetch querystring unless specified by user specifically. Have the aggregation on query hash to avoid fetching the querystring. Do not use latency metrics for anything. - -1. `cloudsql.googleapis.com/database/postgresql/insights/aggregate/latencies`: Aggregated query latency distribution. `cloudsql_instance_database`. `user`, `client_addr`, `project_id`, `resource_id`. -2. `cloudsql.googleapis.com/database/postgresql/insights/aggregate/execution_time`: Accumulated aggregated query execution time since the last sample. `cloudsql_instance_database`. `user`, `client_addr`, `project_id`, `resource_id`. -3. `cloudsql.googleapis.com/database/postgresql/insights/aggregate/io_time`: Accumulated aggregated IO time since the last sample. `cloudsql_instance_database`. `user`, `client_addr`, `io_type`, `project_id`, `resource_id`. -4. `cloudsql.googleapis.com/database/postgresql/insights/aggregate/lock_time`: Accumulated aggregated lock wait time since the last sample. `cloudsql_instance_database`. `user`, `client_addr`, `lock_type`, `project_id`, `resource_id`. -5. `cloudsql.googleapis.com/database/postgresql/insights/aggregate/row_count`: Aggregated number of retrieved or affected rows since the last sample. `cloudsql_instance_database`. `user`, `client_addr`, `project_id`, `resource_id`. -6. `cloudsql.googleapis.com/database/postgresql/insights/aggregate/shared_blk_access_count`: Aggregated shared blocks accessed by statement execution. `cloudsql_instance_database`. `user`, `client_addr`, `access_type`, `project_id`, `resource_id`. -7. `cloudsql.googleapis.com/database/postgresql/insights/perquery/latencies`: Per query latency distribution. `cloudsql_instance_database`. `user`, `client_addr`, `querystring`, `query_hash`, `project_id`, `resource_id`. -8. `cloudsql.googleapis.com/database/postgresql/insights/perquery/execution_time`: Accumulated execution times per user per database per query. `cloudsql_instance_database`. `user`, `client_addr`, `querystring`, `query_hash`, `project_id`, `resource_id`. -9. `cloudsql.googleapis.com/database/postgresql/insights/perquery/io_time`: Accumulated IO time since the last sample per query. `cloudsql_instance_database`. `user`, `client_addr`, `io_type`, `querystring`, `query_hash`, `project_id`, `resource_id`. -10. `cloudsql.googleapis.com/database/postgresql/insights/perquery/lock_time`: Accumulated lock wait time since the last sample per query. `cloudsql_instance_database`. `user`, `client_addr`, `lock_type`, `querystring`, `query_hash`, `project_id`, `resource_id`. -11. `cloudsql.googleapis.com/database/postgresql/insights/perquery/row_count`: The number of retrieved or affected rows since the last sample per query. `cloudsql_instance_database`. `user`, `client_addr`, `querystring`, `query_hash`, `project_id`, `resource_id`. -12. `cloudsql.googleapis.com/database/postgresql/insights/perquery/shared_blk_access_count`: Shared blocks accessed by statement execution per query. `cloudsql_instance_database`. `user`, `client_addr`, `access_type`, `querystring`, `query_hash`, `project_id`, `resource_id`. -13. `cloudsql.googleapis.com/database/postgresql/insights/pertag/latencies`: Query latency distribution. `cloudsql_instance_database`. `user`, `client_addr`, `action`, `application`, `controller`, `db_driver`, `framework`, `route`, `tag_hash`, `project_id`, `resource_id`. -14. `cloudsql.googleapis.com/database/postgresql/insights/pertag/execution_time`: Accumulated execution times since the last sample. `cloudsql_instance_database`. `user`, `client_addr`, `action`, `application`, `controller`, `db_driver`, `framework`, `route`, `tag_hash`, `project_id`, `resource_id`. -15. `cloudsql.googleapis.com/database/postgresql/insights/pertag/io_time`: Accumulated IO time since the last sample per tag. `cloudsql_instance_database`. `user`, `client_addr`, `action`, `application`, `controller`, `db_driver`, `framework`, `route`, `io_type`, `tag_hash`, `project_id`, `resource_id`. -16. `cloudsql.googleapis.com/database/postgresql/insights/pertag/lock_time`: Accumulated lock wait time since the last sample per tag. `cloudsql_instance_database`. `user`, `client_addr`, `action`, `application`, `controller`, `db_driver`, `framework`, `route`, `lock_type`, `tag_hash`, `project_id`, `resource_id`. -17. `cloudsql.googleapis.com/database/postgresql/insights/pertag/shared_blk_access_count`: Shared blocks accessed by statement execution per tag. `cloudsql_instance_database`. `user`, `client_addr`, `action`, `application`, `controller`, `db_driver`, `framework`, `route`, `access_type`, `tag_hash`, `project_id`, `resource_id`. -18. `cloudsql.googleapis.com/database/postgresql/insights/pertag/row_count`: The number of retrieved or affected rows since the last sample per tag. `cloudsql_instance_database`. `user`, `client_addr`, `action`, `application`, `controller`, `db_driver`, `framework`, `route`, `tag_hash`, `project_id`, `resource_id`. - -#### Parameters - -| Name | Type | Description | Required | Default | -| :-------- | :----- | :---------------------------------- | :------- | :------ | -| projectId | string | The Id of the Google Cloud project. | Yes | | -| query | string | The promql query to execute. | Yes | | - ---- - -### get_query_plan - -Generate a PostgreSQL EXPLAIN plan in JSON format for a single SQL statement—without executing it. This returns the optimizer's estimated plan, costs, and rows (no ANALYZE, no extra options). Use in production safely for plan inspection, regression checks, and query tuning workflows. - -#### Parameters - -| Name | Type | Description | Required | Default | -| :---- | :----- | :-------------------------------------------------------------------------------- | :------- | :------ | -| query | string | The SQL statement for which you want to generate plan (omit the EXPLAIN keyword). | Yes | | - ---- - -### get_system_metrics - -Fetches system level cloudmonitoring data (timeseries metrics) for a Postgres instance using a PromQL query. Take projectId and instanceId from the user for which the metrics timeseries data needs to be fetched. -To use this tool, you must provide the Google Cloud `projectId` and a PromQL `query`. - -Generate PromQL `query` for Postgres system metrics. Use the provided metrics and rules to construct queries, Get the labels like `instance_id` from user intent. - -Defaults: - -1. Interval: Use a default interval of `5m` for `_over_time` aggregation functions unless a different window is specified by the user. - -PromQL Query Examples: - -1. Basic Time Series: `avg_over_time({"__name__"="cloudsql.googleapis.com/database/cpu/utilization","monitored_resource"="cloudsql_database","project_id"="my-projectId","database_id"="my-projectId:my-instanceId"}[5m])` -2. Top K: `topk(30, avg_over_time({"__name__"="cloudsql.googleapis.com/database/cpu/utilization","monitored_resource"="cloudsql_database","project_id"="my-projectId","database_id"="my-projectId:my-instanceId"}[5m]))` -3. Mean: `avg(avg_over_time({"__name__"="cloudsql.googleapis.com/database/cpu/utilization","monitored_resource"="cloudsql_database","project_id"="my-projectId","database_id"="my-projectId:my-instanceId"}[5m]))` -4. Minimum: `min(min_over_time({"__name__"="cloudsql.googleapis.com/database/cpu/utilization","monitored_resource"="cloudsql_database","project_id"="my-projectId","database_id"="my-projectId:my-instanceId"}[5m]))` -5. Maximum: `max(max_over_time({"__name__"="cloudsql.googleapis.com/database/cpu/utilization","monitored_resource"="cloudsql_database","project_id"="my-projectId","database_id"="my-projectId:my-instanceId"}[5m]))` -6. Sum: `sum(avg_over_time({"__name__"="cloudsql.googleapis.com/database/cpu/utilization","monitored_resource"="cloudsql_database","project_id"="my-projectId","database_id"="my-projectId:my-instanceId"}[5m]))` -7. Count streams: `count(avg_over_time({"__name__"="cloudsql.googleapis.com/database/cpu/utilization","monitored_resource"="cloudsql_database","project_id"="my-projectId","database_id"="my-projectId:my-instanceId"}[5m]))` -8. Percentile with groupby on database_id: `quantile by ("database_id")(0.99,avg_over_time({"__name__"="cloudsql.googleapis.com/database/cpu/utilization","monitored_resource"="cloudsql_database","project_id"="my-projectId","database_id"="my-projectId:my-instanceId"}[5m]))` - -Available Metrics List: metricname. description. monitored resource. labels. database_id is actually the instance id and the format is `project_id:instance_id`. - -1. `cloudsql.googleapis.com/database/postgresql/new_connection_count`: Count of new connections added to the postgres instance. `cloudsql_database`. `database`, `project_id`, `database_id`. -2. `cloudsql.googleapis.com/database/postgresql/backends_in_wait`: Number of backends in wait in postgres instance. `cloudsql_database`. `backend_type`, `wait_event`, `wait_event_type`, `project_id`, `database_id`. -3. `cloudsql.googleapis.com/database/postgresql/transaction_count`: Delta count of number of transactions. `cloudsql_database`. `database`, `transaction_type`, `project_id`, `database_id`. -4. `cloudsql.googleapis.com/database/memory/components`: Memory stats components in percentage as usage, cache and free memory for the database. `cloudsql_database`. `component`, `project_id`, `database_id`. -5. `cloudsql.googleapis.com/database/postgresql/external_sync/max_replica_byte_lag`: Replication lag in bytes for Postgres External Server (ES) replicas. Aggregated across all DBs on the replica. `cloudsql_database`. `project_id`, `database_id`. -6. `cloudsql.googleapis.com/database/cpu/utilization`: Current CPU utilization represented as a percentage of the reserved CPU that is currently in use. Values are typically numbers between 0.0 and 1.0 (but might exceed 1.0). Charts display the values as a percentage between 0% and 100% (or more). `cloudsql_database`. `project_id`, `database_id`. -7. `cloudsql.googleapis.com/database/disk/bytes_used_by_data_type`: Data utilization in bytes. `cloudsql_database`. `data_type`, `project_id`, `database_id`. -8. `cloudsql.googleapis.com/database/disk/read_ops_count`: Delta count of data disk read IO operations. `cloudsql_database`. `project_id`, `database_id`. -9. `cloudsql.googleapis.com/database/disk/write_ops_count`: Delta count of data disk write IO operations. `cloudsql_database`. `project_id`, `database_id`. -10. `cloudsql.googleapis.com/database/postgresql/num_backends_by_state`: Number of connections to the Cloud SQL PostgreSQL instance, grouped by its state. `cloudsql_database`. `database`, `state`, `project_id`, `database_id`. -11. `cloudsql.googleapis.com/database/postgresql/num_backends`: Number of connections to the Cloud SQL PostgreSQL instance. `cloudsql_database`. `database`, `project_id`, `database_id`. -12. `cloudsql.googleapis.com/database/network/received_bytes_count`: Delta count of bytes received through the network. `cloudsql_database`. `project_id`, `database_id`. -13. `cloudsql.googleapis.com/database/network/sent_bytes_count`: Delta count of bytes sent through the network. `cloudsql_database`. `destination`, `project_id`, `database_id`. -14. `cloudsql.googleapis.com/database/postgresql/deadlock_count`: Number of deadlocks detected for this database. `cloudsql_database`. `database`, `project_id`, `database_id`. -15. `cloudsql.googleapis.com/database/postgresql/blocks_read_count`: Number of disk blocks read by this database. The source field distingushes actual reads from disk versus reads from buffer cache. `cloudsql_database`. `database`, `source`, `project_id`, `database_id`. -16. `cloudsql.googleapis.com/database/postgresql/tuples_processed_count`: Number of tuples(rows) processed for a given database for operations like insert, update or delete. `cloudsql_database`. `operation_type`, `database`, `project_id`, `database_id`. -17. `cloudsql.googleapis.com/database/postgresql/tuple_size`: Number of tuples (rows) in the database. `cloudsql_database`. `database`, `tuple_state`, `project_id`, `database_id`. -18. `cloudsql.googleapis.com/database/postgresql/vacuum/oldest_transaction_age`: Age of the oldest transaction yet to be vacuumed in the Cloud SQL PostgreSQL instance, measured in number of transactions that have happened since the oldest transaction. `cloudsql_database`. `oldest_transaction_type`, `project_id`, `database_id`. -19. `cloudsql.googleapis.com/database/replication/log_archive_success_count`: Number of successful attempts for archiving replication log files. `cloudsql_database`. `project_id`, `database_id`. -20. `cloudsql.googleapis.com/database/replication/log_archive_failure_count`: Number of failed attempts for archiving replication log files. `cloudsql_database`. `project_id`, `database_id`. -21. `cloudsql.googleapis.com/database/postgresql/transaction_id_utilization`: Current utilization represented as a percentage of transaction IDs consumed by the Cloud SQL PostgreSQL instance. Values are typically numbers between 0.0 and 1.0. Charts display the values as a percentage between 0% and 100% . `cloudsql_database`. `project_id`, `database_id`. -22. `cloudsql.googleapis.com/database/postgresql/num_backends_by_application`: Number of connections to the Cloud SQL PostgreSQL instance, grouped by applications. `cloudsql_database`. `application`, `project_id`, `database_id`. -23. `cloudsql.googleapis.com/database/postgresql/tuples_fetched_count`: Total number of rows fetched as a result of queries per database in the PostgreSQL instance. `cloudsql_database`. `database`, `project_id`, `database_id`. -24. `cloudsql.googleapis.com/database/postgresql/tuples_returned_count`: Total number of rows scanned while processing the queries per database in the PostgreSQL instance. `cloudsql_database`. `database`, `project_id`, `database_id`. -25. `cloudsql.googleapis.com/database/postgresql/temp_bytes_written_count`: Total amount of data (in bytes) written to temporary files by the queries per database. `cloudsql_database`. `database`, `project_id`, `database_id`. -26. `cloudsql.googleapis.com/database/postgresql/temp_files_written_count`: Total number of temporary files used for writing data while performing algorithms such as join and sort. `cloudsql_database`. `database`, `project_id`, `database_id`. - -#### Parameters - -| Name | Type | Description | Required | Default | -| :-------- | :----- | :---------------------------------- | :------- | :------ | -| projectId | string | The Id of the Google Cloud project. | Yes | | -| query | string | The promql query to execute. | Yes | | - ---- - -### list_active_queries - -List the top N (default 50) currently running queries (state='active') from pg_stat_activity, ordered by longest-running first. Returns pid, user, database, application_name, client_addr, state, wait_event_type/wait_event, backend/xact/query start times, computed query_duration, and the SQL text. - -#### Parameters - -| Name | Type | Description | Required | Default | -| :------------------------ | :------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------- | :--------- | -| min_duration | string | Optional: Only show queries running at least this long (e.g., '1 minute', '1 second', '2 seconds'). | No | `1 minute` | -| exclude_application_names | string | Optional: A comma-separated list of application names to exclude from the query results. This is useful for filtering out queries from specific applications (e.g., 'psql', 'pgAdmin', 'DBeaver'). The match is case-sensitive. Whitespace around commas and names is automatically handled. If this parameter is omitted, no applications are excluded. | No | `` | -| limit | integer | Optional: The maximum number of rows to return. | No | `50` | - ---- - -### list_database_stats - -#### Parameters - -| Name | Type | Description | Required | Default | -| :----------------- | :------ | :--------------------------------------------------------------------------------- | :------- | :------ | -| database_name | string | Optional: A specific database name pattern to search for. | No | `` | -| include_templates | boolean | Optional: Whether to include template databases in the results. | No | `false` | -| database_owner | string | Optional: A specific database owner name pattern to search for. | No | `` | -| default_tablespace | string | Optional: A specific default tablespace name pattern to search for. | No | `` | -| order_by | string | Optional: The field to order the results by. Valid values are 'size' and 'commit'. | No | `` | -| limit | integer | Optional: The maximum number of rows to return. | No | `10` | - ---- - -### list_locks - -Identifies all locks held by active processes showing the process ID, user, query text, and an aggregated list of all transactions and specific locks (relation, mode, grant status) associated with each process. - ---- - -### list_query_stats - -Lists performance statistics for executed queries ordered by total time, filtering by database name pattern if provided. This skill requires the pg_stat_statements extension to be installed. The skill returns the database name, query text, execution count, timing metrics (total, min, max, mean), rows affected, and buffer cache I/O statistics (hits and reads). - -#### Parameters - -| Name | Type | Description | Required | Default | -| :------------ | :------ | :----------------------------------------------------------------- | :------- | :------ | -| database_name | string | Optional: The database name to list query stats for. | No | `` | -| limit | integer | Optional: The maximum number of results to return. Defaults to 50. | No | `50` | - ---- - -### long_running_transactions - -Identifies and lists database transactions that exceed a specified time limit. For each of the long running transactions, the output contains the process id, database name, user name, application name, client address, state, connection age, transaction age, query age, last activity age, wait event type, wait event, and query string. - -#### Parameters - -| Name | Type | Description | Required | Default | -| :----------- | :------ | :---------------------------------------------------------------------------------------------------------- | :------- | :---------- | -| min_duration | string | Optional: Only show transactions running at least this long (e.g., '1 minute', '15 minutes', '30 seconds'). | No | `5 minutes` | -| limit | integer | Optional: The maximum number of long-running transactions to return. Defaults to 20. | No | `20` | - ---- diff --git a/skills/cloud-sql-postgres-monitor/scripts/get_query_metrics.js b/skills/cloud-sql-postgres-monitor/scripts/get_query_metrics.js deleted file mode 100755 index 0fb6e93..0000000 --- a/skills/cloud-sql-postgres-monitor/scripts/get_query_metrics.js +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "get_query_metrics"; -const configArgs = ["--prebuilt", "cloud-sql-postgres"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -let userAgent = "skills"; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); - userAgent = "skills-geminicli"; -} - -const args = process.argv.slice(2); - -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, "--user-agent-metadata", userAgent, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-monitor/scripts/get_query_plan.js b/skills/cloud-sql-postgres-monitor/scripts/get_query_plan.js deleted file mode 100755 index 122f3d0..0000000 --- a/skills/cloud-sql-postgres-monitor/scripts/get_query_plan.js +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "get_query_plan"; -const configArgs = ["--prebuilt", "cloud-sql-postgres"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -let userAgent = "skills"; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); - userAgent = "skills-geminicli"; -} - -const args = process.argv.slice(2); - -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, "--user-agent-metadata", userAgent, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-monitor/scripts/get_system_metrics.js b/skills/cloud-sql-postgres-monitor/scripts/get_system_metrics.js deleted file mode 100755 index 8c759eb..0000000 --- a/skills/cloud-sql-postgres-monitor/scripts/get_system_metrics.js +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "get_system_metrics"; -const configArgs = ["--prebuilt", "cloud-sql-postgres"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -let userAgent = "skills"; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); - userAgent = "skills-geminicli"; -} - -const args = process.argv.slice(2); - -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, "--user-agent-metadata", userAgent, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-monitor/scripts/list_active_queries.js b/skills/cloud-sql-postgres-monitor/scripts/list_active_queries.js deleted file mode 100755 index ea548e1..0000000 --- a/skills/cloud-sql-postgres-monitor/scripts/list_active_queries.js +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "list_active_queries"; -const configArgs = ["--prebuilt", "cloud-sql-postgres"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -let userAgent = "skills"; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); - userAgent = "skills-geminicli"; -} - -const args = process.argv.slice(2); - -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, "--user-agent-metadata", userAgent, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-monitor/scripts/list_database_stats.js b/skills/cloud-sql-postgres-monitor/scripts/list_database_stats.js deleted file mode 100755 index 45f17de..0000000 --- a/skills/cloud-sql-postgres-monitor/scripts/list_database_stats.js +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "list_database_stats"; -const configArgs = ["--prebuilt", "cloud-sql-postgres"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -let userAgent = "skills"; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); - userAgent = "skills-geminicli"; -} - -const args = process.argv.slice(2); - -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, "--user-agent-metadata", userAgent, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-monitor/scripts/list_locks.js b/skills/cloud-sql-postgres-monitor/scripts/list_locks.js deleted file mode 100755 index 1a01686..0000000 --- a/skills/cloud-sql-postgres-monitor/scripts/list_locks.js +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "list_locks"; -const configArgs = ["--prebuilt", "cloud-sql-postgres"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -let userAgent = "skills"; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); - userAgent = "skills-geminicli"; -} - -const args = process.argv.slice(2); - -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, "--user-agent-metadata", userAgent, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-monitor/scripts/list_query_stats.js b/skills/cloud-sql-postgres-monitor/scripts/list_query_stats.js deleted file mode 100755 index 60184d6..0000000 --- a/skills/cloud-sql-postgres-monitor/scripts/list_query_stats.js +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "list_query_stats"; -const configArgs = ["--prebuilt", "cloud-sql-postgres"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -let userAgent = "skills"; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); - userAgent = "skills-geminicli"; -} - -const args = process.argv.slice(2); - -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, "--user-agent-metadata", userAgent, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-monitor/scripts/long_running_transactions.js b/skills/cloud-sql-postgres-monitor/scripts/long_running_transactions.js deleted file mode 100755 index a7d976e..0000000 --- a/skills/cloud-sql-postgres-monitor/scripts/long_running_transactions.js +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "long_running_transactions"; -const configArgs = ["--prebuilt", "cloud-sql-postgres"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -let userAgent = "skills"; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); - userAgent = "skills-geminicli"; -} - -const args = process.argv.slice(2); - -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, "--user-agent-metadata", userAgent, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-replication/SKILL.md b/skills/cloud-sql-postgres-replication/SKILL.md deleted file mode 100644 index 9ee14e1..0000000 --- a/skills/cloud-sql-postgres-replication/SKILL.md +++ /dev/null @@ -1,73 +0,0 @@ ---- -name: cloud-sql-postgres-replication -description: Use these skills when you need to monitor replication health, manage sync states between nodes, and audit database roles and security settings to ensure environment integrity. ---- - -## Usage - -All scripts can be executed using Node.js. Replace `` and `` with actual values. - -**Bash:** -`node /scripts/.js '{"": ""}'` - -**PowerShell:** -`node /scripts/.js '{\"\": \"\"}'` - -Note: The scripts automatically load the environment variables from various .env files. Do not ask the user to set vars unless skill executions fails due to env var absence. - -## Scripts - -### database_overview - -Fetches the current state of the PostgreSQL server, returning the version, whether it's a replica, uptime duration, maximum connection limit, number of current connections, number of active connections, and the percentage of connections in use. - ---- - -### list_pg_settings - -#### Parameters - -| Name | Type | Description | Required | Default | -| :----------- | :------ | :----------------------------------------------------------------------- | :------- | :------ | -| setting_name | string | Optional: A specific configuration parameter name pattern to search for. | No | `` | -| limit | integer | Optional: The maximum number of rows to return. | No | `50` | - ---- - -### list_publication_tables - -#### Parameters - -| Name | Type | Description | Required | Default | -| :---------------- | :------ | :---------------------------------------------------------------- | :------- | :------ | -| table_names | string | Optional: Filters by a comma-separated list of table names. | No | `` | -| publication_names | string | Optional: Filters by a comma-separated list of publication names. | No | `` | -| schema_names | string | Optional: Filters by a comma-separated list of schema names. | No | `` | -| limit | integer | Optional: The maximum number of rows to return. | No | `50` | - ---- - -### list_replication_slots - -List key details for all PostgreSQL replication slots (e.g., type, database, active status) and calculates the size of the outstanding WAL that is being prevented from removal by the slot. - ---- - -### list_roles - -Lists all the user-created roles in the instance . It returns the role name, Object ID, the maximum number of concurrent connections the role can make, along with boolean indicators for: superuser status, privilege inheritance from member roles, ability to create roles, ability to create databases, ability to log in, replication privilege, and the ability to bypass row-level security, the password expiration timestamp, a list of direct members belonging to this role, and a list of other roles/groups that this role is a member of. - -#### Parameters - -| Name | Type | Description | Required | Default | -| :-------- | :------ | :--------------------------------------------------------------------------------------- | :------- | :------ | -| role_name | string | Optional: a text to filter results by role name. The input is used within a LIKE clause. | No | `` | -| limit | integer | Optional: The maximum number of rows to return. Default is 10 | No | `50` | - ---- - -### replication_stats - -Lists each replica's process ID, user name, application name, backend_xmin (standby's xmin horizon reported by hot_standby_feedback), client IP address, connection state, and sync_state, along with lag sizes in bytes for sent_lag (primary to sent), write_lag (sent to written), flush_lag (written to flushed), replay_lag (flushed to replayed), and the overall total_lag (primary to replayed). - ---- diff --git a/skills/cloud-sql-postgres-replication/scripts/database_overview.js b/skills/cloud-sql-postgres-replication/scripts/database_overview.js deleted file mode 100755 index 960d20a..0000000 --- a/skills/cloud-sql-postgres-replication/scripts/database_overview.js +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "database_overview"; -const configArgs = ["--prebuilt", "cloud-sql-postgres"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -let userAgent = "skills"; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); - userAgent = "skills-geminicli"; -} - -const args = process.argv.slice(2); - -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, "--user-agent-metadata", userAgent, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-replication/scripts/list_pg_settings.js b/skills/cloud-sql-postgres-replication/scripts/list_pg_settings.js deleted file mode 100755 index 0aa7bc5..0000000 --- a/skills/cloud-sql-postgres-replication/scripts/list_pg_settings.js +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "list_pg_settings"; -const configArgs = ["--prebuilt", "cloud-sql-postgres"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -let userAgent = "skills"; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); - userAgent = "skills-geminicli"; -} - -const args = process.argv.slice(2); - -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, "--user-agent-metadata", userAgent, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-replication/scripts/list_publication_tables.js b/skills/cloud-sql-postgres-replication/scripts/list_publication_tables.js deleted file mode 100755 index 621844f..0000000 --- a/skills/cloud-sql-postgres-replication/scripts/list_publication_tables.js +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "list_publication_tables"; -const configArgs = ["--prebuilt", "cloud-sql-postgres"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -let userAgent = "skills"; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); - userAgent = "skills-geminicli"; -} - -const args = process.argv.slice(2); - -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, "--user-agent-metadata", userAgent, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-replication/scripts/list_replication_slots.js b/skills/cloud-sql-postgres-replication/scripts/list_replication_slots.js deleted file mode 100755 index 2be0c12..0000000 --- a/skills/cloud-sql-postgres-replication/scripts/list_replication_slots.js +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "list_replication_slots"; -const configArgs = ["--prebuilt", "cloud-sql-postgres"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -let userAgent = "skills"; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); - userAgent = "skills-geminicli"; -} - -const args = process.argv.slice(2); - -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, "--user-agent-metadata", userAgent, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-replication/scripts/list_roles.js b/skills/cloud-sql-postgres-replication/scripts/list_roles.js deleted file mode 100755 index 5c9c0d9..0000000 --- a/skills/cloud-sql-postgres-replication/scripts/list_roles.js +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "list_roles"; -const configArgs = ["--prebuilt", "cloud-sql-postgres"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -let userAgent = "skills"; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); - userAgent = "skills-geminicli"; -} - -const args = process.argv.slice(2); - -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, "--user-agent-metadata", userAgent, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-replication/scripts/replication_stats.js b/skills/cloud-sql-postgres-replication/scripts/replication_stats.js deleted file mode 100755 index c8318f8..0000000 --- a/skills/cloud-sql-postgres-replication/scripts/replication_stats.js +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "replication_stats"; -const configArgs = ["--prebuilt", "cloud-sql-postgres"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -let userAgent = "skills"; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); - userAgent = "skills-geminicli"; -} - -const args = process.argv.slice(2); - -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, "--user-agent-metadata", userAgent, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-view-config/SKILL.md b/skills/cloud-sql-postgres-view-config/SKILL.md deleted file mode 100644 index 36f6528..0000000 --- a/skills/cloud-sql-postgres-view-config/SKILL.md +++ /dev/null @@ -1,64 +0,0 @@ ---- -name: cloud-sql-postgres-view-config -description: Use these skills when you need to discover and manage PostgreSQL extensions or fine-tune engine-level settings such as memory allocation and server configuration parameters. ---- - -## Usage - -All scripts can be executed using Node.js. Replace `` and `` with actual values. - -**Bash:** -`node /scripts/.js '{"": ""}'` - -**PowerShell:** -`node /scripts/.js '{\"\": \"\"}'` - -Note: The scripts automatically load the environment variables from various .env files. Do not ask the user to set vars unless skill executions fails due to env var absence. - -## Scripts - -### database_overview - -Fetches the current state of the PostgreSQL server, returning the version, whether it's a replica, uptime duration, maximum connection limit, number of current connections, number of active connections, and the percentage of connections in use. - ---- - -### get_instance - -#### Parameters - -| Name | Type | Description | Required | Default | -| :--------- | :----- | :----------------------------------------------------------------------------------------------------------------- | :------- | :------ | -| projectId | string | The GCP project ID. This is pre-configured; do not ask for it unless the user explicitly provides a different one. | No | | -| instanceId | string | The instance ID | Yes | | - ---- - -### list_available_extensions - -Discover all PostgreSQL extensions available for installation on this server, returning name, default_version, and description. - ---- - -### list_installed_extensions - -List all installed PostgreSQL extensions with their name, version, schema, owner, and description. - ---- - -### list_memory_configurations - -List PostgreSQL memory-related configurations (name and current setting) from pg_settings. - ---- - -### list_pg_settings - -#### Parameters - -| Name | Type | Description | Required | Default | -| :----------- | :------ | :----------------------------------------------------------------------- | :------- | :------ | -| setting_name | string | Optional: A specific configuration parameter name pattern to search for. | No | `` | -| limit | integer | Optional: The maximum number of rows to return. | No | `50` | - ---- diff --git a/skills/cloud-sql-postgres-view-config/scripts/database_overview.js b/skills/cloud-sql-postgres-view-config/scripts/database_overview.js deleted file mode 100755 index 960d20a..0000000 --- a/skills/cloud-sql-postgres-view-config/scripts/database_overview.js +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "database_overview"; -const configArgs = ["--prebuilt", "cloud-sql-postgres"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -let userAgent = "skills"; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); - userAgent = "skills-geminicli"; -} - -const args = process.argv.slice(2); - -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, "--user-agent-metadata", userAgent, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-view-config/scripts/get_instance.js b/skills/cloud-sql-postgres-view-config/scripts/get_instance.js deleted file mode 100755 index 216e7e8..0000000 --- a/skills/cloud-sql-postgres-view-config/scripts/get_instance.js +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "get_instance"; -const configArgs = ["--prebuilt", "cloud-sql-postgres"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -let userAgent = "skills"; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); - userAgent = "skills-geminicli"; -} - -const args = process.argv.slice(2); - -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, "--user-agent-metadata", userAgent, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-view-config/scripts/list_available_extensions.js b/skills/cloud-sql-postgres-view-config/scripts/list_available_extensions.js deleted file mode 100755 index fad9ca5..0000000 --- a/skills/cloud-sql-postgres-view-config/scripts/list_available_extensions.js +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "list_available_extensions"; -const configArgs = ["--prebuilt", "cloud-sql-postgres"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -let userAgent = "skills"; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); - userAgent = "skills-geminicli"; -} - -const args = process.argv.slice(2); - -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, "--user-agent-metadata", userAgent, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-view-config/scripts/list_installed_extensions.js b/skills/cloud-sql-postgres-view-config/scripts/list_installed_extensions.js deleted file mode 100755 index 5ef1047..0000000 --- a/skills/cloud-sql-postgres-view-config/scripts/list_installed_extensions.js +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "list_installed_extensions"; -const configArgs = ["--prebuilt", "cloud-sql-postgres"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -let userAgent = "skills"; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); - userAgent = "skills-geminicli"; -} - -const args = process.argv.slice(2); - -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, "--user-agent-metadata", userAgent, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-view-config/scripts/list_memory_configurations.js b/skills/cloud-sql-postgres-view-config/scripts/list_memory_configurations.js deleted file mode 100755 index 9e5f7c1..0000000 --- a/skills/cloud-sql-postgres-view-config/scripts/list_memory_configurations.js +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "list_memory_configurations"; -const configArgs = ["--prebuilt", "cloud-sql-postgres"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -let userAgent = "skills"; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); - userAgent = "skills-geminicli"; -} - -const args = process.argv.slice(2); - -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, "--user-agent-metadata", userAgent, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -}); diff --git a/skills/cloud-sql-postgres-view-config/scripts/list_pg_settings.js b/skills/cloud-sql-postgres-view-config/scripts/list_pg_settings.js deleted file mode 100755 index 0aa7bc5..0000000 --- a/skills/cloud-sql-postgres-view-config/scripts/list_pg_settings.js +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env node - -// Copyright 2026 Google LLC -// -// Licensed 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. - -const { spawn, execSync } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -const toolName = "list_pg_settings"; -const configArgs = ["--prebuilt", "cloud-sql-postgres"]; - -function getToolboxPath() { - if (process.env.GEMINI_CLI === '1') { - const localPath = path.resolve(__dirname, '../../../toolbox'); - if (fs.existsSync(localPath)) { - return localPath; - } - } - try { - const checkCommand = process.platform === 'win32' ? 'where toolbox' : 'which toolbox'; - const globalPath = execSync(checkCommand, { stdio: 'pipe', encoding: 'utf-8' }).trim(); - if (globalPath) { - return globalPath.split('\n')[0].trim(); - } - throw new Error("Toolbox binary not found"); - } catch (e) { - throw new Error("Toolbox binary not found"); - } -} - -let toolboxBinary; -try { - toolboxBinary = getToolboxPath(); -} catch (err) { - console.error("Error:", err.message); - process.exit(1); -} - -function getEnv() { - const envPath = path.resolve(__dirname, '../../../.env'); - const env = { ...process.env }; - if (fs.existsSync(envPath)) { - const envContent = fs.readFileSync(envPath, 'utf-8'); - envContent.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && !trimmed.startsWith('#')) { - const splitIdx = trimmed.indexOf('='); - if (splitIdx !== -1) { - const key = trimmed.slice(0, splitIdx).trim(); - let value = trimmed.slice(splitIdx + 1).trim(); - value = value.replace(/(^['"]|['"]$)/g, ''); - if (env[key] === undefined) { - env[key] = value; - } - } - } - }); - } - return env; -} - -let env = process.env; -let userAgent = "skills"; -if (process.env.GEMINI_CLI === '1') { - env = getEnv(); - userAgent = "skills-geminicli"; -} - -const args = process.argv.slice(2); - -const toolboxArgs = ["--log-level", "error", ...configArgs, "invoke", toolName, "--user-agent-metadata", userAgent, ...args]; - -const child = spawn(toolboxBinary, toolboxArgs, { stdio: 'inherit', env }); - -child.on('close', (code) => { - process.exit(code); -}); - -child.on('error', (err) => { - console.error("Error executing toolbox:", err); - process.exit(1); -});