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

gear-roboto

v3.1.3

Published

a framework to facilitate the creation of chatbots

Readme

Gear-roboto

NodeJS TypeScript eventEmitter

gear-roboto is a mini framework for creating and organizing chatbot logic, allowing message transport message flow and event monitoring.

🚀 Installation

npm install gear-roboto

🔥 Usage Example

import { DefaultChatBot, DefaultCommander, CommandLineEngine, CommandLineTransporter } from "gear-roboto";

async function main() {
    const commander = new DefaultCommander(["!"]);
    commander.addCommand("hello", (engine, author) => engine.send(author, { text: "world", type: "text" }));
    
    const engine = new CommandLineEngine(commander);
    const transporter = new CommandLineTransporter();
    
    const chatbot = new DefaultChatBot(engine, transporter);
    await chatbot.init();
    chatbot.send("you", { type: "text", text: "Enter a command starting with !" });
}

main();

🛠 Main Structure

the main classes of the library such as transporters, engines and flows are child classes of the Gear class, a Gear has an event emitter to ensure communication between the gears managed by the chatbot.

Gear events: |event | description | |-------|----------------| |gear.connection.status | connection events | |gear.message.received| received message events| |gear.message.send | message sending request(flow) | |gear.flow.end |end flow in chat |

The DefaultChatbot class manages the engine events and their sending to the transporters, but its emitters can be accessed outside the chatbot, as occurs in flows, through the method inherited from Gear, the .getEmitter() method.


The library has four main classes:

  1. Commander – Manages the chatbot's commands.
  2. Engine – Controls external interactions.
  3. Transporter – Manages the transport of messages and events.
  4. Chatbot – Provides communication between the Engine and Transporter.
  5. flow – responsible for defining a conversation flow

🎯 Commander (Command Manager)

The Commander is responsible for managing the chatbot's commands. When instantiating it, you define a prefix for the commands:

const commander = new DefaultCommander(["/"]);

commander.addCommand("hello", (engine, author, args) => {
engine.send(author, { text: "world", type: "text" });
});

📌 The callback receives the parameters in the following order: engine, author, args

For the commands to be processed, the Commander needs to be injected into an Engine object:

const engine = new CommandLineEngine(commander);

Importing Commands from a Directory

commander.addCommandsByPath("path/commands");

Now you can automatically import commands from a directory in your project where .ts or .js files export a function implementing the CommanderFunction type.

This will load all .ts or .js files in the "commands" folder located in the project's root directory.

Example Command File (commands/hello.ts)

const helloCommand: CommanderFunction = async (engine, author, args) => {
    engine.send(author, { text: "Hello, world!", type: "text" });
};

export default helloCommand;

After calling addCommandsByPath("commands"), the command "hello" will be available automatically. 🚀


⚙️ Engine (Interaction Manager)

The Engine is responsible for handling external interactions. The base class DefaultEngine can be extended for different platforms.

The CommandLineEngine, for example, uses readline to interact with the user:

async monitoring() {
    const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
    while (this.status === 'connected') {
        const text = await rl.question("");
        const author = "you";
        this.getEmitter().emit('gear.message.received', { type: "text", author, text, isGroup: false });
        
        if (this.commander?.isCommand(text)) {
            const { command, args } = this.commander.extractCommandAndArgs(text);
            const fun = this.commander.searchCommand(command);
            fun ? fun(this, author, args) : this.send(author, { type: "text", text: "Comando não encontrado" });
        }
    }
    rl.close();
}

methods of Engine:

  • send(to: string, message: IMessageSend) – send message.
  • monitoring() – monitoring messages or other events.

🔄 Transporter (Message Transporter)

The Transporter manages the transport of events and can be extended to different platforms (RabbitMQ, WebSocket, Kafka, etc.).

Example with the CommandLineTransporter:

const transporter = new CommandLineTransporter();

🤖 Chatbot (General Manager)

The Chatbot class connects the Engine to the Transporter and allows you to send messages without accessing the Engine directly:

const chatbot = new CommandLineChatBot(engine, transporter);
await chatbot.init();
chatbot.send("you", { type: "text", text: "Enter a command starting with !" });

🔀 Message flow

Flows are responsible for emulating a conversation with the chatbot without relying on commands and also serve to store responses. The class responsible for managing a flow is DefaultFlow, the main methods of this class are:

  • start: start a flow.
  • addMessage: add a message in flow.
  • addMessages: add many messages in flow.
  • setFirstMessage: define the first message of flow.
  • setLastMessage: define the last message of flow.
  • getLastMessage: return the last message of flow.
  • getFirstMessage: return the first message of flow.
  • removeMessage: remove a message by id.

🎯 flow messages:

Structures that store and process responses have a special class, we use child classes of DefaultMessageFlow. StoreMessageFlow receives an array of IMessageSend that will be sent in sequence, the class and its children have a linked list logic, each object of the class has an id and a nextId of another object of the same class, the latter being able to be null, which would end the flow.

const flow = new DefaultFlow("test-flow");

const nameMessage = new StoreMessageFlow("YOUR_NAME", [{ type: "text", text: "what's your name?" }]); //define message
const ageMessage = new StoreMessageFlow("YOUR_AGE", [{type:"text",text:"great!"},{ type: "text", text: "how old are you?" }]);

nameMessage.setNextId(ageMessage.getId()) //set next message by id

flow.addMessage(nameMessage)
flow.addMessage(ageMessage)

flow.start()

So far there are 3 types of MessageFlow:

| Class | description | | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | StoreMessageFlow | basic class, just stores the response | | KeyWordMessageFlow | compares whether the response has any of the keywords, if yes, it points to the next message, if no, it points to the error message or ends the flow if it is the last message | | OptionMessageFlow | receives an object with options, the options can be numbers or strings, each option will point to a message of any type, if the response does not satisfy the options, the message is sent again informing the error |


🧩 practical use of MessageFlow classes

  • StoreMessageFlow:
    
    const nameMessage = new StoreMessageFlow("YOUR_NAME", [{ type: "text", text: "what's your name?" }]);
    flow.addMessage(nameMessage)
     
  • KeyWordMessageFlow:
      
    //keyword message
    const isRioPeopleMessage = new KeyWordMessageFlow("IS_RJ_PEOPLE", [{ type: "text", text: "Do you live in Rio de Janeiro?" }],["yes","yeah"]);
     
    //If the keywords are found in the response, the next message will be:
    const bestRestaurantInRioFromMessage = new StoreMessageFlow("BEST_RESTAURANT", [{ type: "text", text: "What is the best restaurant in Rio?" }]);
    isRioPeopleMessage.setNextId(bestRestaurantInRioFromMessage)
     
    //otherwise the next message will be:
    const whereAreYouFromMessage = new StoreMessageFlow("YOUR_CITY", [{ type: "text", text: "Oh... where are you from?" }]);
    isRioPeopleMessage.setNextErrorId(whereAreYouFromMessage)
      
    flow.addMessage(isRioPeopleMessage)
    flow.addMessage(bestRestaurantInRioFromMessage)
    flow.addMessage(whereAreYouFromMessage)
    
  • OptionMessageFlow:
    
    //define options:
    const opt1 = new StoreMessageFlow("1", [{ type: "text", text: "talk about number one:" }]);
    const opt2 = new StoreMessageFlow("2", [{ type: "text", text: "talk about number two:" }]);
    const opt3 = new StoreMessageFlow("3", [{ type: "text", text: "talk about number three:" }]);
    
    //define menu
    const menu = new OptionMessageFlow(
        "1",
        [{ type: "text", text: "choose a number between 1 and 3" }],
        [
            { key: 1, nextId: opt1.getId() },
            { key: 2, nextId: opt2.getId() },
            { key: 3, nextId: opt3.getId() },
        ],
        { text: "invalid option", type: "text" }
    );
    
    flow.addMessage(menu)
    flow.addMessages(opt1,opt2,opt3)
      
     

the first MessageFlow to be added to the flow is the first one to be sent right after sending the firstMessage

at the end of the flow, a gear.flow.end event will be fired to the transporter.

🎯 First and last messages in flow:

The last and the first messages are objects that implement the interface IMessageSend just like in the methods send in Engine and Chatbot. These messages will be sent at the beginning and end of a flow as a "greeting" and a "farewell", they are two optional parameters.


const flow = new DefaultFlow("test-flow");
flow.setFirstMessage({type:"text",text:"hello"});
flow.setLastMessage({type:"text",text:"bye bye"});

first and last messages don´t store response

init a flow in chatbot:

a flow can be initiated directly from the chatbot or by a CommanderFuncion passing through the engine;

  • in chatbot:
     
    chatbot.startFlow(to, flow)
  • in the engine via commander function:
     
     engine.startFlowInEngine(to, flow)

Examples:

📜 License

ISC © isaias-silva