Creating Plugins#

Sidekick is built on oclif, so any oclif plugin works as a Sidekick plugin.

Plugin structure#

A Sidekick plugin is an npm package that exports oclif commands. The minimal structure:

my-plugin/
├── package.json
├── src/
   └── commands/
       └── hello.ts
└── tsconfig.json

Create a command#

import {Command} from '@oclif/core'

export default class Hello extends Command {
  static description = 'Say hello'

  static args = {
    name: Args.string({description: 'Person to greet'}),
  }

  async run(): Promise<void> {
    const {args} = await this.parse(Hello)
    this.log(`Hello, ${args.name}!`)
  }
}

Install your plugin#

# From npm
sdkck plugins install my-custom-plugin

# From GitHub
sdkck plugins install myorg/my-custom-plugin

# From a local directory (for development)
sdkck plugins link ./my-plugin

Plugin conventions#

  • Commands are auto-discovered from src/commands/ (compiled to dist/commands/)
  • Each file exports a class extending Command
  • Use ESM modules ("type": "module" in package.json)
  • Target ES2022 with TypeScript strict mode
  • Space-based topic separator ("myplugin subcommand")

JIT plugin declaration#

To make your plugin auto-install on first use, add it to oclif.jitPlugins in Sidekick's package.json:

{
  "oclif": {
    "jitPlugins": {
      "@myorg/my-plugin": "^1.0.0"
    }
  }
}

When a user invokes a command from your plugin for the first time, Sidekick automatically installs it.

Testing#

Test your plugin commands by directly instantiating the command class with a mock config. The config must include:

const config = {
  runHook: async () => ({failures: [], successes: []}),
}

For commands that depend on external clients, use public properties for dependency injection.