Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
96 commits
Select commit Hold shift + click to select a range
cae436a
feat(01-01): add blocks to message types and wire through data pipeline
tyom Feb 15, 2026
bebb702
feat(01-01): fix block action payloads and view submission type discr…
tyom Feb 15, 2026
506c1e2
feat(01-02): add blocks to UI types, state, and SSE handler
tyom Feb 15, 2026
1f024c6
feat(01-02): render BlockKit in messages and wire block action callbacks
tyom Feb 15, 2026
152ca01
fix(01): parse JSON-encoded form fields and fix static_select view_su…
tyom Feb 15, 2026
2e23306
feat(02-01): rewrite renderMrkdwn with slack-markdown + DOMPurify and…
tyom Feb 15, 2026
72602f2
refactor(02-01): unify all mrkdwn consumers to use shared renderMrkdwn
tyom Feb 15, 2026
e5caf51
fix(02): resolve TypeScript errors and CSS conflicts in Message.svelte
tyom Feb 15, 2026
0dedcfa
fix(02): improve mrkdwn rendering — lists, code blocks, block-level m…
tyom Feb 15, 2026
76f970d
feat(quick-01): create @botarium/mrkdwn package with mrkdwnToHtml and…
tyom Feb 15, 2026
3034502
feat(quick-01): swap UI to @botarium/mrkdwn and remove slack-markdown
tyom Feb 15, 2026
28b4abd
fix(quick-1): replace \x00 control chars with Unicode PUA placeholder…
tyom Feb 15, 2026
e51f1ee
fix(quick-1): point @botarium/mrkdwn export to source for Vite resolu…
tyom Feb 15, 2026
9d5dfed
fix(quick-1): improve markdownToMrkdwn — nested lists, task lists, ta…
tyom Feb 15, 2026
9db8567
fix(quick-1): render Markdown tables as code blocks in mrkdwn conversion
tyom Feb 15, 2026
e6577e7
docs: add README for @botarium/mrkdwn package
tyom Feb 15, 2026
150f71a
fix: prevent CSS br+br rule from hiding single line breaks in messages
tyom Feb 15, 2026
c2bbb55
feat(03-01): add all Phase 3 type definitions
tyom Feb 15, 2026
3ca1855
feat(03-01): build OverflowMenu and RadioButtonGroup with block wirin…
tyom Feb 15, 2026
36fb884
feat(03-02): add NumberInput, EmailInput, and UrlInput components
tyom Feb 15, 2026
10df3e0
feat(03-02): wire typed inputs and radio buttons into modal form flow
tyom Feb 15, 2026
1fe03f0
feat(03-03): add ConfirmDialog composition object component
tyom Feb 15, 2026
ec04c7b
feat(03-03): retrofit confirm dialog onto all interactive elements
tyom Feb 15, 2026
0e75a13
fix(03-01): use fixed positioning for overflow dropdown to prevent cl…
tyom Feb 15, 2026
8f3412a
feat(04-01): add date/time picker types and components
tyom Feb 15, 2026
3cba353
feat(04-01): wire date/time pickers into blocks, modal, dispatch, and…
tyom Feb 15, 2026
8822f02
feat(04-02): add DateTimePicker composed Calendar + TimeField component
tyom Feb 15, 2026
0235438
feat(04-02): wire DateTimePicker into actions blocks, input blocks, a…
tyom Feb 15, 2026
d0479c5
fix(04-03): fix calendar dropdown clipping and add compact sizing
tyom Feb 15, 2026
aa37b2b
feat(04-03): convert TimePicker to popover+Done commit pattern
tyom Feb 15, 2026
a724c66
fix: constrain message content width to match Slack layout
tyom Feb 15, 2026
ed59a76
fix: persist BlockKit blocks across emulator restarts
tyom Feb 15, 2026
e106ef7
feat(05-01): wire checkboxes into actions blocks, section accessories…
tyom Feb 15, 2026
17b8b28
feat(05-02): scaffold showcase bot and register in bots.json
tyom Feb 15, 2026
d3c827f
feat(05-01): add showcase channel with hidden input bar
tyom Feb 15, 2026
cb4d253
feat(05-02): add infrastructure modules and command handler stub
tyom Feb 15, 2026
df4e0da
feat(05-02): create showcase message payloads and wire command handler
tyom Feb 15, 2026
44a073f
feat(05-03): add block_actions echo handler and view_submission handler
tyom Feb 15, 2026
200c8f3
feat(05-03): add /showcase modal with all 9 input element types
tyom Feb 15, 2026
d0dc86b
feat(05-05): add deleteMessageByChannelAndTs method to EmulatorState
tyom Feb 16, 2026
d0101d5
feat(05-06): add getBotByToken lookup method to EmulatorState
tyom Feb 16, 2026
62b6796
feat(05-05): add chat.delete endpoint to emulator web API
tyom Feb 16, 2026
1eec617
feat(05-04): auto-populate showcase channel on bot startup
tyom Feb 16, 2026
7d297c0
fix(05-06): target interactive dispatch to specific bot instead of br…
tyom Feb 16, 2026
14494d8
fix: target slash command dispatch to owning bot and fix chat.delete
tyom Feb 17, 2026
532fe16
feat(quick-2): re-enable InputBar in showcase channel
tyom Feb 17, 2026
569c155
feat(quick-2): restructure /showcase into subcommands with help
tyom Feb 17, 2026
cf58489
feat: add chat.postEphemeral support with Slack-style ephemeral UI
tyom Feb 17, 2026
0e38e74
feat: extract Block Kit showcase messages into JSON files and improve…
tyom Feb 18, 2026
afdba01
feat(quick-3): add rich_text block type support with all sub-element …
tyom Feb 18, 2026
71117c3
fix: match Slack's rich_text spacing with block-level spacer spans
tyom Feb 18, 2026
f954d63
fix: refine block spacing and section block styles to match Slack
tyom Feb 18, 2026
bd1617e
fix: refine Block Kit element rendering and move max-width to block l…
tyom Feb 18, 2026
8972e9c
feat: add kitchen sink showcase message and fix newsletter action_ids
tyom Feb 18, 2026
b91fb56
feat: send help text to bot DM on startup and add showcase-bot README
tyom Feb 18, 2026
a80f79b
feat(quick-4): thread onImagePreview callback through Block Kit compo…
tyom Feb 18, 2026
f90a4ff
feat(quick-4): add user name to image preview modal and pass through …
tyom Feb 18, 2026
1315c38
fix: add author details (avatar, timestamp, channel) to image preview…
tyom Feb 18, 2026
f0ad07b
fix: add 30px inset padding and rounded corners to image preview modal
tyom Feb 18, 2026
54105dd
fix: limit image preview to standalone image blocks only
tyom Feb 18, 2026
34af83e
fix: stack author name and timestamp on separate lines in image preview
tyom Feb 18, 2026
886839f
fix: constrain zoomed image panning to dialog panel bounds
tyom Feb 18, 2026
047390b
fix: pad small zoomed images from panel edges, allow large images to …
tyom Feb 18, 2026
64ba99e
feat: add workspace select menu types (users, conversations, channels…
tyom Feb 19, 2026
e760b71
feat: add images showcase message
tyom Feb 19, 2026
745585a
feat(quick-5): add table block type with types, component, and render…
tyom Feb 19, 2026
f38a515
feat(quick-5): enhance showcase table with multi-column, multi-row co…
tyom Feb 19, 2026
f1e19d3
fix: match table block styling to real Slack (content-width, no hover…
tyom Feb 19, 2026
c8797d6
fix: remove #random channel from emulator
tyom Feb 19, 2026
381e7ec
fix: deduplicate bot DM help message across restarts
tyom Feb 19, 2026
869d819
feat(quick-6): add backend channel persistence and REST API endpoints
tyom Feb 19, 2026
413acea
feat(quick-6): add frontend channel management UI with add/remove/per…
tyom Feb 19, 2026
0907cdc
feat: add Messages tab to channel header matching real Slack
tyom Feb 19, 2026
8feb5c0
feat: replace inline channel input with Create Channel modal and add …
tyom Feb 19, 2026
b766bb9
style: format codebase with bun format
tyom Feb 19, 2026
90a610d
fix: resolve lint warnings, type errors, and a11y issues
tyom Feb 19, 2026
6ab6a17
feat: add context_actions block type for AI-assistant-style action bu…
tyom Feb 19, 2026
96ff854
feat: add emoji hover popover showing large preview and shortcode
tyom Feb 19, 2026
28cc3f5
fix: adjust context block font size and constrain divider width
tyom Feb 19, 2026
58ec171
fix: use span-based line breaks instead of br for CSS-controllable sp…
tyom Feb 19, 2026
5f06f7a
feat: add day separator between messages from different dates
tyom Feb 19, 2026
22927e3
feat: add bot about header at top of DM conversations
tyom Feb 19, 2026
814abdd
fix: resolve svelte-check error and formatting in MessagePanel
tyom Feb 19, 2026
1c39995
fix: address code review findings across security, bugs, and robustness
tyom Feb 19, 2026
89c9f4c
fix: address code review findings from CodeRabbit
tyom Feb 19, 2026
8de19e8
fix: address code review findings across multiple packages
tyom Feb 19, 2026
5ad4919
fix: fix race condition in ImageBlock and falsy class in StaticSelect
tyom Feb 19, 2026
da44c7d
fix: align GroupDefinition interface with UI schema
tyom Feb 19, 2026
965b5a8
fix: fix confirm dialog state, timestamp validation, and async delete…
tyom Feb 19, 2026
3f8bd8b
fix: sanitize mrkdwn link labels, blockquote detection, and channel o…
tyom Feb 19, 2026
d00d623
fix: fix table border wrapping and content-width sizing
tyom Feb 19, 2026
a20c4d8
fix: handle input block actions and sanitize mrkdwn link labels
tyom Feb 20, 2026
0f60c0f
docs: add CLAUDE.md for Claude Code guidance
tyom Feb 20, 2026
b58bda4
fix: reset datetimepicker draft state on dismiss and normalize empty …
tyom Feb 20, 2026
ed52a90
Fix format
tyom Feb 20, 2026
c45a7dc
docs: add missing commas in CLAUDE.md packages/core description
tyom Feb 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## What is Botarium

Botarium is a local Slack bot development simulator. Build, test, and debug Slack bots entirely on your machine without deploying to real Slack.

- Emulator app that runs in the browser or as a native desktop app (Electron)
- CLI tools to scaffold bots from scratch
- Development tools: persistence layer, Slack mrkdwn converter, and AI integration

## Commands

```sh
bun run dev # Start web UI dev server (Vite, port 5173)
bun run dev:electron # Start desktop app (Electron + Vite + emulator)
bun run build # Build all packages and apps
bun run test # Run all tests (bun test)
bun test <file> # Run a single test file
bun run check # typecheck + format:check + lint (CI runs this)
bun run typecheck # TypeScript check across all workspaces
bun run lint # ESLint
bun run format # Prettier (write)
bun run cli create # Scaffold a new bot interactively
```

Run the emulator standalone: `bun run packages/slack/src/server/index.ts`

## Architecture

Bun monorepo with workspaces in `apps/` and `packages/`.

### Packages

- **`packages/core`** — Plugin system and CLI entry point. Defines the `BotariumPlugin` interface that platform plugins implement (`createEmulator`, `defaultPort`, `envVarName`). Currently, only Slack is implemented, but the design supports adding other platforms.
- **`packages/slack`** — Slack API emulator. A Bun HTTP + WebSocket server that implements Slack Web API endpoints, Socket Mode protocol, SSE event broadcasting to the frontend, and optional SQLite persistence. Key files: `server/state.ts` (in-memory state), `server/web-api.ts` (API handlers), `server/socket-mode.ts` (WebSocket protocol), `server/persistence.ts` (SQLite).
- **`packages/mrkdwn`** — Bidirectional converters: Slack mrkdwn to HTML (for rendering in UI) and Markdown to mrkdwn (for AI responses). Uses `marked` for Markdown parsing.
- **`packages/create-bot`** — CLI tool (`create-botarium`) that scaffolds new bots via Handlebars templates in `templates/`.

### Apps

- **`apps/ui`** — Svelte 5 + Tailwind CSS 4 chat interface. Uses Svelte 5 runes (`$state`, `$derived`, `$effect`) for reactivity. Key state files: `lib/state.svelte.ts` (reactive UI state), `lib/dispatcher.svelte.ts` (SSE connection to emulator, API calls), `lib/backend-state.svelte.ts` (Electron IPC bridge). Uses `$lib` path alias for `src/lib/`.
- **`apps/electron`** — Desktop wrapper. Manages emulator and bot child processes, provides IPC for settings (encrypted via OS keychain), and bundles everything into a native app.

### Data Flow

1. User types in UI → HTTP POST to emulator `/api/simulator/user-message`
2. Emulator creates Slack event → sends via WebSocket (Socket Mode) to connected bot
3. Bot processes event → calls Slack Web API endpoints (e.g., `chat.postMessage`) on the emulator
4. Emulator broadcasts SSE event → UI updates reactively

## Code Style

- No semicolons, single quotes, trailing commas (es5) — enforced by Prettier
- `{@html}` is intentionally used in Svelte for mrkdwn rendering (ESLint rule disabled)
- Prefix unused variables with `_`
- Svelte components use runes (`$state`, `$derived`, `$effect`), not legacy stores
- TypeScript strict mode with `noUncheckedIndexedAccess`

## Testing

Tests use Bun's built-in test runner (`bun:test`). Test files are colocated with source as `*.test.ts`. Main test areas:

- `packages/mrkdwn/src/` — mrkdwn/HTML conversion tests
- `packages/create-bot/src/` — scaffold and template utility tests
- `apps/ui/src/lib/` — UI state tests
7 changes: 6 additions & 1 deletion apps/electron/bots.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
{
"bots": []
"bots": [
{
"source": "../showcase-bot",
"name": "showcase"
}
]
}
95 changes: 95 additions & 0 deletions apps/showcase-bot/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# Showcase Bot

A Slack bot that populates a channel with [Block Kit](https://api.slack.com/block-kit) examples and echoes back interactive element payloads. Built with [@slack/bolt](https://slack.dev/bolt-js/) and [Bun](https://bun.sh).

## How it works

On startup (in simulator mode), the bot automatically posts a series of Block Kit messages to the `#showcase` channel. These messages demonstrate various block types and interactive elements. When a user interacts with any element, the bot responds with the raw action payload so you can inspect exactly what Slack sends.

### Block Kit samples

Message definitions live in `src/messages/blocks/` as numbered JSON files, loaded and posted in order:

| # | File | What it shows |
| --- | ---------------------------- | -------------------------------------------------------- |
| 01 | `text-and-layout.json` | Headers, sections, dividers, context, images |
| 02 | `button-variations.json` | Primary, danger, and default buttons |
| 03 | `selection-elements.json` | Static selects, multi-selects, overflow menus |
| 04 | `radio-and-checkboxes.json` | Radio buttons and checkbox groups |
| 05 | `date-and-time-pickers.json` | Date pickers, time pickers, datetime pickers |
| 06 | `section-accessories.json` | Buttons, selects, and overflows as section accessories |
| 07 | `combined-actions.json` | Multiple interactive elements in a single actions block |
| 08 | `rich-text.json` | Rich text with formatting, lists, quotes, code blocks |
| 09 | `template-newsletter.json` | A realistic newsletter-style message template |
| 10 | `kitchen-sink.json` | Mixed rich text, actions, selects, and feedback elements |

JSON files support template variables (`{{TODAY_DATE}}`, `{{TODAY_NOON_UNIX}}`) that are resolved at load time.

You can try pasting examples from Slack's [Block Kit Builder](https://app.slack.com/block-kit-builder) to show them in the emulator.

### Action responses

All interactive elements use action IDs prefixed with `showcase_`. A single catch-all handler matches this prefix:

```js
app.action(/^showcase_/, ...)
```

When triggered, the handler acknowledges the action and posts a reply containing the action type, action ID, and the full JSON payload. This makes it easy to see exactly what data each interactive element produces.

Modal submissions (callback ID `showcase_modal`) are handled the same way -- the bot posts the `view.state.values` back to the channel.

### Slash command

The bot registers a `/showcase` command with the following subcommands:

| Subcommand | Description |
| ---------- | -------------------------------------------------------- |
| `generate` | Clear and re-populate `#showcase` with all block samples |
| `clear` | Remove all messages from `#showcase` |
| `modal` | Open a modal with various input elements |
| `help` | Show available subcommands |

## Running

```sh
# With the Botarium simulator
bun run dev:local

# With real Slack credentials
SLACK_BOT_TOKEN=xoxb-... SLACK_APP_TOKEN=xapp-... bun run dev
```

### Environment variables

| Variable | Required | Description |
| ---------------------- | ---------------- | --------------------------------------------------------------- |
| `SLACK_BOT_TOKEN` | Yes (production) | Bot user OAuth token |
| `SLACK_APP_TOKEN` | Yes (production) | App-level token for Socket Mode |
| `SLACK_SIGNING_SECRET` | Yes (production) | Signing secret for request verification |
| `SLACK_API_URL` | No | Set automatically in simulator mode |
| `BOT_NAME` | No | Display name (default: `Showcase Bot`) |
| `PORT` | No | Server port (default: `3000`) |
| `LOG_LEVEL` | No | `silent`, `debug`, `info`, `warn`, or `error` (default: `info`) |

In simulator mode, token and secret values are generated automatically.

## Project structure

```text
src/
app.ts # Entry point, Bolt app setup, startup sequence
settings.ts # Environment variable validation (zod)
config/
loader.ts # Bot configuration loader
http-server.ts # Config server for simulator registration
listeners/
index.ts # Registers commands and actions
commands/showcase.ts # /showcase command and message posting
actions/showcase-actions.ts # block_actions and view_submission handlers
messages/
showcase-messages.ts # Loads and templates block JSON files
blocks/*.json # Block Kit message definitions
utils/
logger.ts # Pino logger setup
```
Empty file added apps/showcase-bot/bunfig.toml
Empty file.
42 changes: 42 additions & 0 deletions apps/showcase-bot/config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Showcase Bot Configuration
# Sends categorized Block Kit example messages for visual verification.

# Simulator-specific configuration (not sent to Slack)
simulator:
id: showcase # Isolates DM messages per-bot in the simulator

# Slack app configuration
slack:
commands:
- command: /showcase
description: Block Kit showcase commands
usage_hint: '[generate|clear|modal|help]'
shortcuts: []
actions: {}
modals:
showcase_modal: showcase_modal

# Settings with schema metadata for UI generation
settings:
bot_name:
value: Showcase Bot
schema:
type: string
label: Bot Name
description: Display name for the bot in conversations
group: bot
required: true

bot_description:
value: Sends categorized Block Kit example messages for visual verification.
schema:
type: string
label: Bot Description
description: Short description shown in the DM about section
group: bot

# Group definitions with display order
groups:
- id: bot
label: Bot Configuration
order: 1
26 changes: 26 additions & 0 deletions apps/showcase-bot/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"name": "showcase-bot",
"version": "0.1.0",
"description": "Block Kit showcase bot for Botarium",
"type": "module",
"private": true,
"scripts": {
"start": "bun run src/app.ts",
"dev": "bun --watch run src/app.ts",
"dev:local": "SLACK_API_URL=http://localhost:7557 bun --watch run src/app.ts",
"typecheck": "tsc --noEmit",
"test": "echo 'No tests yet'"
},
"dependencies": {
"@slack/bolt": "^4.6.0",
"@slack/types": "^2.15.0",
"@slack/web-api": "^7.10.0",
"pino": "^10.1.0",
"zod": "^4.3.5"
},
"devDependencies": {
"@types/bun": "^1.3.6",
"pino-pretty": "^13.1.3",
"typescript": "^5"
}
}
Loading