// bot.js
import { Bot, defineBot, isMainModule, MemoryStore, slashCommandsPlugin } from '@botmesh/core'
import { BaileysProvider } from '@botmesh/baileys'
// Stand-in for your order API
const ORDERS = {
A100: { item: 'Blue sneakers', status: '🚚 On its way', eta: 'Thursday' },
B200: { item: 'Rain jacket', status: '📦 Being packed', eta: 'next week' },
C300: { item: 'Wool socks', status: '✅ Delivered', eta: 'already there' },
}
const findOrder = (code) => ORDERS[code.trim().toUpperCase()]
const createBot = defineBot((provider) => {
// A store saved to a file: profiles survive a restart (use SQLite or Redis in production)
const bot = new Bot({ provider, store: new MemoryStore({ file: './orders.json' }) })
bot.plug(slashCommandsPlugin, {
greeting: '📦 Send "track" to follow an order, "my orders" to list them. /forget clears your data.',
})
// 1. A conversation that reads and writes the user's profile (ctx.user)
bot.conversation(
'track',
async (c, ctx) => {
const orders = ctx.user.ns('orders') // a namespace just for this feature
const last = await orders.get('last')
// 2. Per-user memory: offer the last order instead of asking again
let code
if (last && (await c.choose(`Track ${last} again?`, { yes: `Yes, ${last}`, other: 'Another order' })) === 'yes') {
code = last
} else {
const answer = await c.ask('What is your order number? (e.g. A100)', {
validate: (body) => (findOrder(body) ? true : '🔎 I cannot find that order. Check the number and try again.'),
maxAttempts: 3,
})
code = answer.trim().toUpperCase()
}
// 3. Remember it: the last order and every order this user follows
const followed = (await orders.get('followed')) ?? []
await orders.update({ last: code, followed: followed.includes(code) ? followed : [...followed, code] })
const order = findOrder(code)
await c.say(`${order.status}\n${code} · ${order.item}\nArrives: ${order.eta}`)
},
{ trigger: ['track', 'where is my order'] },
)
bot.when('my orders', async (ctx) => {
const followed = (await ctx.user.ns('orders').get('followed')) ?? []
if (followed.length === 0) return ctx.reply('You are not following any order yet. Send "track".')
await ctx.reply(followed.map((code) => `• ${code}: ${findOrder(code).status}`).join('\n'))
})
// 4. Let the user erase what the bot remembers about them
bot.command('forget', async (ctx) => {
await ctx.user.ns('orders').clear()
await ctx.reply('🧹 Done, I forgot your orders.')
})
bot.onMessage((ctx) => ctx.reply('Send "track", "my orders" or /help.'))
return bot
})
export default createBot
// `node bot.js` connects to WhatsApp; `npx botmesh dev bot.js` skips this block
if (isMainModule(import.meta)) {
const bot = await createBot(new BaileysProvider({ session: 'orders-bot' }))
bot.on('ready', () => console.log('✅ Connected'))
await bot.start()
// Ctrl+C: stop the bot so the store writes orders.json before exiting
process.once('SIGINT', async () => {
await bot.stop()
process.exit(0)
})
}