Installation
TC-Bot is the Ark of War Theorycrafter bot: Discord slash commands for gear stats, troop healing costs, Ignore Tier Suppression math, mopup timing, plus utilities like ping, help, metrics inspection, and controlled reboot - aimed at the Diplomacy of War server and anyone who wires their own guild and spreadsheet.
Requirements
- Node.js 25+
- pnpm 11+
Setup
- Install Node.js and pnpm using your preferred method for your OS.
- Install dependencies:
pnpm install - Copy and edit the environment file:
cp .env.example .env
Edit.envwith your editor of choice. - Provide Google service account credentials for Sheet-backed commands (see below).
- Build and run:
pnpm run buildpnpm start - Or run under PM2 using the repo’s ecosystem file:
pm2 start ecosystem.config.cjs - Register slash commands with Discord (required after adding or changing commands):
pnpm run deploy
dotenvx and encrypted env files
This project supports dotenvxfor local .env loading and can optionally use encrypted env artifacts.
- Use
pnpm dlx dotenvx encryptto encrypt your local.envwhen you want it safe to commit. - That flow also creates a
.env.keysfile with your private encryption key, which must never be committed. - To change variables, use
pnpm dlx dotenvx decryptwith the key in.env.keysto restore a plain.env. - Re-encrypt afterward (keys are reused) and commit only the encrypted artifacts.
- Store private keys in your secrets manager the same way you would a deploy key.
Suggested secret naming when vault is enabled:
- DOTENV_PRIVATE_KEY_DEVELOPMENT
- DOTENV_PRIVATE_KEY_PRODUCTION
Use one key per environment to reduce blast radius.
Google service account credentials
Place client_secret.json in the project root (service account JSON from Google Cloud). The bot uses readonly spreadsheet scope. Unless you have access to the Theorycrafters sheet (or a compatible copy), healing and iTS-style commands will not return meaningful troop data.
Environment variables
| Variable | Description |
| -------------------------------- | --------------------------------------------------------------------------- |
| `TOKEN` | Discord bot token. |
| `CLIENT_ID` | Discord application client ID. |
| `GUILD_ID` | Guild ID for guild-scoped slash commands (see deploy script behavior). |
| `OCR_SPACEKEY` | OCR.space API key (if features using OCR are enabled). |
| `CHANNEL_ID1` | Mopup status channel ID. |
| `CHANNEL_ID2` | Mopup timer channel ID. |
| `ENABLE_LEGACY_MESSAGE_COMMANDS` | `true` / `1` to handle legacy `!tcmu` (requires extra gateway intents). |
| `MESSAGE_COMMAND_CHANNEL_ID` | Channel ID limiting legacy message commands when enabled. |
| `GOOGLE_SPREADSHEET_ID` | Theorycrafters Google Spreadsheet ID. |
| `GOOGLE_SHEET_ID` | Tab ID within that spreadsheet. |
| `GOOGLE_SHEET_CACHE` | Sheet row cache TTL (ms). |
| `SQLITE_DB_PATH` | Path to the SQLite metrics database. |
| `CHECKPOINT_INTERVAL_MS` | How often to checkpoint the metrics DB. |
| `METRICS_RETENTION_DAYS` | Rolling retention in days (`0` = keep indefinitely). |
| `METRICS_FLUSH_INTERVAL_MS` | Flush interval for the metrics queue. |
| `METRICS_FLUSH_BATCH_SIZE` | Batch size when flushing metrics. |
| `METRICS_MAX_QUEUE_LENGTH` | Max queued metric events before dropping. |
| `METRICS_MAX_RETRIES` | Max retries when flushing metrics fails. |
| `DEBUG` | Verbose debug logging (`true` / `false`). |Scripts
| Script | Description |
| ------------------- | ---------------------------------------------------------- |
| `pnpm run build` | Compile TypeScript to `dist/`. |
| `pnpm start` | Run the bot from `dist/`. |
| `pnpm run deploy` | Register slash commands with Discord. |
| `pnpm run lint` | Run Oxlint. |
| `pnpm run format` | Run Oxfmt. |
| `pnpm run validate` | Format check, lint, typecheck, and tests (project script). |
| `pnpm run test` | Run Vitest once. |
| `pnpm run test:watch` | Vitest in watch mode. |SQLite / metrics notes
Point SQLITE_DB_PATH at a persistent path in production (absolute paths inside containers are fine). The bot runs periodic WAL checkpointing and closes cleanly on SIGTERM/SIGINT; avoid sharing one metrics file across multiple bot processes unless you really know why.
