npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

gtools-cli

v1.0.0

Published

CLI for interacting with Google services, built with Bun

Readme

gtools-cli

A command-line tool for interacting with Google services. Currently supports:

  • Google Tag Manager (GTM) — containers, tags, triggers, variables, and custom templates
  • Google Docs — read document content as plain text
  • Google Sheets — read spreadsheet values across all tabs

Built with Bun and the Google APIs.

Requirements

  • Bun v1.0+
  • A Google OAuth 2.0 client (Desktop app type)
  • Access to the Google services you want to query (GTM, Docs, Sheets)

Setup

1. Install

bun add -g gtools-cli

npm install -g gtools-cli also works, but the CLI still requires Bun at runtime to execute.

git clone https://github.com/Dylan0916/gtools-cli.git
cd gtools-cli
bun install
bun link   # registers `gtools-cli` as a global command

2. Set up Google OAuth credentials

Create a Google OAuth 2.0 client (Desktop app) in Google Cloud Console, then add to ~/.zshrc:

export GOOGLE_CLIENT_ID="your-client-id"
export GOOGLE_CLIENT_SECRET="your-client-secret"
source ~/.zshrc

Required OAuth scopes (requested automatically on login):

  • tagmanager.edit.containers — edit GTM containers (but not publish)
  • documents.readonly — read Google Docs (upgraded to documents with --write)
  • spreadsheets.readonly — read Google Sheets (upgraded to spreadsheets with --write)

3. Log in

gtools-cli login

This opens a browser for Google OAuth consent. Tokens are stored at ~/.config/gtools-cli/token.json.

To request read+write scopes (currently used by future Docs/Sheets write commands), add --write:

gtools-cli login --write

This upgrades the Docs and Sheets scopes from *.readonly to their full counterparts. Re-run this whenever you want to change the granted scopes — the consent screen will appear again.

Usage

gtools-cli <service> <command> [flags]

All output is JSON. Top-level commands (login) don't require a service prefix.

GTM Commands

--account takes the numeric accountId and --container takes the numeric containerId (not the GTM-XXXXXX public ID). Run gtm list-accountsgtm list-containers first to get these IDs.

| Command | Flags | Description | |---------|-------|-------------| | gtm list-accounts | — | List all GTM accounts | | gtm list-containers | --account <id> | List containers in an account | | gtm list-tags | --account <id> --container <id> | List tags in a container | | gtm list-triggers | --account <id> --container <id> | List triggers in a container | | gtm list-variables | --account <id> --container <id> | List variables in a container | | gtm list-templates | --account <id> --container <id> | List custom templates in a container | | gtm get-tag | --account <id> --container <id> --id <tagId> | Full tag details | | gtm get-trigger | --account <id> --container <id> --id <triggerId> | Full trigger details | | gtm get-variable | --account <id> --container <id> --id <variableId> | Full variable details | | gtm get-template | --account <id> --container <id> --id <templateId> | Full template details including source code | | gtm search | --account <id> --container <id> --query <keyword> | Search tags, triggers, and variables by keyword | | gtm update-tag-html | --account <id> --container <id> --id <tagId> --html-file <path> [--workspace <id>] | Update an HTML tag's html parameter from a file | | gtm list-versions | --account <id> --container <id> | List all container versions (published + drafts) | | gtm get-version | --account <id> --container <id> --id <versionId> | Full snapshot of a version (tags/triggers/variables/templates/builtInVariables) | | gtm get-live-version | --account <id> --container <id> | Full snapshot of the currently published version | | gtm diff-versions | --account <id> --container <id> --from-version <id> --to-version <id> | Diff two versions in the same container (matched by resource ID). Output: added / removed / modified with field-level diff | | gtm diff-containers | --from-account <id> --from-container <id> --to-account <id> --to-container <id> | Diff the live versions of two containers (matched by resource name). --account may be used as a shared default if both containers live in the same account | | gtm create-tag | --account <id> --container <id> --from-file <path> [--workspace <id>] | Create a tag from a JSON file (accepts raw tag object or the wrapped {tag: ...} format emitted by get-tag). Targets the first workspace unless --workspace is supplied | | gtm create-trigger | --account <id> --container <id> --from-file <path> [--workspace <id>] | Create a trigger from a JSON file (raw trigger object or {trigger: ...}) | | gtm create-variable | --account <id> --container <id> --from-file <path> [--workspace <id>] | Create a variable from a JSON file (raw variable object or {variable: ...}) | | gtm update-variable | --account <id> --container <id> --id <variableId> --from-file <path> [--workspace <id>] | Replace an existing variable's parameter array with the one from a JSON file | | gtm list-workspaces | --account <id> --container <id> | List all workspaces (draft buckets) in a container | | gtm create-workspace | --account <id> --container <id> --name <workspaceName> [--description <text>] | Create a new workspace forked from the current live version | | gtm delete-workspace | --account <id> --container <id> --id <workspaceId> | Delete a workspace |

Docs Commands

| Command | Flags | Description | |---------|-------|-------------| | docs get | --id <documentId> | Read document as plain text (title + content) |

The document ID is the part between /d/ and /edit in a Google Docs URL:

https://docs.google.com/document/d/1aBcDeFg.../edit
                                  ^^^^^^^^^^
                                  document ID

Sheets Commands

| Command | Flags | Description | |---------|-------|-------------| | sheets get | --id <spreadsheetId> | Read all tabs in a spreadsheet. Output: { spreadsheetId, title, sheets: [{ title, rows }] } |

The spreadsheet ID is the part between /d/ and /edit in a Google Sheets URL:

https://docs.google.com/spreadsheets/d/1aBcDeFg.../edit
                                      ^^^^^^^^^^
                                      spreadsheet ID

Examples

# --- GTM ---

# Find your account and container IDs
gtools-cli gtm list-accounts
gtools-cli gtm list-containers --account 123456789

# List all tags
gtools-cli gtm list-tags --account 123456789 --container 987654321

# Get full tag details
gtools-cli gtm get-tag --account 123456789 --container 987654321 --id 42

# Search for purchase-related items
gtools-cli gtm search --account 123456789 --container 987654321 --query purchase

# Get custom template source code
gtools-cli gtm get-template --account 123456789 --container 987654321 --id 26

# Update an HTML tag's html content (the file's content is uploaded as-is)
gtools-cli gtm update-tag-html --account 123456789 --container 987654321 --id 42 --html-file ./new-tag.html

# List all versions in a container
gtools-cli gtm list-versions --account 123456789 --container 987654321

# Get a specific version's full snapshot
gtools-cli gtm get-version --account 123456789 --container 987654321 --id 31

# Diff two versions in the same container (e.g. what changed from v28 → v31)
gtools-cli gtm diff-versions --account 123456789 --container 987654321 --from-version 28 --to-version 31

# Diff the live versions of two containers (same account)
gtools-cli gtm diff-containers --account 123456789 --from-container 987654321 --to-container 987654322

# Copy a tag/trigger/variable from one container to another:
#   1. Dump the source resource to a file
gtools-cli gtm get-tag --account 123456789 --container 987654321 --id 42 > /tmp/src-tag.json
#   2. Create it in the target container (--from-file accepts the whole `{tag: ...}` output)
gtools-cli gtm create-tag --account 123456789 --container 987654322 --from-file /tmp/src-tag.json

# Update a variable's parameter block (use get-variable output as input)
gtools-cli gtm get-variable --account 123456789 --container 987654321 --id 27 > /tmp/src-var.json
gtools-cli gtm update-variable --account 123456789 --container 987654322 --id 63 --from-file /tmp/src-var.json

# Create a new workspace (forked from the current live version), then
# create resources inside it via --workspace so the change can be
# published independently of pending changes in other workspaces.
gtools-cli gtm create-workspace --account 123456789 --container 987654322 --name ZOEKIT-18164
#   → response includes the new workspaceId, e.g. "82"
gtools-cli gtm create-tag --account 123456789 --container 987654322 --from-file /tmp/src-tag.json --workspace 82

# List / delete workspaces
gtools-cli gtm list-workspaces --account 123456789 --container 987654322
gtools-cli gtm delete-workspace --account 123456789 --container 987654322 --id 82

# --- Docs ---

# Read a Google Doc's content
gtools-cli docs get --id 1aBcDeFgHiJkLmNoPqRsTuVwXyZ

# --- Sheets ---

# Read every tab's values from a spreadsheet
gtools-cli sheets get --id 1aBcDeFgHiJkLmNoPqRsTuVwXyZ

Development

bun test       # Run tests
bun run start  # Run directly without linking

Project Structure

src/
  cli.ts                 # Entry point, subcommand routing
  auth.ts                # OAuth client initialization
  oauth.ts               # OAuth login flow
  tokenStore.ts          # Token persistence
  config.ts              # Scopes, paths, OAuth config
  types.ts               # Shared CommandResult union
  commands/login.ts      # Top-level login command
  commands/install.ts    # Install skills command
  services/
    gtm/                 # Google Tag Manager service
      router.ts, client.ts, types.ts, diff.ts, commands/
    docs/                # Google Docs service
      router.ts, client.ts, extractText.ts, types.ts, commands/
    sheets/              # Google Sheets service
      router.ts, client.ts, types.ts, commands/

Adding a new Google service means adding a new directory under src/services/ with router.ts, client.ts, types.ts, and commands/, then registering it in src/cli.ts.

Claude Code Skills

Three skills are included for natural-language querying in Claude Code sessions:

  • skills/gtm/SKILL.md — query GTM data
  • skills/google-docs/SKILL.md — query Google Docs content
  • skills/google-sheets/SKILL.md — query Google Sheets content

To install, run the interactive installer:

gtools-cli install --skills

It will ask you:

  1. Scope — current project or global (~/)
  2. Target.claude/skills, .agents/skills, or a custom path