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

@happyvertical/projects

v0.78.0

Published

Standardized project management interface for GitHub Projects, Jira, ZenHub, and Linear

Downloads

2,559

Readme

@happyvertical/projects

Standardized project management interface for GitHub Projects, Jira, ZenHub, and Linear.

Installation

pnpm add @happyvertical/projects @happyvertical/repos

Claude Code Context

Install Claude Code context files for AI-assisted development:

npx have-projects-context

This copies the package's AGENT.md documentation and metadata.json metadata to your project's .claude/ directory, enabling Claude to provide better assistance when working with this package.

Usage

Basic Example

import { getProject } from '@happyvertical/projects';
import { getRepository } from '@happyvertical/repos';

// Get repository to retrieve issue node IDs
const repo = await getRepository({
  type: 'github',
  owner: 'happyvertical',
  repo: 'sdk',
  token: process.env.GITHUB_TOKEN
});

// Get project with status field configuration
const project = await getProject({
  type: 'github',
  projectId: 'PVT_kwDOB9Y8ns4A8-TY',
  token: process.env.GITHUB_TOKEN,
  statusFieldId: 'PVTSSF_lADOB9Y8ns4A8-TYzgw0GaY',
  statusOptions: {
    'New': 'option-id-1',
    'Backlog': 'option-id-2',
    'In Progress': 'option-id-3',
    'Done': 'option-id-4'
  }
});

// Add issue to project
const issue = await repo.getIssue(352);
const item = await project.addItem(issue.id);

// Update status
await project.updateItemStatus(item.id, 'In Progress');

Kanban Workflow

// List all items
const items = await project.listItems();

// Get available statuses
const statuses = await project.listStatuses();

// Move item through workflow
await project.updateItemStatus(itemId, 'Ready');
await project.updateItemStatus(itemId, 'In Progress');
await project.updateItemStatus(itemId, 'Review');
await project.updateItemStatus(itemId, 'Done');

Custom Field Management

// List all project fields
const fields = await project.listFields();

// Update custom field
const priorityField = fields.find(f => f.name === 'Priority');
if (priorityField) {
  await project.updateItemField(itemId, priorityField.id, 'high-priority-option-id');
}

API Reference

Factory Function

getProject(options)

Creates a project management client instance.

Parameters:

  • options: ProjectConfig | IProject - Project configuration or existing instance

Returns: Promise<IProject>

Example:

const project = await getProject({
  type: 'github',
  projectId: 'PVT_kwDOB9Y8ns4A8-TY',
  token: process.env.GITHUB_TOKEN,
  statusFieldId: 'PVTSSF_lADOB9Y8ns4A8-TYzgw0GaY',
  statusOptions: {
    'New': 'option-id-1',
    'Backlog': 'option-id-2',
    'In Progress': 'option-id-3',
    'Done': 'option-id-4'
  }
});

IProject Interface

Project Information

getProject(): Promise<Project>

Get project details including fields and statuses.

Returns: Project metadata with all fields and status options

Item Management

addItem(contentId: string): Promise<ProjectItem>

Add an issue or pull request to the project.

Parameters:

  • contentId: string - Node ID of the issue or PR (from @happyvertical/repos)

Returns: Created project item

removeItem(itemId: string): Promise<void>

Remove an item from the project.

Parameters:

  • itemId: string - Project item ID
getItem(itemId: string): Promise<ProjectItem | null>

Get a specific project item.

Parameters:

  • itemId: string - Project item ID

Returns: Project item or null if not found

listItems(filters?: ItemFilters): Promise<ProjectItem[]>

List all items in the project.

Parameters:

  • filters?: ItemFilters - Optional filters (limit, cursor, status)

Returns: Array of project items

Status Management

updateItemStatus(itemId: string, status: string): Promise<void>

Update the status of a project item.

Parameters:

  • itemId: string - Project item ID
  • status: string - Status name (must match statusOptions in config)

Example:

await project.updateItemStatus(itemId, 'In Progress');
listStatuses(): Promise<Status[]>

Get all available status options.

Returns: Array of status definitions with IDs, names, colors

Field Management

updateItemField(itemId: string, fieldId: string, value: unknown): Promise<void>

Update a custom field value.

Parameters:

  • itemId: string - Project item ID
  • fieldId: string - Field ID
  • value: unknown - Field value (type depends on field type)
listFields(): Promise<Field[]>

Get all project fields.

Returns: Array of field definitions

GitHub Projects V2 Setup

Finding Your Project ID

  1. Navigate to your GitHub Project
  2. In the URL, find the project number: https://github.com/orgs/ORG/projects/123
  3. Use GitHub CLI to get the node ID:
    gh api graphql -f query='
      query {
        organization(login: "ORG") {
          projectV2(number: 123) {
            id
          }
        }
      }
    '

Finding Status Field ID and Options

gh api graphql -f query='
  query {
    node(id: "PVT_kwDOB9Y8ns4A8-TY") {
      ... on ProjectV2 {
        fields(first: 20) {
          nodes {
            ... on ProjectV2SingleSelectField {
              id
              name
              options {
                id
                name
              }
            }
          }
        }
      }
    }
  }
'

Look for the "Status" field and note:

  • Field ID (PVTSSF_...)
  • Option IDs for each status

Configuration Example

const project = await getProject({
  type: 'github',
  projectId: 'PVT_kwDOB9Y8ns4A8-TY',      // From step 1
  token: process.env.GITHUB_TOKEN,
  statusFieldId: 'PVTSSF_lADOB9Y8ns4A8-TYzgw0GaY',  // From step 2
  statusOptions: {
    'New': '47fc9ee4',           // Option IDs from step 2
    'Backlog': '4c6e9e0c',
    'Planning': 'f75ad846',
    'Ready': '98236657',
    'In Progress': 'b5f9e3e1',
    'Review': '5e1b3e8f',
    'Done': '3f4e5d6c'
  }
});

Standard Kanban Statuses

The package exports standard kanban status names:

import { KANBAN_STATUSES } from '@happyvertical/projects';

// ['New', 'Backlog', 'Planning', 'Ready', 'In Progress', 'Review', 'Done']

Error Handling

import { ProjectError, ProjectErrorCode } from '@happyvertical/projects';

try {
  await project.updateItemStatus(itemId, 'Invalid Status');
} catch (error) {
  if (error instanceof ProjectError) {
    switch (error.code) {
      case ProjectErrorCode.INVALID_STATUS:
        console.error('Status not found:', error.message);
        break;
      case ProjectErrorCode.UNAUTHORIZED:
        console.error('Token lacks permissions');
        break;
      case ProjectErrorCode.RATE_LIMITED:
        console.error('Rate limited, retry after delay');
        break;
    }
  }
}

Integration with @happyvertical/repos

Projects work seamlessly with repositories:

import { getRepository } from '@happyvertical/repos';
import { getProject } from '@happyvertical/projects';

const repo = await getRepository({
  type: 'github',
  owner: 'happyvertical',
  repo: 'sdk',
  token: process.env.GITHUB_TOKEN
});

const project = await getProject({
  type: 'github',
  projectId: 'PVT_kwDOB9Y8ns4A8-TY',
  token: process.env.GITHUB_TOKEN,
  statusFieldId: 'PVTSSF_lADOB9Y8ns4A8-TYzgw0GaY',
  statusOptions: {
    'New': 'option-id-1',
    'In Progress': 'option-id-2',
    'Done': 'option-id-3'
  }
});

// Create issue and add to project
const issue = await repo.createIssue({
  title: 'New feature',
  body: 'Description',
  labels: ['type: feature']
});

const item = await project.addItem(issue.id);
await project.updateItemStatus(item.id, 'In Progress');

Supported Platforms

| Platform | Status | Notes | |----------|--------|-------| | GitHub Projects V2 | ✅ Complete | Full GraphQL implementation | | Jira | 🚧 Planned | Coming soon | | ZenHub | 🚧 Planned | Coming soon | | Linear | 🚧 Planned | Coming soon |

License

MIT