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

@aligntrue/exporters

v0.9.3

Published

Agent-specific exporters for AlignTrue with hybrid manifest + handler registry.

Downloads

116

Readme

@aligntrue/exporters

Agent-specific exporters for AlignTrue with hybrid manifest + handler registry.

Architecture Note

This package implements the ExporterPlugin interface defined in @aligntrue/plugin-contracts and uses AtomicFileWriter from @aligntrue/file-utils. Plugin contracts are defined separately to avoid circular dependencies between core and exporters packages.

Features

  • Hybrid Registry - Declarative manifest.json + optional TypeScript handlers
  • Community-Scalable - Add new exporters without changing core code
  • Schema Validation - Manifest validation with JSON Schema (draft 2020-12)
  • Dynamic Loading - Handler modules loaded on-demand with ESM imports
  • Fidelity Notes - Surface semantic mapping limitations in exports

Core Exporters

  • Cursor (.mdc) - Scope-based .cursor/rules/*.mdc files with vendor.cursor frontmatter
  • AGENTS.md - Universal single-file format for multiple agents
  • VS Code MCP - .vscode/mcp.json configuration with vendor.vscode extraction

Cursor Exporter

Generates .cursor/rules/*.mdc files (one per scope) with YAML frontmatter.

Features:

  • Scope-based file organization (preserves source file names; default scope uses the source filename)
  • Vendor.cursor metadata extracted to YAML frontmatter
  • Multiple rules concatenated as markdown sections
  • Content hash footer for drift detection
  • Fidelity tracking for unmapped fields and cross-agent vendor metadata

Example output: .cursor/rules/testing.mdc

---
session: default
ai_hint: "Focus on code quality"
---

## Rule: testing.require-tests

**Severity:** warn

All features must have tests to ensure reliability.

---

**Generated by AlignTrue**  
Content Hash: abc123...xyz789

**Fidelity Notes:**

- Machine-checkable rules (check) not represented in Cursor format

AGENTS.md Exporter

Generates single root-level AGENTS.md file with v1 versioned format.

Features:

  • Single merged file (not per-scope)
  • V1 format with version marker
  • Plain text severity labels (ERROR, WARN, INFO)
  • Scope paths in rule metadata
  • No vendor extraction (universal format)
  • Content hash footer

Example output: AGENTS.md

# AGENTS.md

**Version:** v1  
**Generated by:** AlignTrue

This file contains rules and guidance for AI coding agents.

## Rule: testing.require-tests

**ID:** testing.require-tests  
**Severity:** WARN  
**Scope:** \*_/_.ts

## All features should have tests.

**Generated by AlignTrue**  
Content Hash: abc123...xyz789

VS Code MCP Exporter

Generates .vscode/mcp.json configuration for Model Context Protocol support.

Features:

  • Single JSON file at workspace root
  • V1 JSON format with version marker
  • Extracts vendor.vscode metadata to top level (flattened structure)
  • Scope paths in rule metadata
  • Deterministic content hash
  • Fidelity tracking for unmapped fields and non-vscode vendor metadata

Example output: .vscode/mcp.json

{
  "version": "v1",
  "generated_by": "AlignTrue",
  "content_hash": "abc123...xyz789",
  "rules": [
    {
      "id": "formatting.use-prettier",
      "severity": "warn",
      "guidance": "Use Prettier for consistent code formatting.",
      "applies_to": ["**/*.ts", "**/*.tsx"],
      "workbench_setting": "editor.formatOnSave",
      "diagnostic_code": "format-001"
    }
  ],
  "fidelity_notes": [
    "Machine-checkable rules (check) not represented in MCP config format",
    "Vendor-specific metadata for other agents not extracted to MCP config: cursor, copilot"
  ]
}

Vendor.vscode extraction: Fields in vendor.vscode are flattened to the top level of each rule object. This makes the JSON cleaner for VS Code to consume while preserving VS Code-specific metadata.

Exporter Registry

The hybrid manifest system allows community contributions without modifying core code.

Manifest Structure

Each exporter directory contains a manifest.json:

{
  "name": "cursor",
  "version": "1.0.0",
  "description": "Export AlignTrue rules to Cursor .mdc format",
  "outputs": [".cursor/rules/*.mdc"],
  "handler": "./index.ts",
  "license": "MIT",
  "fidelityNotes": [
    "Session metadata stored in vendor.cursor namespace",
    "AI hints preserved in vendor.cursor.ai_hint"
  ]
}

Registry API

import { ExporterRegistry } from "@aligntrue/exporters";

const registry = new ExporterRegistry();

// Programmatic registration (for tests/mocks)
registry.register(exporter);

// Manifest-based registration (production)
await registry.registerFromManifest("./path/to/manifest.json");

// Discover all exporters in directory
const manifests = registry.discoverExporters("./src");

// Get exporter by name
const exporter = registry.get("cursor");

// List all registered exporters
const names = registry.list();

// Get manifest metadata
const manifest = registry.getManifest("cursor");

Creating Exporters

1. Create Manifest

Create manifest.json in your exporter directory:

{
  "name": "my-exporter",
  "version": "1.0.0",
  "description": "Export AlignTrue rules to My Tool format (min 10 chars)",
  "outputs": [".mytool/*.txt"],
  "handler": "./index.ts",
  "license": "MIT",
  "fidelityNotes": ["Optional: list any semantic mapping limitations"]
}

Required fields:

  • name - Lowercase alphanumeric with hyphens (e.g., my-exporter)
  • version - Semantic version (e.g., 1.0.0)
  • description - Human-readable description (min 10 characters)
  • outputs - Array of file patterns produced (min 1 item)

Optional fields:

  • handler - Relative path to TypeScript handler (e.g., ./index.ts)
  • license - License identifier (default: MIT)
  • fidelityNotes - Array of semantic mapping caveats

2. Implement Handler

Create a TypeScript file that exports an ExporterPlugin:

import type {
  ExporterPlugin,
  ScopedExportRequest,
  ExportOptions,
  ExportResult,
} from "@aligntrue/plugin-contracts";
import { AtomicFileWriter } from "@aligntrue/file-utils";
import { canonicalizeJson, computeHash } from "@aligntrue/schema";

export class MyExporterExporter implements ExporterPlugin {
  name = "my-exporter";
  version = "1.0.0";

  async export(
    request: ScopedExportRequest,
    options: ExportOptions,
  ): Promise<ExportResult> {
    // request.scope - Scope this export is for
    // request.align - Align with sections for this scope
    // request.outputPath - Suggested output path

    // options.outputDir - Base output directory
    // options.dryRun - If true, don't write files
    // options.backup - If true, create .backup files

    // Your export logic here
    const filesWritten: string[] = [];
    const contentHash = "sha256-hash-of-output";
    const fidelityNotes: string[] = [];

    return {
      success: true,
      filesWritten,
      contentHash,
      fidelityNotes,
    };
  }
}

// Export as default for registry loading
export default MyExporterExporter;

3. Write Tests

Create snapshot tests for your exporter:

import { describe, it, expect } from "vitest";
import { MyExporterExporter } from "./index.js";

describe("MyExporterExporter", () => {
  it("exports rules correctly", async () => {
    const exporter = new MyExporterExporter();
    const result = await exporter.export(request, options);

    expect(result.success).toBe(true);
    expect(result.filesWritten).toHaveLength(1);
    expect(result.contentHash).toMatch(/^sha256-/);
  });

  it("matches snapshot", async () => {
    // Golden output snapshot test
    const output = await generateOutput(rules);
    expect(output).toMatchSnapshot();
  });
});

Testing

The registry includes comprehensive test coverage:

Registry Tests (26 tests)

  • Programmatic registration
  • Manifest loading and validation
  • Handler loading with dynamic imports
  • Exporter discovery in directories
  • Query methods (get, has, list)

Schema Tests (20 tests)

  • Valid manifest validation
  • Required field enforcement
  • Format validation (name, version, semver)
  • Optional field handling
  • Additional properties rejection

API Reference

ExporterPlugin Interface

interface ExporterPlugin {
  name: string;
  version: string;
  export(
    request: ScopedExportRequest,
    options: ExportOptions,
  ): Promise<ExportResult>;
}

ScopedExportRequest

interface ScopedExportRequest {
  scope: ResolvedScope; // Scope this export is for
  align: Align; // Align with sections for this scope
  outputPath: string; // Suggested output path
}

ExportOptions

interface ExportOptions {
  outputDir: string;
  dryRun?: boolean;
  backup?: boolean;
}

ExportResult

interface ExportResult {
  success: boolean;
  filesWritten: string[];
  fidelityNotes?: string[];
  contentHash: string;
}

ExporterManifest

interface ExporterManifest {
  name: string; // Exporter name (lowercase alphanumeric with hyphens)
  version: string; // Semantic version (e.g., 1.0.0)
  description: string; // Human-readable description
  outputs: string[]; // File patterns produced
  handler?: string; // Optional: relative path to TypeScript handler
  license?: string; // License identifier (default: MIT)
  fidelityNotes?: string[]; // Optional: semantic mapping limitations
}

Fidelity Notes

Fidelity notes document semantic mapping limitations when converting AlignTrue IR to agent-specific formats.

When to add fidelity notes:

  • Agent format cannot represent a field (e.g., no severity levels)
  • Lossy conversion (e.g., severity mapped to markdown emphasis)
  • Agent-specific metadata stored in vendor.<agent> namespace
  • Behavioral differences (e.g., applies_to as comments vs. enforced)

Example:

{
  "fidelityNotes": [
    "Severity mapped to markdown emphasis (* = info, ** = warn, *** = error)",
    "applies_to patterns stored as comments (not enforced)",
    "Vendor metadata preserved in frontmatter"
  ]
}

Package Status

Step 10 Complete - Exporter registry with hybrid manifests implemented
Step 11 Complete - Cursor exporter with snapshot tests
Step 12 Complete - AGENTS.md formatter with v1 format
Step 13 Complete - VS Code MCP config exporter

All core exporters implemented!

Test Coverage:

  • 116 tests passing (100% pass rate)
  • 15 snapshot validations across 3 exporters
  • Full vendor extraction and fidelity tracking

Next:

  • Step 14: Complete sync engine

Security Expectations

Status: Trust-based contract (implemented)
See also: packages/core/docs/SECURITY.md

Guidelines for Exporter Implementations

All exporters (community-contributed or official) must follow these security and safety guidelines:

1. No Network Calls During Export

Exporters must be deterministic and work offline.

❌ Don't do this:

async export(request, options) {
  await fetch('https://api.example.com/track')  // Violation
  // ...
}

✅ Do this:

async export(request, options) {
  // Only work with local data
  const output = generateOutput(request.align.sections)
  return { success: true, filesWritten: [...] }
}

Rationale: Network calls introduce:

  • Non-determinism (network failures)
  • Privacy concerns (data leakage)
  • Security risks (MITM attacks)
  • Offline workflow breakage

2. Only Write Files via Provided Mechanisms

Use the output mechanisms provided by the framework. Don't write directly to arbitrary paths.

❌ Don't do this:

import { writeFileSync } from "fs";
writeFileSync("/tmp/output.txt", content); // Violation

✅ Do this:

// Use options.outputDir as base for all writes
const outputPath = join(options.outputDir, ".cursor/rules.mdc");
// Return file paths for atomic write handling
return {
  success: true,
  filesWritten: [outputPath],
  contentHash: "sha256-...",
};

Rationale: Framework provides:

  • Atomic writes (temp+rename pattern)
  • Path validation (no directory traversal)
  • Backup/rollback on errors
  • Checksum tracking

See: packages/core/src/sync/file-operations.ts - AtomicFileWriter


3. Don't Execute External Commands

Exporters must not execute shell commands or external programs.

❌ Don't do this:

import { execSync } from "child_process";
execSync("npm install something"); // Violation
execSync('git commit -m "Update"'); // Violation

✅ Do this:

// Pure transformation only
function transformSections(sections: AlignSection[]): string {
  return sections.map(formatSection).join("\n");
}

Rationale: Command execution introduces:

  • Security risks (arbitrary code execution)
  • Non-determinism (environment-dependent)
  • Side effects (unintended system changes)

4. Respect outputDir Boundaries

All output paths must be relative to options.outputDir. Never write outside the workspace.

❌ Don't do this:

const outputPath = "../../../etc/passwd"; // Violation
const outputPath = "/tmp/malicious.txt"; // Violation

✅ Do this:

// Always use join() with outputDir
const outputPath = join(options.outputDir, ".cursor/rules.mdc");

Enforcement: Sync engine validates output paths before calling exporters.
See: packages/core/src/sync/engine.ts - output path validation


5. Document Unsafe Operations in Fidelity Notes

If an exporter cannot support a feature safely, document the limitation in fidelityNotes:

const fidelityNotes: string[] = [];

if (rule.autofix?.command) {
  fidelityNotes.push(
    "Autofix commands not executed for security - stored as metadata only",
  );
}

if (rule.check?.type === "command_runner") {
  fidelityNotes.push(
    "Command runner checks not executed - validation deferred to CLI",
  );
}

return {
  success: true,
  fidelityNotes,
  // ...
};

Purpose: Transparency about what features are supported vs. preserved as metadata.


Runtime Enforcement (Future)

Current: Trust-based expectations with documentation and code review.

Future: Runtime sandboxing may be added:

  • Block network access (no fetch, http, https)
  • Block file system access outside workspace
  • Block child_process and exec family
  • Use Node.js VM or worker threads for isolation

See: packages/core/docs/SECURITY.md - "Future Enhancements"


Security Testing Checklist

When contributing an exporter:

  • [ ] No fetch(), http.request(), or network calls
  • [ ] No execSync(), spawn(), or command execution
  • [ ] All file writes use join(options.outputDir, relativePath)
  • [ ] No absolute paths or .. in output paths
  • [ ] Fidelity notes document any unsupported features
  • [ ] Tests include error paths and invalid inputs
  • [ ] No external dependencies beyond framework types

Code review will validate these requirements.


Contributing

See CONTRIBUTING.md for exporter contribution guidelines.

License

MIT