Skip to content
25 changes: 22 additions & 3 deletions RUNEWAGER_FUNCTIONALITY_MAP.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# RUNEWAGER_FUNCTIONALITY_MAP.md

_Last audited: 2026-02-28_
_Last audited: 2026-02-28 (v3.1 pass)_
_Source of truth files: `index.js`, `test/*.test.js`, scripts under `scripts/`, deployment/runtime docs in repo root._

---
Expand Down Expand Up @@ -48,6 +48,8 @@ Navigation is driven by inline menus plus command aliases. Persistent user/admin
- Many menu-style responses use `replaceCallbackPanel(...)` to avoid stale stacked cards.
- Single active menu rule: `clearOldMenus(ctx)` + menu send helpers keep only one active transient menu card per user/chat.
- `to_main_menu` clears transient menu cards via `clearOldMenus(...)` before rendering persistent menu headers.
- **Group command guard middleware** intercepts commands sent in group/supergroup chats. Commands that have their own group-specific handling (`link`, `linkrunewager`, `giveaway`, `start_giveaway`, `admin`) pass through. All other commands receive a "💬 This command works in DM" response with a deep-link button; the command handler is suppressed. This prevents onboarding, settings, promo, and other DM flows from executing in group chats.
- **`GROUP_PASSTHROUGH_COMMANDS`** set defines which commands bypass the group guard; it does NOT restrict admin access or callback queries.

## 4. User Menu Tree

Expand Down Expand Up @@ -86,7 +88,8 @@ Navigation is driven by inline menus plus command aliases. Persistent user/admin
- TestAll engine (`/testall`) runs structured diagnostics across environment, data/stores, callbacks/commands, navigation helpers, giveaway/promo/helpful-tooltips, SSHV, pendingAction timeout/label rules; summary line: `TestAll complete — X passed, Y warnings, Z failures.`
- `admin_cat_giveaway`: start/test/status + persistent navigation row (`Admin Dashboard`, `Main Menu`, `Cancel`).
- `admin_cat_promo`: full promo manager actions + guide + persistent navigation row (`Admin Dashboard`, `Main Menu`, `Cancel`).
- `admin_cat_system`: health/version/verify/setup/backup/admin mode/testall/sshv + persistent navigation row (`Admin Dashboard`, `Main Menu`, `Cancel`).
- `admin_cat_system`: health/version/verify/setup/backup/admin mode/testall/sshv + **🔗 Group Linking** (v3.1 — opens group linking tools with return to System Tools) + persistent navigation row (`Admin Dashboard`, `Main Menu`, `Cancel`).
- `admin_sys_group_linking` callback renders the group linking panel (`renderGroupLinkingTools`) with `admin_cat_system` as the back target.
- `admin_cat_tests`: bug tools + test tools + sshv shortcut + return navigation controls.
- `admin_cat_support`: bug report management shortcuts + persistent navigation row (`Admin Dashboard`, `Main Menu`, `Cancel`).

Expand Down Expand Up @@ -150,13 +153,27 @@ The bot uses `user.pendingAction.type` as its input state machine. Key families:
5. Community join prompts (channel/group flags).
6. Walkthrough progression tracking (`user.walkthrough`, onboarding milestones).

**Progress Indicator (v3.1+):**
- `onboardingProgressBar(step)` renders a visual dot bar: `●●○○○ Step 2 of 5 — Link Runewager`.
- `showOnboardingPrompt(ctx, user, step)` sends the progress bar as a Markdown message (auto-deletes after 8s) before each step-specific prompt.
- `user.onboarding.completionCardShown` — boolean, defaults `false`. Set to `true` on first main-menu arrival after completion.
- **Completion card** is shown once, the first time the user reaches the main menu after completing all 5 steps: friendly welcome, feature summary, and a "🎮 Open Menu" button.

Recovery:
- `confirm_no_username` returns to username entry.
- `/stuck` and `/fixaccount` provide guided recovery paths.

## 10. Group Commands

Group-aware commands include giveaway interaction and linking shortcuts:
**Group command guard (v3.1+):** All bot commands sent in a group/supergroup are intercepted by middleware and redirected to DM. Passthrough exceptions (have their own group logic):
- `/link` / `/linkrunewager` — accepts inline username argument, acknowledges in group, continues in DM.
- `/giveaway` — shows active giveaways for that group; admin can start a new one.
- `/start_giveaway` — admin-only wizard in the group context.
- `/admin` — sends brief DM-launch button in group.

All other commands (menu, settings, promo, bonus, profile, help, status, etc.) receive: "💬 This command works in DM. Tap below..." with a direct DM deep-link. The command handler is suppressed (next() not called).

Group-aware commands also include giveaway interaction and linking shortcuts:
- `/giveaway` (admin wizard in group context).
- `/join` and `gw_join_<id>` for participant entry.
- `/eligible [id]` checks eligibility.
Expand Down Expand Up @@ -384,3 +401,5 @@ Mandatory rules for any AI agent touching this repo:
- 2026-02-26: Added deterministic 30 SC user submenu (`How It Works`, `Check My Eligibility`, `Request My Bonus`, `Check Bonus Status`) and Admin submenu (`View Pending Requests`, `Approve Bonus`, `Deny Bonus`, `View User History`, `Reset Attempts`) with manual-review copy and admin action logging to `/var/www/html/Runewager/logs/bonus_admin.log`.
- 2026-02-27: Added QA tester scaffolding (`qa/context/bot_capabilities.json`, `qa/context/repo_info.json`, `qa/state/provider_status.json`, `qa/README_QA.md`), with runtime refresh via `/qa_*` commands and 10-minute provider cooldown reset.
- 2026-02-27: Hardened SSHV Run prompt flow so admin text in private DM executes against active SSHV sessions if pending state desynchronizes.
- 2026-02-28: v3.1 — added group command guard middleware (`GROUP_PASSTHROUGH_COMMANDS` + `bot.use` interceptor); added `onboardingProgressBar()` and progress header on each onboarding step prompt (auto-deletes after 8s); added one-time onboarding completion card (tracked via `user.onboarding.completionCardShown`); added `🔗 Group Linking` to Admin System Tools keyboard (`admin_sys_group_linking` callback with back-to-system-tools navigation).
- 2026-02-28: PR #112 review + audit pass — fixed 10 issues: (R1) `await_tip_import_batch` dedicated pending type with JSON-array router; (R2) `generate_tooltips.sh` command-substitution pollution fixed via `RUNEWAGER_APP` env var; (R3) `add_tooltip.sh` shell-injection fixed via `TOOLTIP_TEXT_ENV`/`TOOLTIP_TMP_FILE` env vars and `<<'EOF'`; (R4) `catchAllCases` test extended with multiline patterns + `CATCH_ALL_CORES` updated; (R5) `extractCommandHandlerNames` test extended with `let`/`var`/no-semicolon fixtures; (R6) typo "auto-deletes 8s" → "auto-deletes after 8s"; (A1) dead `buildGiveawayAnnouncementText(giveaway,remainingStr)` removed; (A2) simplified `buildGiveawayAnnouncementKeyboard` with wrong callback removed; (A3+A4) duplicate `bot.action('admin_cat_system')` and `bot.action('admin_cat_support')` first registrations removed. All 60 tests pass.
11 changes: 7 additions & 4 deletions add_tooltip.sh
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,17 @@ node -e "JSON.parse(require('fs').readFileSync('$TOOLTIPS_FILE','utf8'))" 2>/dev
TOOLTIP_TEXT="${CUSTOM_TEXT:-New tooltip — edit in admin panel via /tips.}"

# Append new entry and get new ID using Node.js
NEW_ID=$(node - "$TOOLTIPS_FILE" <<EOF
# Text and tmp path are passed via env vars to avoid shell injection on special characters
NEW_ID=$(TOOLTIP_TEXT_ENV="$TOOLTIP_TEXT" TOOLTIP_TMP_FILE="$TMP_FILE" node - "$TOOLTIPS_FILE" <<'EOF'
const fs = require('fs');
const file = process.argv[1];
const file = process.argv[2];
const text = process.env.TOOLTIP_TEXT_ENV;
const tmpFile = process.env.TOOLTIP_TMP_FILE;
const list = JSON.parse(fs.readFileSync(file, 'utf8'));
const maxId = list.reduce((m, t) => Math.max(m, Number(t.id) || 0), 0);
const newId = maxId + 1;
list.push({ id: newId, text: $(node -e "process.stdout.write(JSON.stringify('$TOOLTIP_TEXT'))"), enabled: true });
fs.writeFileSync('${TMP_FILE}', JSON.stringify(list, null, 2));
list.push({ id: newId, text, enabled: true });
fs.writeFileSync(tmpFile, JSON.stringify(list, null, 2));
console.log(newId);
EOF
)
Comment thread
sourcery-ai[bot] marked this conversation as resolved.
Expand Down
5 changes: 2 additions & 3 deletions generate_tooltips.sh
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ if [[ ! -f "$APP_DIR/index.js" ]]; then
fi

info "Extracting DEFAULT_TIPS_LIST from index.js..."
TOOLTIP_JSON=$(node - <<'EOF'
TOOLTIP_JSON=$(RUNEWAGER_APP="$APP_DIR/index.js" node - <<'EOF'
const fs = require('fs');
const src = fs.readFileSync(process.argv[1] || 'index.js', 'utf8');
const src = fs.readFileSync(process.env.RUNEWAGER_APP || 'index.js', 'utf8');
// Execute just the DEFAULT_TIPS_LIST block and print it as JSON
const m = src.match(/const DEFAULT_TIPS_LIST\s*=\s*(\[[\s\S]+?\]);/);
if (!m) { process.stderr.write('DEFAULT_TIPS_LIST not found\n'); process.exit(1); }
Expand All @@ -46,7 +46,6 @@ try {
console.log(JSON.stringify(list, null, 2));
} catch (e) { process.stderr.write('Parse error: ' + e.message + '\n'); process.exit(1); }
EOF
node "$APP_DIR/index.js" --version 2>/dev/null || true
) || {
# Fallback: emit a minimal valid tooltips.json with a placeholder
warn "Could not extract tooltips from index.js — writing placeholder."
Expand Down
Loading