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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@bobfrankston/gcards

v0.1.21

Published

Google Contacts cleanup and management tool

Downloads

2,019

Readme

gcards - Google Contacts Management Tool

A CLI tool for syncing, managing, and cleaning up Google Contacts.

Installation

npm install -g @bobfrankston/gcards

Quick Start

# First time - specify your Gmail username
gcards sync --user yourname

# Subsequent runs remember the user
gcards sync
gcards push

Commands

gcards

Main sync and push operations (Google API):

gcards sync [-u user] [-a]    # Download contacts from Google
gcards push [-u user] [-a]    # Push local changes to Google
gcards -a                     # Process all users

gfix

One-time cleanup operations (local files only):

gfix inspect -u user          # Preview all standard fixes (no changes)
gfix apply -u user            # Apply all standard fixes

gfix names -u user            # Preview name parsing + dup phone/email removal
gfix names -u user --apply    # Parse names, remove dup phones/emails, move email/phone-only to _delete/
gfix problems -u user         # Process edited problems.txt (x=delete, or replace name)

gfix birthday -u user         # Preview birthday extraction
gfix birthday -u user --apply # Extract to CSV and remove

gfix undup -u user            # Find duplicate contacts -> merger.json
gfix merge -u user            # Merge duplicates locally (then use gcards push)

gfix export -u source -to target "pattern"  # Export contacts to another user

Google People API Fields

Identity (Names)

| Field | Read/Write | Description | |-------|------------|-------------| | names[].givenName | Write | First name | | names[].familyName | Write | Last name | | names[].middleName | Write | Middle name | | names[].honorificPrefix | Write | Prefix (Dr., Prof., etc.) | | names[].honorificSuffix | Write | Suffix (Jr., III, PhD, etc.) | | names[].displayName | Read-only | Full name (Google generates from above) | | names[].displayNameLastFirst | Read-only | Sorting form "Last, First" (Google generates) | | names[].unstructuredName | Write | Free-form name when structured fields not available |

Sorting

| Field | Read/Write | Description | |-------|------------|-------------| | fileAses[].value | Write | Custom sort override (e.g., "Home Depot" instead of "The Home Depot") |

If blank, Google sorts by familyName automatically.

Contact Information

| Field | Read/Write | Description | |-------|------------|-------------| | emailAddresses[].value | Write | Email address | | emailAddresses[].type | Write | Label: home, work, other | | phoneNumbers[].value | Write | Phone number | | phoneNumbers[].type | Write | Label: mobile, work, home, main |

Business

| Field | Read/Write | Description | |-------|------------|-------------| | organizations[].name | Write | Company name | | organizations[].title | Write | Job title |

Dates

| Field | Read/Write | Description | |-------|------------|-------------| | birthdays[].date.year | Write | Birth year (optional) | | birthdays[].date.month | Write | Birth month (1-12) | | birthdays[].date.day | Write | Birth day (1-31) |

Management (Required for Updates)

| Field | Read/Write | Description | |-------|------------|-------------| | resourceName | Read-only | Unique contact ID (e.g., people/c12345) | | etag | Read-only | Version key - must match when updating |

The etag prevents conflicts: if Google's version changed since you downloaded, your update will fail. Run gcards sync to get the latest version.

Data Directory

  • Windows: %APPDATA%\gcards\ (app directory)
  • Linux/Mac: ~/.config/gcards/ (app directory)
  • Development: ./data/ symlink to app directory's data/ folder

Directory Structure

gcards/                   # App directory (%APPDATA%\gcards or ~/.config/gcards)
  config.json             # Last user, settings
  data/                   # User data directory
    <username>/
      contacts/           # Active contacts (*.json)
      deleted/            # Backup of deleted contact files
      _delete/            # User requests to delete (move files here)
      _add/               # User requests to add new contacts
      fix-logs/           # Logs from gfix operations
      index.json          # Active contact index (hasPhoto, starred flags)
      deleted.json        # Deleted contacts index
      notdeleted.json     # Contacts skipped due to photo/starred
      token.json          # OAuth token (read-only)
      token-write.json    # OAuth token (read-write)
      changes.log         # Log from gfix names
      birthdays.csv       # Extracted birthdays
      merger.json         # Duplicates to merge (from gfix undup)
      merged.json         # Processed merges (history)

Fixes Applied by gfix inspect/apply

  • Remove leading/trailing dashes, quotes, spaces from name fields
  • Extract repeated honorific prefixes (Dr., Prof.) to honorificPrefix
  • Remove duplicate phone numbers (normalized comparison)
  • Remove duplicate email addresses (case-insensitive)

Name Parsing (gfix names)

When a contact has a full name in givenName but no familyName:

  • Parses "First Middle Last" into separate fields
  • Handles suffixes like Ph.D., M.D., P.E., Jr., III
  • Updates displayNameLastFirst to proper "Last, First" format
  • Cleans up fileAses entries (strips junk characters)
  • Fixes repeated words (e.g., "John Smith Smith Smith" → "John Smith")
  • Creates changes.log with all modifications

Contacts with no real name are moved to _delete/:

  • Email-only (no name field)
  • Phone-only (phone number as name)
  • Empty contacts (no name, email, or phone)

Recovery lists saved to emailonly.json and phoneonly.json.

Handling Problem Contacts (gfix problems)

After gfix names, ambiguous contacts are saved to problems.txt. Edit this file to fix:

  • Add x at start of line to mark for deletion
  • Replace the name with corrected "First Last" format
  • Leave unchanged to skip

Then run gfix problems -u user to apply.

Workflow

  1. Initial sync: gcards sync -u yourname
  2. Review fixes: gfix inspect -u yourname
  3. Apply fixes: gfix apply -u yourname
  4. Parse names: gfix names -u yourname --apply
  5. Push to Google: gcards push -u yourname

Deleting Contacts

Three ways to mark contacts for deletion:

  1. In index.json: Add "_delete": true to an entry
  2. In contact JSON: Add "_delete": true to the contact file
  3. Move to _delete/: Move the contact file to the _delete/ folder

Then run gcards push to apply deletions.

Photo/Starred Protection

Contacts with photos or starred status are not deleted from Google to prevent data loss:

  • Contacts with non-default photos: _delete set to "photo"
  • Starred/favorite contacts: _delete set to "starred"

These remain in Google and index.json with the skip reason. Review notdeleted.json after push.

Backup

All deleted contact files are moved to deleted/ folder as backup (not permanently deleted). Index entries move to deleted.json.

Duplicate Contact Merging

  1. Find duplicates: gfix undup -u yourname
    • Creates merger.json with contacts having same name + overlapping email
  2. Review: Edit merger.json:
    • Remove entries you don't want to merge
    • Add "_delete": true to delete all contacts in a group instead of merging
  3. Merge locally: gfix merge -u yourname
    • Updates target contact files with merged data
    • Marks source contacts with _delete: true
    • Moves processed entries to merged.json
  4. Push to Google: gcards push -u yourname
  5. Resync: gcards sync -u yourname --full

Example merger.json:

[
  { "name": "John Smith", "emails": ["[email protected]"], "resourceNames": ["people/c1", "people/c2"] },
  { "name": "Spam Contact", "emails": ["[email protected]"], "resourceNames": ["people/c3", "people/c4"], "_delete": true }
]

ESC Key

Press ESC during sync/push to stop safely after the current operation.

Multiple Users

# Process specific user
gcards sync -u alice

# Process all users
gcards sync -a
gcards push -a

Exporting Contacts Between Users

Transfer contacts from one user's account to another:

gfix export -u bob -to alice "John*"         # Export contacts matching "John*"
gfix export -u bob -to ali "*@example.com"   # Export by email (partial user match)
gfix export -u bob -to alice c1234567890     # Export specific contact by ID

Features:

  • -u source user (partial match supported)
  • -to target user (partial match - "ali" matches "alice" if unique)
  • Pattern supports * (any chars) and ? (single char) wildcards
  • Matches on: displayName, givenName, familyName, "Last, First", email
  • Searches both contacts/ and deleted/ directories
  • Multiple matches prompt for selection: number(s), * for all, q to quit
  • Creates cleaned file in target's _add/ as x<sourceId>.json

After export, run gcards push -u <target> to upload.

Setup

Google API Setup

  1. Create Google Cloud project
  2. Enable People API
  3. Create OAuth2 credentials (Desktop app type)
  4. Download credentials.json to the gcards directory

AI Error Explanations (Optional)

When API errors occur, gcards can use AI to explain what went wrong and suggest fixes.

  1. Create keys.env in your gcards app directory:

    • Windows: %APPDATA%\gcards\keys.env
    • Linux/Mac: ~/.config/gcards/keys.env
  2. Add your API key(s):

    ANTHROPIC_API_KEY=sk-ant-api03-...

    or

    OPENAI_API_KEY=sk-...

Get API keys:

  • Anthropic: https://console.anthropic.com/settings/keys
  • OpenAI: https://platform.openai.com/api-keys

The tool tries Anthropic first, then falls back to OpenAI if available.

License

MIT