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

@openpets/slack

v1.0.4

Published

Slack integration plugin for OpenCode - search channels, read messages, and post to Slack

Downloads

412

Readme

Factory-Based Plugin Template

A comprehensive template for creating OpenCode plugins using the factory pattern with multi-provider workflow management. This template demonstrates modern plugin architecture with provider abstraction, configuration management, and workflow orchestration.

Table of Contents

  1. Factory Architecture
  2. Multi-Provider Design
  3. Quick Start
  4. Configuration Management
  5. Workflow Tools
  6. Provider Integration
  7. Best Practices
  8. Migration Guide
  9. Testing

Factory Architecture

This template uses the factory pattern from src/core/plugin-factory.ts:

Key Components

  • Factory Functions: createPlugin() and createSingleTool()
  • Zod Schemas: Type-safe parameter validation
  • Provider Abstraction: Dynamic provider loading and fallbacks
  • Configuration Management: Environment-based multi-provider setup

Architecture Benefits

Type Safety: Zod schemas ensure parameter validation
Provider Agnostic: Support multiple providers per service type
Graceful Fallbacks: Automatic provider switching on failures
Configuration Driven: Environment-based provider selection
Workflow Focused: High-level orchestration tools


Multi-Provider Design

Provider Types

interface PluginConfig {
  providers: {
    github?: { token: string; apiUrl?: string }
    maps?: { provider: 'googlemaps' | 'mapbox'; apiKey: string }
    ai?: { provider: 'fal'; apiKey: string }
  }
  preferences: Record<string, string>
  workflow: { timeout: number; retries: number; logLevel: string }
}

Provider Selection Logic

  1. Configuration Loading: Parse PROVIDER_PREFERENCES JSON
  2. Provider Initialization: Load available providers based on API keys
  3. Fallback Handling: Graceful degradation when providers fail
  4. Dynamic Loading: Import providers only when needed

Quick Start

1. Copy This Template

# Navigate to pets directory
cd /Users/andrewmaguire/LOCAL/Github/raggle-code/raggle-repo/core/pets/

# Copy template
cp -r _TEMPLATE_ my-workflow-manager
cd my-workflow-manager

2. Install Dependencies

npm install

3. Configure Environment

# Copy environment template
cp .env.example .env

# Edit with your API keys
nano .env

Example .env:

# Primary providers
GITHUB_TOKEN=ghp_your_github_token
GOOGLE_MAPS_API_KEY=your_google_maps_key
FAL_KEY=your_fal_api_key

# Provider preferences
PROVIDER_PREFERENCES={"maps":"googlemaps","ai":"fal"}

# Workflow settings
DEFAULT_TIMEOUT=30000
MAX_RETRIES=3
LOG_LEVEL=info

4. Test the Template

# Check provider status
opencode run "check provider status"

# Demo workflow
opencode run "demo workflow with geocode and enhance for 'New York'"

Configuration Management

Environment Variables

| Variable | Description | Required | |----------|-------------|-----------| | GITHUB_TOKEN | GitHub personal access token | Optional | | GOOGLE_MAPS_API_KEY | Google Maps API key | Optional | | MAPBOX_ACCESS_TOKEN | Mapbox access token | Optional | | FAL_KEY | FAL AI API key | Optional | | PROVIDER_PREFERENCES | JSON string with provider preferences | Optional | | DEFAULT_TIMEOUT | Operation timeout in milliseconds | Optional | | MAX_RETRIES | Maximum retry attempts | Optional | | LOG_LEVEL | Logging level (debug/info/warn/error) | Optional |

Provider Preferences

{
  "maps": "googlemaps",
  "ai": "fal",
  "version_control": "github"
}

Workflow Tools

1. workflow-demo

Demonstrates multi-provider workflow orchestration.

Actions:

  • geocode-and-enhance: Geocode location and enhance with AI
  • create-and-tag: Create repository with location-based tags
  • ai-process: Process text using AI provider

Examples:

opencode run "demo workflow with geocode and enhance for 'San Francisco'"
opencode run "demo workflow with create and tag for 'my-project'"
opencode run "demo workflow with ai process for 'Hello world'"

2. manage-providers

Check provider status and availability.

Actions:

  • status: Show all provider statuses
  • test: Test provider connectivity
  • list: List available and configured providers

Examples:

opencode run "check provider status"
opencode run "test all providers"
opencode run "list available providers"

3. manage-config

Manage plugin configuration.

Actions:

  • get: Get configuration values
  • set: Set configuration values
  • validate: Validate configuration

Examples:

opencode run "get configuration"
opencode run "validate plugin configuration"
opencode run "set configuration key 'test.value' to 'demo'"

Provider Integration

Adding New Providers

  1. Create Provider Utils (if not exists):
# Create new provider in src/utils/
mkdir src/utils/my-provider
cd src/utils/my-provider
  1. Implement Provider Interface:
// src/utils/my-provider/index.ts
export interface MyProviderConfig {
  apiKey: string
  apiUrl?: string
}

export class MyProviderAPI {
  constructor(private config: MyProviderConfig) {}
  
  async processData(data: string) {
    // Implementation
  }
}
  1. Update Template Configuration:
interface PluginConfig {
  providers: {
    // Add new provider
    myprovider?: { apiKey: string; apiUrl?: string }
  }
}
  1. Add Provider Initialization:
const initializeProviders = async (config: PluginConfig) => {
  const providers: any = {}
  
  if (config.providers.myprovider) {
    const { MyProviderAPI } = await import('../../src/utils/my-provider')
    providers.myprovider = new MyProviderAPI(config.providers.myprovider)
  }
  
  return providers
}

Best Practices

1. Factory Pattern Usage

// ✅ Good: Use factory for tool creation
const tools = [
  {
    name: "my-tool",
    description: "Tool description",
    schema: z.object({ /* ... */ }),
    execute: async (args) => { /* ... */ }
  }
]

return createPlugin(tools)

// ❌ Bad: Direct tool definition
return {
  tool: {
    "my-tool": tool({ /* ... */ })
  }
}

2. Provider Management

// ✅ Good: Lazy loading with error handling
const initializeProvider = async (config: any) => {
  try {
    const ProviderAPI = await import('../../src/utils/provider')
    return new ProviderAPI(config)
  } catch (error) {
    console.warn(`Provider initialization failed:`, error)
    return null
  }
}

// ❌ Bad: Eager loading without error handling
const provider = new ProviderAPI(config)  // Fails if import errors

3. Configuration Validation

// ✅ Good: Comprehensive validation
const validateConfig = (config: PluginConfig) => {
  const errors: string[] = []
  
  if (!config.providers.github && !config.providers.maps) {
    errors.push("At least one provider must be configured")
  }
  
  return { valid: errors.length === 0, errors }
}

// ❌ Bad: No validation
const providers = await initializeProviders(config)  // May fail silently

4. Error Handling

// ✅ Good: Structured error responses
return createResponse(false, undefined, [{
  error: error.message,
  provider: providerName,
  action: args.action
}], { duration: Date.now() - startTime })

// ❌ Bad: Unstructured errors
throw new Error(`Operation failed: ${error.message}`)

Migration Guide

From Legacy Plugin Structure

Old Structure:

export const LegacyPlugin: Plugin = async ({ project, client, $, directory, worktree }) => {
  return {
    tool: {
      "tool-name": tool({
        description: "...",
        args: { /* ... */ },
        execute: async (args) => { /* ... */ }
      })
    }
  }
}

New Factory Structure:

export const FactoryPlugin = async () => {
  const config = loadConfiguration()
  const providers = await initializeProviders(config)
  const tools = createWorkflowTools(providers, config)
  
  return createPlugin(tools)
}

Migration Steps

  1. Remove Legacy Parameters: Plugin no longer receives { project, client, $, directory, worktree }
  2. Add Configuration Loading: Implement loadConfiguration() function
  3. Add Provider Management: Implement initializeProviders() function
  4. Convert Tools to Factory: Use createPlugin() instead of direct tool objects
  5. Update Tool Schemas: Use Zod schemas instead of JSON schemas
  6. Add Error Handling: Implement structured error responses

Testing

Unit Testing

# Test individual tools
npm run test:queries

# Test workflow scenarios
npm run test:scenarios

# Test all functionality
npm run test:all

Provider Testing

# Test provider connectivity
opencode run "test all providers"

# Test provider fallbacks
# Temporarily disable primary provider and test fallbacks

Configuration Testing

# Test with missing environment variables
unset GITHUB_TOKEN
opencode run "validate plugin configuration"

# Test with invalid configuration
PROVIDER_PREFERENCES='{"invalid":"provider"}' opencode run "check provider status"

Advanced Patterns

1. Dynamic Provider Discovery

const discoverProviders = async () => {
  const providerDir = '../../src/utils'
  const providers = await fs.readdir(providerDir)
  
  return Promise.all(
    providers
      .filter(name => !name.startsWith('.'))
      .map(async name => {
        try {
          const module = await import(`${providerDir}/${name}`)
          return { name, module: module.default || module }
        } catch {
          return { name, error: 'Failed to load' }
        }
      })
  )
}

2. Provider Health Monitoring

const monitorProviderHealth = async (providers: any) => {
  const health = await Promise.allSettled(
    Object.entries(providers).map(async ([name, provider]) => [
      name,
      {
        status: await testProvider(provider),
        lastCheck: new Date().toISOString(),
        responseTime: await measureResponseTime(provider)
      }
    ])
  )
  
  return Object.fromEntries(health)
}

3. Workflow Composition

const composeWorkflow = (steps: WorkflowStep[]) => async (input: any) => {
  let result = input
  
  for (const step of steps) {
    try {
      result = await step.execute(result)
    } catch (error) {
      if (step.required) {
        throw error
      }
      console.warn(`Optional step ${step.name} failed:`, error)
    }
  }
  
  return result
}

Directory Structure

my-workflow-manager/
├── index.ts              # Factory-based plugin implementation
├── package.json          # Dependencies and metadata
├── README.md             # This documentation
├── .env.example          # Environment variable template
├── .env                  # Your actual configuration (gitignored)
├── .gitignore           # Git ignore file
└── opencode.json        # OpenCode configuration

Need Help?

  • Factory Pattern: See src/core/plugin-factory.ts
  • Provider Examples: See src/utils/ directory
  • Documentation: See prompts/pet-creator.md for LLM guidance

License

MIT - feel free to use this template for your own workflow managers!


Happy workflow building! 🚀