Robot

The central runtime. Manages commands, adapters, listeners, middleware, and state.

Constructor

new Robot(config = {})

Static Factory (recommended)

const robot = await Robot.create({
  adapters:  [],          // Array of Adapter instances to register immediately
  directory: './modules', // Path to auto-load modules from
  baseUrl:   import.meta.url  // Base URL for resolving module paths
})

Robot.create() auto-registers the built-in help command and loads modules from the given directory.

Properties

PropertyTypeDescription
commandsCommandRegistryRegister and resolve commands
adaptersAdapterRegistryRegister and retrieve adapters
listenersListenerRegistryRegister regex pattern listeners

Methods

MethodReturnsDescription
robot.use(fn)voidRegister one or more middleware functions
robot.receive(envelope)Promise<Result>Dispatch an inbound command envelope through the full pipeline
robot.listen(envelope)Promise<void>Run pattern listeners against an envelope
robot.load(moduleLoader)Promise<void>Load a module inline (moduleLoader is an async fn receiving robot)
robot.loadModules({ directory, baseUrl })Promise<void>Auto-load all .js modules from a directory
robot.log(event, entry)voidEmit a structured lifecycle log event
// Register middleware
robot.use(async (ctx, next) => {
  console.log('→', ctx.command.id)
  await next()
})

// Dispatch a command programmatically
const result = await robot.receive({
  adapter:  'cli',
  type:     'message',
  text:     'ping',
  actor:    { id: 'test', permissions: [] },
  channel:  { id: 'test-channel' }
})

// Load a module inline
await robot.load(async (robot) => {
  robot.commands.register(new Command({ id: 'ping', handler: async () => createTextResponse('Pong!') }))
})

Command

import { Command } from '@devchitchat/chatopsjs'

new Command({
  id:          string,                    // required — canonical ID, e.g. 'tickets.create'
  description: string,                    // optional — shown in help output
  aliases:     string[],                  // optional — alternate invocation names
  args:        Record<string, ArgDef>,    // optional — argument schema
  permissions: string[],                  // optional — required actor permission grants
  confirm:     ConfirmDef | null,         // optional — confirmation policy
  handler:     async (ctx) => Response    // optional — command handler
})

ArgDef

{
  type:     'string',        // currently only 'string' is supported
  required: true | false
}

ConfirmDef

{
  mode:    'yes-no',          // confirmation mode
  message: string             // prompt shown to the user
}

Properties

PropertyTypeDescription
idstringCanonical identifier
descriptionstringHuman-readable description for help
aliasesstring[]Alternate invocation names
normalizedAliasesstring[]Normalized alias variants (lowercased, trimmed)
argsobjectArgument schema map
permissionsstring[]Required permission grants
confirmobject | nullConfirmation configuration
handlerfunctionAsync handler function

Adapter

Abstract base class for all adapters. Extend this and implement the three methods.

import { Adapter } from '@devchitchat/chatopsjs'

class MyAdapter extends Adapter {
  constructor(robot, options = {}) {
    super(robot, 'my-adapter')  // second arg = adapter name
  }

  async start() {
    // Bootstrap provider connection
    // Call robot.receive(envelope) for each incoming message
  }

  async send(envelope, message) {
    // Deliver response to envelope.channel.id
  }

  async reply(envelope, message) {
    // Deliver direct reply to actor (defaults to send())
    await this.send(envelope, message)
  }
}
MethodRequiredDescription
start()RequiredBootstrap the provider connection
send(envelope, message)RequiredDeliver a response to the originating channel
reply(envelope, message)OptionalDeliver a direct reply to the actor. Defaults to send()

CliAdapter

The built-in CLI adapter. Uses Node.js readline for an interactive REPL.

import { CliAdapter } from '@devchitchat/chatopsjs'

const cli = new CliAdapter(robot, {
  inputStream:  process.stdin,        // readable stream (default: stdin)
  outputStream: process.stdout,       // writable stream (default: stdout)
  prompt:       'chatops> ',          // REPL prompt string
  prefix:       null,                 // command prefix (null = no prefix required)
  actor: {
    id:          'cli',               // actor identity for this session
    permissions: ['deploys:write']    // permission grants for this session
  },
  channel: {
    id: 'local-shell'                 // channel identifier
  }
})

The CLI adapter handles the confirmation flow internally — when a command requires confirmation, it prompts the user inline and waits for yes or no.

Response Builders

createTextResponse

import { createTextResponse } from '@devchitchat/chatopsjs'

createTextResponse(text: string)
// Returns: { text: string }

createMessageResponse

import { createMessageResponse } from '@devchitchat/chatopsjs'

createMessageResponse({
  fallbackText: string,    // Plain text fallback for adapters that can't render blocks
  blocks: Block[]          // Array of block objects
})
// Returns: { text: string, blocks: Block[] }

Block Types

TypeFieldsDescription
sectiontext: stringA paragraph of text
factsitems: { label, value }[]A key/value data table

createNativeResponse

import { createNativeResponse } from '@devchitchat/chatopsjs'

createNativeResponse({
  fallbackText: string,    // Shown by adapters that don't match the provider
  provider:     string,    // Provider name: 'slack' | 'discord' | etc.
  payload:      object     // Provider-native payload object
})
// Returns: { text: string, native: { provider, payload } }

Context (ctx)

The context object is passed to command handlers and middleware:

{
  envelope: Envelope,       // The original inbound message envelope
  command:  Command,        // The resolved Command instance
  args:     object,         // Parsed argument key/value pairs
  adapter:  Adapter,        // The active Adapter instance

  storage: {
    get(key: string): Promise<any>,
    set(key: string, value: any): Promise<void>
  },

  state:   object,          // Mutable per-invocation state for middleware

  robot:   Robot,           // The Robot instance

  meta: {
    adapter:       string,  // Adapter name ('cli', 'discord', etc.)
    correlationId: string   // Unique UUID for this invocation
  }
}

Middleware Signature

robot.use(async (ctx, next) => {
  // Before handler: mutate ctx.state, add logging, etc.
  await next()
  // After handler: inspect result, record metrics, etc.
})

Envelope

Passed to robot.receive() by adapters. Describes an inbound message:

{
  adapter:  string,          // Adapter name — must match a registered adapter
  type:     'message',       // Message type
  text:     string,          // Command text (prefix already stripped by adapter)

  actor: {
    id:          string,     // User / actor identifier
    permissions: string[]    // Permission grants for this actor
  },

  channel: {
    id:      string,         // Channel / room identifier
    guildId?: string         // Optional — guild/workspace ID
  },

  correlationId?: string,    // Optional — auto-generated UUID if omitted
  confirmation?: {
    approved: true           // Set by adapter when user confirms a pending command
  }
  // Any additional adapter-specific fields are passed through transparently
}

receive() Result

robot.receive(envelope) always resolves to a structured result object:

{
  ok: boolean,

  // Present when ok === true:
  response?: { text, blocks?, native? },
  command?:  { id, aliasUsed },
  context?:  object,

  // Present when ok === false:
  error?: {
    code:     string,
    message?: string,
    errors?:  object[]    // Validation errors
  },

  // Present when confirmation is pending:
  confirmation?: { commandId: string },

  meta: {
    adapter:       string,
    correlationId: string
  }
}

Error Codes

CodeMeaning
unknown_commandNo command matched the input text
validation_failedRequired arguments are missing or invalid
permission_deniedActor lacks a required permission
confirmation_requiredCommand is awaiting user confirmation
confirmation_cancelledUser responded no to a confirmation prompt

Registries

CommandRegistry

// Available as robot.commands
robot.commands.register(command: Command): void
robot.commands.resolve(name: string): Command | undefined
robot.commands.list(): Command[]

AdapterRegistry

// Available as robot.adapters
robot.adapters.add(adapter: Adapter): void
robot.adapters.get(name: string): Adapter | undefined

ListenerRegistry

// Available as robot.listeners
robot.listeners.register(pattern: RegExp, handler: async (envelope, match) => void): void
robot.listeners.list(): { pattern, handler }[]
robot.listeners.match(text: string): { pattern, match }[]

Utilities

parseProgramArgs(argv)

import { parseProgramArgs } from '@devchitchat/chatopsjs'

// Parses process.argv-style array for --adapter / -a flags
const args = parseProgramArgs(process.argv.slice(2))
// { adapter: './path/to/adapter.js', ... }

normalizeCommandName(name, options)

import { normalizeCommandName } from '@devchitchat/chatopsjs'

normalizeCommandName('!deploy', { prefix: '!' })
// → 'deploy'

normalizeCommandName('Deploy', {})
// → 'deploy'