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

prosemirror-suggestcat-plugin

v2.3.0

Published

AI-powered grammar checking, text completion, and prompt-based editing for ProseMirror

Downloads

545

Readme

prosemirror-suggestcat-plugin

logo

Made by Emergence Engineering

AI-powered grammar checking, text completion, and inline autocomplete for ProseMirror

Features

  • AI grammar and style corrections with paragraph-level processing and parallel execution
  • AI text completion, rewriting, translation, tone changes, and more with streaming
  • Inline autocomplete with ghost text (like GitHub Copilot)
  • Multiple AI model support with automatic fallback
  • Dirty-state tracking -- only edited paragraphs are re-checked
  • Works with ProseMirror and TipTap

Installation

npm install prosemirror-suggestcat-plugin

Peer dependencies

npm install prosemirror-model prosemirror-state prosemirror-transform prosemirror-view

Quick Start

Create an account on SuggestCat and generate an API key, then register the plugins you need:

import { EditorState } from "prosemirror-state";
import { EditorView } from "prosemirror-view";
import {
  grammarSuggestPluginV2,
  grammarSuggestV2Key,
  completePluginV2,
  autoCompletePlugin,
} from "prosemirror-suggestcat-plugin";
import { ActionType } from "@emergence-engineering/prosemirror-block-runner";

const view = new EditorView(document.querySelector("#editor"), {
  state: EditorState.create({
    plugins: [
      grammarSuggestPluginV2("<YOUR_API_KEY>"),
      completePluginV2("<YOUR_API_KEY>"),
      autoCompletePlugin("<YOUR_API_KEY>"),
    ],
  }),
});

// Initialize the grammar checker
view.dispatch(
  view.state.tr.setMeta(grammarSuggestV2Key, {
    type: ActionType.INIT,
    metadata: {},
  }),
);

Options

GrammarSuggestV2Options

| Option | Type | Default | Description | |---|---|---|---| | apiKey | string | -- | SuggestCat API key (required, passed as first argument) | | apiEndpoint | string | SuggestCat API | Custom endpoint URL | | model | string \| AIModel | "openai:gpt-4o-mini" | AI model to use | | fallback | ModelFallbackConfig | -- | Fallback model config ({ fallbackModel, failureThreshold? }) | | batchSize | number | 2 | Number of parallel workers | | maxRetries | number | 3 | Max retries per paragraph | | backoffBase | number | 2000 | Base backoff delay in ms | | debounceMs | number | 1000 | Debounce delay before re-checking | | systemPrompt | string | -- | Custom system prompt for grammar requests (overrides default behavior) | | createPopup | "react" \| function | -- | "react" for React popups, or a factory function returning an HTMLElement |

CompleteV2Options

| Option | Type | Default | Description | |---|---|---|---| | maxSelection | number | 1000 | Max selected characters for a task | | apiEndpoint | string | SuggestCat API | Custom endpoint URL | | model | string | "openai:gpt-4o-mini" | AI model to use |

AutoCompleteOptions

| Option | Type | Default | Description | |---|---|---|---| | debounceMs | number | 500 | Debounce delay before requesting a suggestion | | maxContextLength | number | 2000 | Max characters sent as context | | apiEndpoint | string | SuggestCat API | Custom endpoint URL | | model | string | "openai:gpt-4o-mini" | AI model to use | | ghostTextClass | string | "autoCompleteGhostText" | CSS class for ghost text decoration | | systemPrompt | string | -- | Custom system prompt for autocomplete requests |

API

Grammar plugin

| Export | Type | Description | |---|---|---| | grammarSuggestPluginV2(apiKey, options?) | Plugin factory | Creates the grammar checking plugin | | grammarSuggestV2Key | PluginKey | Plugin key for dispatching metas | | acceptSuggestion(view, id) | function | Accept a grammar suggestion | | discardSuggestion(view, id) | function | Discard a grammar suggestion | | selectSuggestion(view, id) | function | Select a suggestion (for popup) | | deselectSuggestion(view) | function | Deselect the current suggestion | | requestHint(apiKey, original, replacement, options?) | function | Request an AI explanation for a suggestion (options: { endpoint?, model?, systemPrompt? }) | | getSelectedDecoration(view, key) | function | Get the currently selected decoration | | setGrammarSystemPrompt(view, key, prompt?) | function | Set or clear a custom system prompt for grammar checking | | grammarSuggestInit(view, key, systemPrompt?) | function | Initialize grammar checking, optionally with a custom system prompt | | setGrammarSuggestEnabled(view, enabled) | function | Enable/disable grammar checking |

Complete plugin

| Export | Type | Description | |---|---|---| | completePluginV2(apiKey, options?) | Plugin factory | Creates the completion plugin | | completeV2Key | PluginKey | Plugin key | | startTask(view, taskType, params?) | function | Start an AI task | | startCustomTask(view, systemPrompt) | function | Start a task with a custom system prompt | | acceptResult(view) | function | Accept the streamed result | | rejectResult(view) | function | Reject the streamed result | | cancelTask(view) | function | Cancel an in-progress task | | getCompleteState(state) | function | Get the current plugin state | | setEnabled(view, enabled) | function | Enable/disable the plugin | | AiPromptsWithoutParam | enum | Complete, SmallComplete, Improve, MakeLonger, MakeShorter, Simplify, Explain, ActionItems | | AiPromptsWithParam | enum | ChangeTone, Translate, Hint, Custom | | MoodParamType | enum | Casual, Confident, Straightforward, Friendly | | TranslationTargetLanguage | enum | English, Spanish, French, German, Italian, Portuguese, Dutch, Russian, Chinese, Korean, Japanese |

Autocomplete plugin

| Export | Type | Description | |---|---|---| | autoCompletePlugin(apiKey, options?) | Plugin factory | Creates the autocomplete plugin | | autoCompleteKey | PluginKey | Plugin key | | setAutoCompleteEnabled(view, enabled, systemPrompt?) | function | Enable/disable autocomplete, optionally with a custom prompt | | autoCompleteInit(view, systemPrompt?) | function | Enable autocomplete with an optional custom system prompt | | setAutoCompleteSystemPrompt(view, prompt?) | function | Set or clear a custom system prompt without toggling enabled | | acceptAutoCompletion(view) | function | Accept the ghost text | | dismissAutoCompletion(view) | function | Dismiss the ghost text | | isAutoCompleteEnabled(view) | function | Check if autocomplete is enabled | | hasAutoCompletion(view) | function | Check if a suggestion is showing |

Low-level API

| Export | Type | Description | |---|---|---| | streamingRequest(options, callbacks) | function | Streaming POST with onChunk, onComplete, onError | | grammarRequest(options) | function | Non-streaming POST for grammar corrections | | createApiConfig(apiKey, endpoint?, model?) | function | Build an API config object | | createGrammarApiConfig(apiKey, endpoint?, model?) | function | Build a grammar-specific API config | | getDiff(oldText, newText) | function | Re-exported from @emergence-engineering/fast-diff-merge |

Custom Prompts

All three plugins support custom system prompts, allowing you to control the AI behavior for your use case.

Grammar — custom system prompt

Set a system prompt at plugin creation, at init time, or dynamically at runtime:

// At creation time (baked into plugin options)
const grammarPlugin = grammarSuggestPluginV2("<API_KEY>", {
  systemPrompt: "You are a strict academic reviewer. Return only the fixed text, keeping separators intact.",
});

// At init time (recommended — combines init + system prompt)
import { grammarSuggestInit, grammarSuggestV2Key } from "prosemirror-suggestcat-plugin";

grammarSuggestInit(view, grammarSuggestV2Key, "Your custom prompt here");
// Without a custom prompt (uses default behavior):
grammarSuggestInit(view, grammarSuggestV2Key);

// Or dynamically at runtime (change prompt without re-init)
import { setGrammarSystemPrompt } from "prosemirror-suggestcat-plugin";

setGrammarSystemPrompt(view, grammarSuggestV2Key, "Your custom prompt here");
// Clear custom prompt to restore defaults:
setGrammarSystemPrompt(view, grammarSuggestV2Key, undefined);

Autocomplete — custom system prompt

// At creation time (baked into plugin options)
const autoComplete = autoCompletePlugin("<API_KEY>", {
  systemPrompt: "Complete sentences in a formal, technical tone.",
});

// At enable time (recommended — combines enable + system prompt)
import { autoCompleteInit } from "prosemirror-suggestcat-plugin";

autoCompleteInit(view, "Your custom prompt here");
// Or with setAutoCompleteEnabled:
setAutoCompleteEnabled(view, true, "Your custom prompt here");

// Dynamically change prompt without toggling enabled
import { setAutoCompleteSystemPrompt } from "prosemirror-suggestcat-plugin";

setAutoCompleteSystemPrompt(view, "Your custom prompt here");
// Clear:
setAutoCompleteSystemPrompt(view, undefined);

Complete — custom task

import { startCustomTask } from "prosemirror-suggestcat-plugin";

// Select text first, then:
startCustomTask(view, "Rewrite this text as API documentation.");

Hint — custom system prompt

The grammar hint (the "?" button explaining a correction) also supports a custom prompt:

import { requestHint } from "prosemirror-suggestcat-plugin";

const hint = await requestHint(apiKey, originalText, replacement, {
  systemPrompt: "Explain the correction as a writing tutor would, with examples.",
});

When using the React GrammarPopup, pass the hintSystemPrompt prop:

<GrammarPopup
  editorView={view}
  editorState={editorState}
  apiKey={apiKey}
  hintSystemPrompt="Explain the correction in simple terms."
/>

Styles

import "prosemirror-suggestcat-plugin/dist/styles/styles.css";

CSS classes for grammar decorations:

  • .grammarSuggestionV2 -- inline decoration on suggestions
  • .removalSuggestionV2 -- when the suggestion is a deletion
  • .grammarSuggestionV2-selected -- currently selected suggestion
  • .grammarPopupV2 -- popup container

CSS for autocomplete ghost text (add your own):

.autoCompleteGhostText {
  color: #9ca3af;
  opacity: 0.7;
  pointer-events: none;
}

TipTap

Wrap the plugins in a TipTap extension:

import { Extension } from "@tiptap/core";
import {
  grammarSuggestPluginV2,
  completePluginV2,
  autoCompletePlugin,
} from "prosemirror-suggestcat-plugin";

const SuggestCatExtension = Extension.create({
  name: "suggestcat",
  addProseMirrorPlugins() {
    return [
      grammarSuggestPluginV2("<YOUR_API_KEY>"),
      completePluginV2("<YOUR_API_KEY>"),
      autoCompletePlugin("<YOUR_API_KEY>"),
    ];
  },
});

Playground

See the interactive demo in the monorepo playground.

License

MIT