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

  1. Install Node.js and pnpm using your preferred method for your OS.

  2. Install dependencies:
    pnpm install

  3. Copy and edit the environment file:
    cp .env.example .env
    Edit .env with your editor of choice.

  4. Provide Google service account credentials for Sheet-backed commands (see below).

  5. Build and run:
    pnpm run build
    pnpm start

  6. Or run under PM2 using the repo’s ecosystem file:
    pm2 start ecosystem.config.cjs

  7. 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 encrypt to encrypt your local .env when you want it safe to commit.
  • That flow also creates a .env.keys file with your private encryption key, which must never be committed.
  • To change variables, use pnpm dlx dotenvx decrypt with the key in .env.keys to 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.