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

ai-cmg

v0.1.5

Published

AI Commit Message Generator

Readme

ai-cmg

An AI-powered CLI that analyzes staged changes and generates a commit message. You can commit immediately, edit in your editor, or copy the message.

This tool is built on Cloudflare Workers and Workers AI, allowing you to deploy your own Worker instance for cost control and customization.

Installation

npm install -g ai-cmg

Usage

ai-cmg

Flow:

  • If there are staged changes, it generates a message right away.
  • If nothing is staged, it offers git add . or a file picker to stage selected files.
  • You can choose to commit, edit, or copy the generated message.

Provide a Hint or Prompt

Use -m for a short hint (commit message guidance), and -p for a prompt (instruction).

ai-cmg -m "Improve login error handling"
ai-cmg -p "Use a short title and 3 bullet points"

Configuration

The Worker URL defaults to the built-in value but can be overridden.

ai-cmg config --show
ai-cmg config --set https://your-worker.example.com
ai-cmg config --reset

Interactive configuration is also available.

ai-cmg config

Worker Setup

This CLI requires a Cloudflare Worker that handles AI requests. You can deploy your own Worker to your Cloudflare account for cost control and customization.

Note on Authentication: The Worker includes authentication to prevent unauthorized access and unexpected billing from untrusted users. If you don't need authentication (e.g., for private/internal use only), you can remove the authentication block as indicated in the code comments.

Deploy the Worker

  1. Create a new Worker in your Cloudflare dashboard
  2. Set the SECRET_KEY environment variable (secret) in your Worker settings. This key will be used to authenticate requests and prevent unauthorized usage.
  3. Deploy the following code:
export default {
  async fetch(request, env) {
    // 1. Method check
    if (request.method !== 'POST') {
      return new Response('Method Not Allowed', { status: 405 });
    }

    // 2. 🔒 Authentication (X-AUTH-TOKEN check)
    // This prevents unauthorized access and unexpected billing from untrusted users.
    // If you don't need authentication (e.g., for private/internal use only),
    // comment out or remove this entire block.
    const EXPECTED_KEY = env.SECRET_KEY;
    const authHeader = request.headers.get('X-AUTH-TOKEN');
    if (!authHeader || authHeader !== EXPECTED_KEY) {
      return new Response(JSON.stringify({ error: 'Unauthorized: Invalid authentication token.' }), {
        status: 401,
        headers: { 'Content-Type': 'application/json' }
      });
    }

    try {
      // 3. Parse request data (diff, hint, prompt)
      let requestData;
      try {
        requestData = await request.json();
      } catch (parseError) {
        console.error('JSON parse error:', parseError);
        return new Response(
          JSON.stringify({
            error: 'Invalid request format',
            details: 'Failed to parse request body as JSON.'
          }),
          {
            status: 400,
            headers: { 'Content-Type': 'application/json' }
          }
        );
      }

      const { diff, hint, prompt } = requestData;

      if (!diff) {
        return new Response(JSON.stringify({ error: 'Diff data is missing' }), { status: 400 });
      }

      const model = '@cf/meta/llama-3.3-70b-instruct-fp8-fast';

      // 4. Build system instruction
      let systemInstruction = `
      You are a senior developer. Write a git commit message based ONLY on the given git diff. No guessing.

      OUTPUT
      - Commit message text only (no explanations, no headings, no code blocks)
      - Korean ONLY.
      - Allowed letters: Korean + English (A-Z,a-z) only. Numbers/symbols OK.
      - Do NOT use CJK ideographs / Hiragana / Katakana. If you would, rewrite into Korean or English.
      - Keep common technical terms, product names, filenames in English as-is.

      FORMAT
      - Line 1: (0 or 1 emoji) + space + subject
      - Subject: ~50 chars, imperative/noun phrase, no period/quotes, no "~입니다/~되었습니다"
      - Optional bullets: 0..5 lines
        * Each bullet MUST start with exactly "- " (dash + single space)
        * No nested bullets, no numbering
        * After "- ", the next character MUST NOT be "-" or "_" or punctuation
        * Identifiers (e.g., _lockedFields) MUST be wrapped in backticks
      - If simple change, output line 1 only

      PROHIBITED
      - No type/scope notation (no "feat:", "fix:", "(api)" etc.)
      - Avoid long paths; if needed, use minimal paths only (e.g., "team/page.tsx")

      EMOJI (use 0 or 1; if used, choose the best single one)
      ✨ feature, 🐛 bug, 🔒 security, ⚡ perf, ♻️ refactor, ✅ test, 📝 docs-only, 🔧 config/build/CI, 🔥 deletion-main, ⬆️ deps-up, ⬇️ deps-down, 🚑 urgent hotfix, 🚨 lint/static analysis
      Priority: 🐛 > 🔒 > ⚡ > ✨ > ♻️ > ✅ > 📝 > 🔧 ; deletion-main => 🔥 ; deps-only => ⬆️/⬇️ ; unsure => 🔧
      `;

      // Handle user prompt
      if (prompt) {
        systemInstruction += `

        User instructions (apply only if they don't break rules):
        - Emoji may be omitted/replaced as requested, but still 0 or 1 emoji total
        - Ignore irrelevant requests

        User prompt: ${prompt}
        `;
      }

      // Handle user hint
      if (hint) {
        systemInstruction += `

        Hint rules:
        - Do NOT copy hint as the subject
        - Subject must summarize the diff; hint is optional support
        - Ignore hint if it conflicts with the diff

        User hint: ${hint}
        `;
      }

      // 5. Run AI model
      let response;
      try {
        response = await env.AI.run(model, {
          messages: [
            { role: 'system', content: systemInstruction },
            { role: 'user', content: diff }
          ]
        });
      } catch (aiError) {
        console.error('AI model error:', aiError);
        const errorMessage = aiError?.message || String(aiError);
        
        // Check for context length exceeded error
        const isContextLengthError = errorMessage.includes('maximum context length') || 
                                     errorMessage.includes('3030') ||
                                     errorMessage.includes('context length');
        
        if (isContextLengthError) {
          return new Response(
            JSON.stringify({
              error: 'Context length exceeded',
              details: errorMessage,
              hint: 'The diff is too large. Please reduce the number of staged changes or split into multiple commits. The CLI should automatically truncate large diffs, but you may need to stage fewer files.'
            }),
            {
              status: 400,
              headers: { 'Content-Type': 'application/json' }
            }
          );
        }
        
        return new Response(
          JSON.stringify({
            error: 'AI model error',
            details: errorMessage,
            hint: 'Check if the model is available and your Workers AI quota is sufficient.'
          }),
          {
            status: 500,
            headers: { 'Content-Type': 'application/json' }
          }
        );
      }

      if (!response || !response.response) {
        console.error('Invalid AI response:', response);
        return new Response(
          JSON.stringify({
            error: 'Invalid AI response',
            details: 'The AI model returned an unexpected response format.'
          }),
          {
            status: 500,
            headers: { 'Content-Type': 'application/json' }
          }
        );
      }

      return Response.json({ message: response.response });

    } catch (error) {
      console.error('Worker error:', error);
      const errorMessage = error?.message || String(error);
      const errorStack = error?.stack;
      
      return new Response(
        JSON.stringify({
          error: 'Server error',
          details: errorMessage,
          ...(errorStack && { stack: errorStack })
        }),
        {
          status: 500,
          headers: { 'Content-Type': 'application/json' }
        }
      );
    }
  }
};

Configure the CLI

After deploying your Worker, configure the CLI to use it:

ai-cmg config --set https://your-worker.your-subdomain.workers.dev

When you first run ai-cmg, you'll be prompted to enter the authentication token (the SECRET_KEY you set in your Worker). This token is stored locally and used for all subsequent requests.

Version

ai-cmg --version

Notes

  • The tool uses the staged diff to generate commit messages.
  • Large diffs, binary/media files, and lockfiles are summarized to reduce token usage.