Skip to content

Add admin VPS console, tips persistence, HTTPS health, safe path handling and admin UX improvements - #74

Merged
gamblecodezcom merged 3 commits into
mainfrom
codex/configure-git-and-update-project-files-ai9ul2
Feb 25, 2026
Merged

Add admin VPS console, tips persistence, HTTPS health, safe path handling and admin UX improvements#74
gamblecodezcom merged 3 commits into
mainfrom
codex/configure-git-and-update-project-files-ai9ul2

Conversation

@gamblecodezcom

@gamblecodezcom gamblecodezcom commented Feb 25, 2026

Copy link
Copy Markdown
Owner

User description

Motivation

  • Improve admin tooling (lightweight VPS console, session persistence, editor) and make admin UX safer and clearer.
  • Harden runtime file operations and health endpoint by adding path validation, atomic writes, and optional HTTPS for the internal health server.
  • Improve tips/helpful-messages management, persistence and scheduler behavior and add operational scripts/service updates for production VPS installs.

Description

  • Implemented a lightweight admin VPS console (/sshv) with per-admin sessions, editor mode, command execution, locking, confirmation for dangerous commands, persistence to data/sshv-sessions.json, GC of expired sessions, and many safer guards (sshv* helpers and callbacks).
  • Added helpful-messages (tips) import/export and persistence via data/helpful_messages.json, deterministic normalization, scheduler improvements to avoid repeating the last tip and to check posting permissions before sending.
  • Hardened filesystem operations with validateSafePath, atomic writeFileAtomic and safe loadJson that restricts I/O to the data directory and prevents path traversal.
  • Health server now supports optional HTTPS via HTTPS_KEY_PATH/HTTPS_CERT_PATH (with allowed dirs and safe resolution), and internal health checks (/health and /metrics) are requested over HTTP/HTTPS depending on config.
  • WebApp init-data verification changed to use WEBAPP_HMAC_KEY env var instead of a constant; .env.example updated to document WEBAPP_HMAC_KEY.
  • Admin UI and workflow changes: admin "view/mode" toggles (/on /off), persistent admin/user menus, ephemeral promo prompt, admin command list updates, safer requireAdmin checks and many callback/menu key name adjustments.
  • Tips manager: JSON import/export via /tipadd and /tipedit payloads, save/load helpers saveHelpfulMessages/loadHelpfulMessages, persist on changes, and UI changes for listing and indexing tips.
  • Deployment and packaging: removed Dockerfile, added LICENSE and SECURITY.md, updated prod-run.sh to create runtime data files and log paths, updated .gitignore and runewager.service to run as runewager user and tighten service sandboxing, and ensured logrotate includes admin event log.

Testing

  • Module load smoke test under CI guard: ran the runtime in CI mode (CI=true node index.js) to verify the module initializes without runtime errors (passed).
  • Health endpoint invocation tested via the new internal request helper using both HTTP and the configured HTTPS path check in automated startup scenario (internal smoke checks succeeded).
  • npm ci --omit=dev behavior exercised in the deployment script path to ensure data/log files are created as expected during installation (simulated run of prod-run.sh steps completed without errors).

Codex Task


CodeAnt-AI Description

Auto-expire ephemeral bonus prompt and ensure runtime directories/files on startup

What Changed

  • New ephemeral promo message for the new-user bonus is shown during onboarding and automatically removed after 15 seconds to keep chats tidy.
  • Opening or refreshing the persistent main menu now removes any active ephemeral promo so the menu remains the primary visible element.
  • Script that runs in production now creates required runtime directories and log/data files on startup so a fresh clone won't miss expected files.

Impact

✅ Fewer stray promo messages in chats
✅ Clearer main menu visibility for users
✅ No missing runtime directories/files on fresh deploys

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

Summary by CodeRabbit

  • New Features
    • Introduced ephemeral bonus prompts that automatically disappear after 15 seconds during onboarding.
    • Improved menu navigation by clearing transient prompts to prevent stale messages in chat.

@codeant-ai

codeant-ai Bot commented Feb 25, 2026

Copy link
Copy Markdown

CodeAnt AI is reviewing your PR.


Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@codeant-ai codeant-ai Bot added the size:M This PR changes 30-99 lines, ignoring generated files label Feb 25, 2026
@coderabbitai

coderabbitai Bot commented Feb 25, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@gamblecodezcom has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 10 minutes and 52 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between d177515 and 12e7aa4.

📒 Files selected for processing (2)
  • index.js
  • prod-run.sh
📝 Walkthrough

Walkthrough

Changes add ephemeral bonus message handling to a Telegram bot by introducing two helper functions for managing transient prompts with auto-deletion. Integration points include cleanup during menu navigation and replacement of inline promo prompts in the onboarding flow. The runtime setup script was refactored with explicit directory creation.

Changes

Cohort / File(s) Summary
Ephemeral Bonus Prompt Management
index.js
Added ephemeralBonusMsgId and ephemeralBonusChatId user fields. Introduced sendEphemeralBonusPrompt() helper to send auto-deleting 15-second bonus prompts and deleteEphemeralBonusPrompt() helper to clean up stored message IDs. Integrated cleanup calls in sendPersistentUserMenu() and to_main_menu action. Replaced inline promo prompt in onboarding case 3 with sendEphemeralBonusPrompt() call.
Runtime Setup Refactoring
prod-run.sh
Split combined mkdir/touch operation into explicit, separate mkdir commands for logs, data, and data/backups directories. Added descriptive comment block and informational say command announcing setup completion. Operations remain idempotent with no control flow changes.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

size:L

Poem

🐰 Ephemeral bonuses hop and play,
Vanishing in fifteen seconds' way,
Menu cleanup clears the trace—
Transient prompts know their place! 🎉

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Title check ⚠️ Warning The PR title lists multiple unrelated features but does not reflect the core changes in the provided file summaries (ephemeral bonus prompts and prod-run.sh setup improvements). Align the PR title with the actual changes in these files, such as 'Add ephemeral bonus prompt cleanup and improve runtime setup' or use a more specific title that covers the main modifications.
✅ Passed checks (2 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/configure-git-and-update-project-files-ai9ul2

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codeant-ai

codeant-ai Bot commented Feb 25, 2026

Copy link
Copy Markdown

Nitpicks 🔍

🔒 No security issues identified
⚡ Recommended areas for review

  • Ownership / Permission Risk
    The script creates log and data files as the user running the script (likely root) but later the systemd service may run as a different unprivileged user. This can lead to permission errors where the service user cannot write logs or the app cannot update session/tip files. Ensure created dirs/files have correct owner/group and restrictive permissions for the service user.

  • Fatal failure if creation fails
    The script uses set -euo pipefail so a failure of the directory/file creation (e.g., due to running as non-root) will cause immediate exit. Consider graceful handling or clearer error handling/logging to distinguish permission problems vs unexpected errors.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
index.js (1)

4058-4062: Remove duplicate transient cleanup in to_main_menu.

Line 4061 is redundant because sendPersistentUserMenu already calls deleteEphemeralBonusPrompt at Line 1891.

♻️ Proposed cleanup
 bot.action('to_main_menu', async (ctx) => {
   const user = getUser(ctx);
   await ctx.answerCbQuery();
-  await deleteEphemeralBonusPrompt(ctx, user);
   await sendPersistentUserMenu(ctx, user);
 });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@index.js` around lines 4058 - 4062, The to_main_menu action handler currently
calls deleteEphemeralBonusPrompt(ctx, user) before invoking
sendPersistentUserMenu(ctx, user), which is redundant because
sendPersistentUserMenu already calls deleteEphemeralBonusPrompt; remove the
redundant await deleteEphemeralBonusPrompt(ctx, user) call from the
bot.action('to_main_menu', ...) handler so ephemeral cleanup only happens inside
sendPersistentUserMenu and avoid double deletion.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@index.js`:
- Around line 2106-2139: Both deleteEphemeralBonusPrompt and
sendEphemeralBonusPrompt mutate user.ephemeralBonusMsgId and
user.ephemeralBonusChatId across async/timer boundaries without serialization;
wrap every read/write that affects those fields (including the async
ctx.telegram.deleteMessage calls and the setTimeout cleanup) inside the per-user
queue by calling runUserMutation (or the project's equivalent) so mutations are
executed serially for that user and compare/update the fields only within those
serialized callbacks to avoid races with concurrent handlers.

In `@prod-run.sh`:
- Around line 54-58: The created runtime files and dirs (LOG_DIR,
PROJECT_DIR/data, PROJECT_DIR/data/backups and the touched files MAIN_LOG,
ERROR_LOG, ADMIN_EVENTS_LOG, SSHV_SESSIONS_FILE) may be owned by root but the
service runs as user "runewager"; after the mkdir/touch block ensure ownership
and write permissions are given to that service user by changing ownership (to
runewager) and/or setting appropriate file modes (e.g. group/user write) on
those directories and files (apply recursively to PROJECT_DIR/data and backups)
so the bot can append to MAIN_LOG, ERROR_LOG and write ADMIN_EVENTS_LOG and
SSHV_SESSIONS_FILE at runtime.

---

Nitpick comments:
In `@index.js`:
- Around line 4058-4062: The to_main_menu action handler currently calls
deleteEphemeralBonusPrompt(ctx, user) before invoking
sendPersistentUserMenu(ctx, user), which is redundant because
sendPersistentUserMenu already calls deleteEphemeralBonusPrompt; remove the
redundant await deleteEphemeralBonusPrompt(ctx, user) call from the
bot.action('to_main_menu', ...) handler so ephemeral cleanup only happens inside
sendPersistentUserMenu and avoid double deletion.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between adc4ed8 and d177515.

📒 Files selected for processing (2)
  • index.js
  • prod-run.sh

Comment thread index.js
Comment on lines +2106 to +2139
async function deleteEphemeralBonusPrompt(ctx, user) {
if (!user.ephemeralBonusMsgId || !user.ephemeralBonusChatId) return;
try {
await ctx.telegram.deleteMessage(user.ephemeralBonusChatId, user.ephemeralBonusMsgId);
} catch (_) { /* message may already be gone */ }
user.ephemeralBonusMsgId = null;
user.ephemeralBonusChatId = null;
}

async function sendEphemeralBonusPrompt(ctx, user) {
const sent = await ctx.reply(
`🎁 *Claim Your New User Bonus*

Enter promo code *${promoStore.code}* on the Runewager affiliate page to claim your ${promoStore.amountSC} SC new user bonus!`,
{
parse_mode: 'Markdown',
...Markup.inlineKeyboard([
[Markup.button.url('🎁 Enter Promo Code (Mini App)', LINKS.miniAppClaim)],
[Markup.button.callback('⬅️ Main Menu', 'to_main_menu')],
]),
},
);
user.ephemeralBonusMsgId = sent.message_id;
user.ephemeralBonusChatId = sent.chat.id;
setTimeout(async () => {
try {
await ctx.telegram.deleteMessage(sent.chat.id, sent.message_id);
} catch (_) { /* best effort */ }
if (user.ephemeralBonusMsgId === sent.message_id && user.ephemeralBonusChatId === sent.chat.id) {
user.ephemeralBonusMsgId = null;
user.ephemeralBonusChatId = null;
}
}, 15 * 1000);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Serialize ephemeral prompt state mutations through the per-user queue.

Lines 2111-2112, 2128-2129, and 2134-2137 mutate user state across async and timer boundaries without runUserMutation, which can race with concurrent handlers for the same user.

🔧 Proposed fix
 async function deleteEphemeralBonusPrompt(ctx, user) {
   if (!user.ephemeralBonusMsgId || !user.ephemeralBonusChatId) return;
+  const msgId = user.ephemeralBonusMsgId;
+  const chatId = user.ephemeralBonusChatId;
   try {
-    await ctx.telegram.deleteMessage(user.ephemeralBonusChatId, user.ephemeralBonusMsgId);
+    await ctx.telegram.deleteMessage(chatId, msgId);
   } catch (_) { /* message may already be gone */ }
-  user.ephemeralBonusMsgId = null;
-  user.ephemeralBonusChatId = null;
+  await runUserMutation(user.id, async () => {
+    if (user.ephemeralBonusMsgId === msgId && user.ephemeralBonusChatId === chatId) {
+      user.ephemeralBonusMsgId = null;
+      user.ephemeralBonusChatId = null;
+    }
+  });
 }
 
 async function sendEphemeralBonusPrompt(ctx, user) {
+  await deleteEphemeralBonusPrompt(ctx, user);
   const sent = await ctx.reply(
@@
-  user.ephemeralBonusMsgId = sent.message_id;
-  user.ephemeralBonusChatId = sent.chat.id;
+  await runUserMutation(user.id, async () => {
+    user.ephemeralBonusMsgId = sent.message_id;
+    user.ephemeralBonusChatId = sent.chat.id;
+  });
   setTimeout(async () => {
     try {
       await ctx.telegram.deleteMessage(sent.chat.id, sent.message_id);
     } catch (_) { /* best effort */ }
-    if (user.ephemeralBonusMsgId === sent.message_id && user.ephemeralBonusChatId === sent.chat.id) {
-      user.ephemeralBonusMsgId = null;
-      user.ephemeralBonusChatId = null;
-    }
+    await runUserMutation(user.id, async () => {
+      if (user.ephemeralBonusMsgId === sent.message_id && user.ephemeralBonusChatId === sent.chat.id) {
+        user.ephemeralBonusMsgId = null;
+        user.ephemeralBonusChatId = null;
+      }
+    });
   }, 15 * 1000);
 }

As per coding guidelines Use per-user mutation queues to prevent race conditions on concurrent bonus/state mutations.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@index.js` around lines 2106 - 2139, Both deleteEphemeralBonusPrompt and
sendEphemeralBonusPrompt mutate user.ephemeralBonusMsgId and
user.ephemeralBonusChatId across async/timer boundaries without serialization;
wrap every read/write that affects those fields (including the async
ctx.telegram.deleteMessage calls and the setTimeout cleanup) inside the per-user
queue by calling runUserMutation (or the project's equivalent) so mutations are
executed serially for that user and compare/update the fields only within those
serialized callbacks to avoid races with concurrent handlers.

Comment thread prod-run.sh
Comment on lines +54 to +58
mkdir -p "$LOG_DIR"
mkdir -p "$PROJECT_DIR/data"
mkdir -p "$PROJECT_DIR/data/backups"
touch "$MAIN_LOG" "$ERROR_LOG" "$ADMIN_EVENTS_LOG" "$SSHV_SESSIONS_FILE" # create if missing; safe on existing files

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Ensure runtime data files are writable by the service user.

Line 57 creates data/admin-events.log and data/sshv-sessions.json as the current user (commonly root), but the bot may run as runewager (Line 134). That can block writes and break persistence/logging.

💡 Proposed fix
 mkdir -p "$LOG_DIR"
 mkdir -p "$PROJECT_DIR/data"
 mkdir -p "$PROJECT_DIR/data/backups"
 touch "$MAIN_LOG" "$ERROR_LOG" "$ADMIN_EVENTS_LOG" "$SSHV_SESSIONS_FILE"   # create if missing; safe on existing files
+
+# Ensure bot-writable runtime data files when service runs as runewager
+if id -u "$APP_NAME" >/dev/null 2>&1; then
+    chown "$APP_NAME:$APP_NAME" \
+        "$PROJECT_DIR/data" \
+        "$PROJECT_DIR/data/backups" \
+        "$ADMIN_EVENTS_LOG" \
+        "$SSHV_SESSIONS_FILE"
+    chmod 0640 "$ADMIN_EVENTS_LOG" "$SSHV_SESSIONS_FILE"
+fi
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@prod-run.sh` around lines 54 - 58, The created runtime files and dirs
(LOG_DIR, PROJECT_DIR/data, PROJECT_DIR/data/backups and the touched files
MAIN_LOG, ERROR_LOG, ADMIN_EVENTS_LOG, SSHV_SESSIONS_FILE) may be owned by root
but the service runs as user "runewager"; after the mkdir/touch block ensure
ownership and write permissions are given to that service user by changing
ownership (to runewager) and/or setting appropriate file modes (e.g. group/user
write) on those directories and files (apply recursively to PROJECT_DIR/data and
backups) so the bot can append to MAIN_LOG, ERROR_LOG and write ADMIN_EVENTS_LOG
and SSHV_SESSIONS_FILE at runtime.

Comment thread prod-run.sh
mkdir -p "$PROJECT_DIR/data"
mkdir -p "$PROJECT_DIR/data/backups"
touch "$MAIN_LOG" "$ERROR_LOG" "$ADMIN_EVENTS_LOG" "$SSHV_SESSIONS_FILE" # create if missing; safe on existing files

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: The data directory and JSON/log files are created by this script (often run as root), but the Node service typically runs under a non-root service user; without correcting ownership, the service user cannot write to data/admin-events.log, sshv-sessions.json, or other files under data, breaking persistence of admin events and SSHV sessions. [logic error]

Severity Level: Critical 🚨
- ❌ /sshv admin console sessions fail to persist across restarts.
- ❌ Admin events log writes fail or crash admin commands.
- ⚠️ God-mode heal diagnostics see stale admin-events.log data.
- ⚠️ Future JSON persistence features under data/ may break.
Suggested change
# Ensure data directory and files are writable by the service user, if it exists
if id -u "$APP_NAME" >/dev/null 2>&1; then
chown "$APP_NAME:$APP_NAME" "$PROJECT_DIR/data" "$PROJECT_DIR/data/backups" \
"$ADMIN_EVENTS_LOG" "$SSHV_SESSIONS_FILE" || true
fi
Steps of Reproduction ✅
1. On a VPS host, create a dedicated system user `runewager` and group (as implied by the
systemd unit user selection in `prod-run.sh:141-143`, where `svc_user="$APP_NAME"` and
`APP_NAME="runewager"` at `prod-run.sh:25`).

2. As root, run `prod-run.sh` from the project root; it resolves `PROJECT_DIR` and creates
runtime paths at `prod-run.sh:59-62`:

   - `mkdir -p "$PROJECT_DIR/data"` and `"$PROJECT_DIR/data/backups"`

   - `touch "$PROJECT_DIR/data/admin-events.log"` (via `ADMIN_EVENTS_LOG` at
   `prod-run.sh:29`)

   - `touch "$PROJECT_DIR/data/sshv-sessions.json"` (via `SSHV_SESSIONS_FILE` at
   `prod-run.sh:30`)

   These directories and files are owned by root:root with default permissions (typically
   755 for dirs, 644 for files).

3. The same script writes the systemd unit with `User=runewager` and `Group=runewager` in
`ensure_systemd_service()` at `prod-run.sh:133-170` and enables it; systemd then starts
`index.js` as the non-root `runewager` user from `WorkingDirectory=${PROJECT_DIR}`.

4. An admin uses Telegram admin features (e.g., `/sshv` or other admin commands) handled
in `index.js`, which:

   - Defines `const sshvSessionsFile = path.join(dataDir, 'sshv-sessions.json');` at
   `index.js:206` and later calls `saveJson(sshvSessionsFile, entries);` in
   `persistSshvSessions()` at `index.js:969`.

   - Defines `const adminEventsLogFile = path.join(dataDir, 'admin-events.log');` at
   `index.js:2141` and appends events with `fs.appendFileSync(adminEventsLogFile,
   JSON.stringify(entry) + '\n');` at `index.js:2152`.

   - Uses `function saveJson(filePath, data) { ... }` declared at `index.js:2271` to write
   JSON files under `data/`.

   When these writes execute under the `runewager` user, the process lacks write
   permission to the root-owned `data/` directory and files, causing `EACCES` filesystem
   errors. As a result, admin events are not logged, SSHV sessions cannot be persisted,
   and depending on error handling, the admin flows may throw or silently fail to persist
   data.
Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** prod-run.sh
**Line:** 58:58
**Comment:**
	*Logic Error: The data directory and JSON/log files are created by this script (often run as root), but the Node service typically runs under a non-root service user; without correcting ownership, the service user cannot write to `data/admin-events.log`, `sshv-sessions.json`, or other files under `data`, breaking persistence of admin events and SSHV sessions.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
👍 | 👎

@codeant-ai

codeant-ai Bot commented Feb 25, 2026

Copy link
Copy Markdown

CodeAnt AI finished reviewing your PR.

@gamblecodezcom
gamblecodezcom merged commit 8b42f54 into main Feb 25, 2026
3 of 5 checks passed
@gamblecodezcom
gamblecodezcom deleted the codex/configure-git-and-update-project-files-ai9ul2 branch February 25, 2026 06:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

codex size:M This PR changes 30-99 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant