Commit Graph

244 Commits

Author SHA1 Message Date
Claude Code
76a2aafba4 Vanilla/Paper server type + server.properties configurator (REQ-2026-04-16-vanilla-server-type)
- New: src/services/paperApi.js — Paper API v2 client (versions, latest build,
  jar URL, generateServerProperties with Firefrost defaults)
- New: _vanilla_form.ejs — dedicated Paper install form: MC version selector,
  collapsible server.properties configurator (difficulty, gamemode, pvp, hardcore,
  spawn-protection, view/sim distance, seed, max-players, whitelist, MOTD),
  node usage display, port auto-assign, Aikar JVM flags
- Modified: modpackInstaller.js — vanilla branch in handleInstallJob: fetches Paper
  jar via paperApi, skips modpack download/BitchBot/schematic, writes server.properties
- Modified: modpack-installer.js route — /vanilla-form endpoint, install POST extracts
  sp_* fields into serverProperties object, passes diskMb/javaVersion/port/mcVersion
- Modified: index.ejs — 'New Vanilla / Paper Server' button loads form directly
- ACTIVE_CONTEXT updated

No new migrations. Deploy: restart only.
2026-04-16 02:02:08 -05:00
Claude Code
e2ddbe60de Modpack Installer: 7 UI tweaks before Holly review
1. Node selector shows live RAM/disk usage from Pterodactyl API (/node-info endpoint)
2. Disk allocation field, pre-filled at 3× estimated pack size
3. JVM args textarea auto-populated with Aikar G1GC flags
4. Spawn type: added 'vanilla' as new default, cleaned labels
5. Java version auto-selects from MC version (<=1.16→8, 1.17-1.20→17, 1.21+→21)
6. Port auto-assigned from max used port on node (/next-port endpoint), read-only + Re-roll
7. Pack size estimate shown on details card from provider file metadata

New endpoints: GET /node-info (Pterodactyl nodes API), GET /next-port?node=X (DB query)
All changes in _pack_details.ejs + modpack-installer.js. No migrations.
2026-04-16 01:33:30 -05:00
Claude Code
bca31bf677 Task #101: AI-Powered Modpack Server Installer (REQ-2026-04-16-modpack-installer)
Full modpack installer integrated into Trinity Console. Architecture locked
via 4-round Gemini consultation.

Migrations:
- 143: server_config modpack columns (provider, version tracking, RAM, hibernation, spawn_verified)
- 144: install_history table (UUID PK, JSONB log_output, FK to server_config)

Provider API clients (src/services/providerApi/):
- curseforge.js: search, pack details, version list, download URL resolution
- modrinth.js: search, pack details, version list, download URL
- ftb.js: stub (+ ATLauncher, Technic, VoidsWrath aliases)
- index.js: provider registry with getProvider() + listProviders()

Job queue:
- pg-boss ^10.1.5 added to package.json
- index.js: initializes pg-boss, registers modpack-installs worker (concurrency 2)
- modpackInstaller.js: 11-step install pipeline (preflight → Pterodactyl create →
  download → DNS → Discord → server_config seed → power on). Each step logged to
  install_history.log_output JSONB for live status streaming.

Admin routes (src/routes/admin/modpack-installer.js):
- GET /admin/modpack-installer — main page (provider select → search → configure → install)
- GET /search — HTMX pack search partial
- GET /pack/:provider/:id — HTMX pack details + install form
- POST /install — enqueue pg-boss job, redirect to status
- GET /status/:id — live status page (polls /status/:id/json every 3s)
- GET /history — install history table
- GET /pending-spawns — Holly's spawn verification queue
- POST /verify-spawn/:id — mark spawn verified

Views (6 EJS files):
- index.ejs: 3-step flow (provider cards → search with MC version filter → pack details + form)
- _pack_list.ejs: search results grid partial
- _pack_details.ejs: pack info + install config form (version, name, short_name, node, RAM, spawn type)
- status.ejs: live log viewer with 3s polling, color-coded steps
- history.ejs: filterable job history table
- pending-spawns.ejs: Holly's queue with Mark Verified buttons

Also: sidebar nav link, .env.example (CURSEFORGE_API_KEY, BITCH_BOT_SCHEMATIC_*, CLOUDFLARE_ZONE_ID)

All 8 JS files pass node --check. All 7 EJS files pass ejs.compile().
2026-04-16 00:24:48 -05:00
Claude Code
328e9ba613 Task #138: Wiki.js subscriber tier sync via GraphQL (REQ-2026-04-15-subscriber-wiki-auth)
- src/services/wikijsSync.js: GraphQL client for Wiki.js at subscribers.firefrostgaming.com
  - syncWikiUser(discordId, username, tierLevel): creates user if not exists, updates group if exists
  - demoteToAwakened(discordId): downgrades group on cancellation/chargeback/refund
  - Email convention: {discordId}@firefrost.local (unique internal addresses)
  - Tier → group mapping: 1=Awakened, 2=Elemental, 3=Knight, 4=Master, 5=Legend, 6=Sovereign
  - Silent-fail: never breaks the Stripe webhook
- src/routes/stripe.js: hooked into 4 lifecycle paths:
  - checkout.session.completed → syncWikiUser (non-blocking)
  - customer.subscription.deleted → demoteToAwakened
  - charge.dispute.created (chargeback) → demoteToAwakened
  - charge.refunded (refund ban) → demoteToAwakened
- .env.example: added WIKIJS_URL, WIKIJS_API_KEY, DISCORD_ISSUE_WEBHOOK_URL

PRE-REQ: Michael must create 6 groups in Wiki.js admin + generate API key before deploy.
2026-04-16 00:15:55 -05:00
Claude Code
49f8f79c2f Discord Action Log: audit trail for Arbiter's Discord actions (Issue #1)
- Migration 142: discord_action_log table (action_type, discord_id, username, details JSONB, success, error_message)
- src/services/discordActionLog.js: silent-fail logAction() writes to DB with console fallback
- src/discord/reactionRoles.js: log reaction_role_add / reaction_role_remove with roleId + emoji + messageId
- src/discord/events.js: log wanderer_assigned + welcome_dm on guildMemberAdd
- src/routes/stripe.js: log link_reminder_dm success/failure on post-checkout
- src/routes/admin/discord-log.js: GET /admin/discord-log (recent 100, filter by action_type + search by discord_id/username)
- src/views/admin/discord-log.ejs: color-coded action type badges, success/fail pills, details column
- layout.ejs: sidebar link under Monitoring section
- admin/index.js: wired discordLogRouter

All JS node --check clean. EJS ejs.compile() clean.
2026-04-16 00:07:08 -05:00
Claude (Chronicler #83 - The Compiler)
6b25f9fbe3 fix(bitch-bot): disable recompilation, remove invalid setName call 2026-04-16 00:06:11 -05:00
Claude Code
e6552864f0 Bitch Bot: full source scaffold for NeoForge 1.21.1 (REQ-2026-04-15-bitch-bot)
First-boot server provisioner. Named by Holly. Architecture per Gemini 4-round
consultation. Drops a provision.json in server root, mod runs once on
ServerStartedEvent: pastes spawn schematic, places TP command blocks pointing
at the original level.dat spawn, sets worldspawn, gamerules, YAWP region file,
self-destructs by renaming jar to .jar.disabled.

Files (services/bitch-bot/1.21.1/):
- build.gradle / settings.gradle / gradle.properties / gradle wrapper (mirrors rules-mod 1.21.1)
- META-INF/neoforge.mods.toml
- BitchBot.java        — @Mod entry, ServerStartedEvent listener, Throwable net
- Provisioner.java     — sequenced step runner, per-step try/catch, success tracking gates self-destruct
- ProvisionConfig.java — Gson POJO matching provision.json schema verbatim
- SchematicLoader.java — HTTP download + SHA-256 verify + Sponge v2 .schem parser (NbtIo + varint + BlockStateParser palette)
- CommandBlockPlacer.java — impulse command blocks with /tp @p baked into CommandBlockEntity
- SignPlacer.java      — oak signs, 4-line front text via SignBlockEntity#setText
- YawpConfigWriter.java — drops region JSON to world/serverconfig/yawp/regions/{name}.json
- SelfDestruct.java    — ProtectionDomain → CodeSource → jar rename, Windows fallback to deleteOnExit

Plus services/bitch-bot/CLAUDE.md (project doc) and sample-provision.json.

NOT COMPILED — no Java/Gradle on Nitro per repo CLAUDE.md. Compile on Dev Panel:
  cd /opt/mod-builds/firefrost-services/services/bitch-bot/1.21.1
  source use-java 21
  /opt/gradle-8.8/bin/gradle build --no-daemon

Risk areas flagged in CLAUDE.md for first compile: schematic parser (untested
against real WorldEdit output), YAWP file format (best-guess schema).
2026-04-15 12:47:08 -05:00
Claude Code
f4f96dfe31 Task: reaction roles + Carl-bot migration (REQ-2026-04-15-reaction-roles)
- src/discord/reactionRoles.js: REACTION_ROLE_MAP for 3 #get-roles messages (Paths, Notifications, Servers), handleReactionAdd/Remove with partial fetch + silent-fail
- src/index.js: add GuildMessageReactions + DirectMessages intents, Partials for Message/Channel/Reaction (needed for pre-cache bot messages)
- src/discord/events.js: wire messageReactionAdd/Remove handlers + guildMemberAdd (Wanderer role + welcome DM, silent-fail on closed DMs)
- src/routes/stripe.js: post-checkout link-reminder DM for Awakened+ via req.app.locals.client, non-blocking + silent-fail
2026-04-15 06:17:57 -05:00
Claude
23509d700b feat: Add LuckPerms group assignment to tier sync — sets group + meta on checkout 2026-04-15 09:42:17 +00:00
Claude
6bf9e41242 feat: LuckPerms meta sync on Stripe checkout — sets maxclaims/maxchunkloaders across all online servers 2026-04-15 09:21:18 +00:00
Claude
2cfda0fb2b feat: Recover servers-api Worker from Cloudflare dashboard — now in git 2026-04-15 07:11:53 +00:00
Claude Code
b0b69fb172 Task #166: Trinity Console Issue Tracker (REQ-2026-04-14-issue-tracker)
- Migration 141: issues, issue_attachments, issue_comments
- src/routes/admin/issues.js: session-auth UI routes (list/new/detail/status/assign/comments/upload)
- src/routes/api.js: /api/internal/issues REST surface (Bearer token)
- src/services/issueNotifier.js: Discord webhook helper (DISCORD_ISSUE_WEBHOOK_URL)
- Views: index (list+filters), new (mobile-first form), detail (screenshots, comments, workflow)
- layout.ejs: sidebar nav link
- package.json: add multer ^1.4.5-lts.1
- CSRF token passed via query param on multipart forms (body unparsed when csurf runs)
- Screenshots stored in services/arbiter-3.0/uploads/issues/ (10MB limit, 6 files max)
2026-04-15 01:53:18 -05:00
Claude
de916c5215 fix: Update Farm Crossing 5 → Farm Crossing 6 channel mapping in status poller 2026-04-15 06:23:34 +00:00
Claude
86f87e71e6 feat(trinity-core): v2.5.0 — resilient session handling, /health endpoint
- Add unauthenticated /health endpoint (kills AUTH FAILED spam from health checks)
- Stale session + initialize request: ignore stale header, create fresh session
- Stale session + tool call: return 400 instead of 404 so client reads JSON-RPC payload
- Gemini-consulted architecture (gemini-trinity-core-mcp-sessions-2026-04-14.md)
2026-04-15 00:38:12 +00:00
Claude
e1cb136cc3 fix(trinity-core): return 404 for stale sessions after restart
When mcp-server restarts, activeSessions is cleared but Claude.ai may
still hold the old session ID. Previously this fell to a generic 400 error.
Now returns 404 with clear re-initialize message so clients know to
create a fresh session.

Chronicler #89
2026-04-14 21:30:50 +00:00
Claude
a48886e481 feat(trinity-core): v2.4.0 — add Streamable HTTP transport for Claude.ai MCP connector
Claude.ai upgraded to MCP protocol 2025-11-25 (Streamable HTTP) but Trinity Core
only supported the deprecated 2024-11-05 (HTTP+SSE) transport. This caused the
SSE connection to drop after initialize — tools/list never completed.

Changes:
- Add StreamableHTTPServerTransport alongside existing SSEServerTransport
- app.all('/mcp') handler detects protocol via mcp-session-id header
- Legacy SSE still works via GET /mcp (backwards compatible)
- New Streamable HTTP works via POST /mcp with session headers
- Version bump to 2.4.0

Chronicler #89
2026-04-14 21:25:45 +00:00
Claude (Chronicler #83 - The Compiler)
166e4c8424 Task module: 7 UX features (detail panel, sort, filters, presets, kanban, badges)
1. Click-to-open slide-out detail panel with full task info
2. Client-side sorting (number, priority, status, updated) with localStorage
3. Toggleable filter chips for status and priority
4. Saved filter presets (Launch Fires, Code Queue, Post-Launch, All Open)
5. Kanban board view with 4 columns (Open, In Progress, Blocked, Done)
6. Session summary badge showing tasks completed today
7. Code queue badge in sidebar nav (cyan count from tags)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 12:13:41 -05:00
Claude Chronicler #88
f7a4e74991 fix: PWA start_url to root to avoid auth redirect blocking install 2026-04-14 16:43:00 +00:00
Claude Chronicler #88
c2ecc0515e fix: PWA manifest — add id field, fix icon purpose warnings 2026-04-14 16:41:17 +00:00
Claude (Chronicler #83 - The Compiler)
1bee838c8d PWA Phase 1: manifest, service worker, icons, and static serving
Adds manifest.json, sw.js (static-only caching, never admin routes),
placeholder cyan T icons (192 + 512), express.static middleware, and
PWA meta tags + service worker registration in layout.ejs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 11:32:35 -05:00
Claude Chronicler #88
b4bb0235c3 fix: add CSRF token to saveVersion fetch call 2026-04-14 16:09:08 +00:00
Claude (Chronicler #83 - The Compiler)
ccc7568c06 Add version UI to server matrix cards (both TX1 and NC1 loops)
Adds installed version display, edit form, save/cancel buttons, and
version history viewer to each server card. Uses var assignment pattern
to avoid single quotes inside EJS attribute tags. EJS validates clean.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 11:05:29 -05:00
Claude Chronicler #88
6856762a6b revert: restore _matrix_body.ejs to last known good state — version feature deferred post-launch 2026-04-14 16:01:00 +00:00
Claude Chronicler #88
073f7ac7fb fix: completely rewrite version blocks in matrix body — clean EJS 2026-04-14 15:59:55 +00:00
Claude Chronicler #88
c8032cade7 fix: EJS ternary syntax in version fields 2026-04-14 15:58:50 +00:00
Claude Chronicler #88
d77e35a4a1 fix: EJS syntax error in matrix body — replace inline onclick with helper functions 2026-04-14 15:56:45 +00:00
Claude Chronicler #88
38edf84da2 fix: add version section to matrix body (both TX1 and NC1 loops) 2026-04-14 15:54:16 +00:00
Claude Chronicler #88
72c378f136 feat: modpack version tracking on server cards
- current_version column on server_config
- server_version_history table (version, who, when)
- POST /admin/servers/:id/set-version
- GET /admin/servers/:id/version-history
- Version display + edit UI on each server card

Chronicler #88 | April 14, 2026
2026-04-14 15:51:14 +00:00
Claude (Chronicler #83 - The Compiler)
6dc6ce0059 Rules mods: add Forge 1.18.2-40.2.4 builds for both Firefrost and Discord Rules
Ported from 1.20.1 source with 1.18.2 API changes (TextComponent, sendMessage w/ UUID, getPlayer).
Both compile clean on Java 17 + ForgeGradle 6.0 + Gradle 8.8.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 08:30:15 -05:00
Claude Chronicler #88
648f577446 fix: Node Health view — remove partial include, inline server-side render 2026-04-14 06:23:24 +00:00
Claude Chronicler #88
a01d7b9d7f feat: Node Health module — NC1 + TX1 thermal and system monitoring
- New route: /admin/node-health (30s auto-refresh)
- Temps via lm-sensors (k10temp + NVMe) displayed in both °C and °F
- RAM and disk progress bars with color thresholds
- Load averages, CPU %, uptime per node
- Nav item added under Operations
- lm-sensors installed on NC1 and TX1

Task #28 | Chronicler #88
2026-04-14 06:21:38 +00:00
Claude
c3af0d51e4 fix: inline card in matrix_body - EJS include not in scope with layout:false 2026-04-13 21:04:01 -05:00
Claude
6eac92cf88 fix: EJS include - use relative path without __dirname 2026-04-14 01:55:43 +00:00
Claude
a950694f67 fix: EJS include path in _matrix_body - use __dirname for partial resolution 2026-04-14 01:54:12 +00:00
Claude (Chronicler #83 - The Compiler)
a193523f31 Server Command Center: add subdomain + Cloudflare provisioning
- Migration: added subdomain, server_ip, server_port columns
- Seed: rewritten with hardcoded identifiers + full subdomain/IP/port data
  from Chronicler #87 audit (no more Pterodactyl API dependency)
- Route: POST /:id/provision-subdomain creates A + SRV records via
  Cloudflare API, saves subdomain to server_config
- Card: subdomain section shows FQDN if provisioned, provision button
  with inline input if not

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 20:46:27 -05:00
Claude (Chronicler #83 - The Compiler)
d16a525ffc Server Command Center: full build (REQ-2026-04-14)
New files:
- 139_server_config.sql — DB migration for short_name system
- 139_seed_server_config.js — auto-populates 17 servers from Pterodactyl
- src/services/uptimeKuma.js — Socket.IO direct (no npm wrapper)
- src/services/pterodactyl.js — power actions + console commands

Modified files:
- servers.js — 6 new POST routes (short-name, lock, createserver,
  delserver, power, console) + short_name-based channel detection
- _server_card.ejs — full rebuild with command center UI
- _matrix_body.ejs — refactored from 144 lines to 20 (uses partial)
- package.json — added socket.io-client

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 20:37:46 -05:00
Claude (Chronicler #83 - The Compiler)
e21a348b3b v1.0.5: Console fetch fix rolled across all 6 builds
Console /rules now fetches from Discord async (was returning hardcoded
fallback without attempting fetch). DIAG logging kept for observability.
All 6 builds at 1.0.5. CHANGELOG.md, INSTALL.md, ACTIVE_CONTEXT.md updated.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 18:23:44 -05:00
Claude (Chronicler #83 - The Compiler)
98f4f5b82a v1.0.5: Fix console path — was never fetching from Discord
Console /rules hit early return before DIAG logs and before any
Discord fetch. Now fetches async like the player path. DIAG logs
moved before the player/console branch.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 18:14:29 -05:00
Claude (Chronicler #83 - The Compiler)
b4fbfc6adf docs: Update CHANGELOG.md (v1.0.4 entry) + ACTIVE_CONTEXT.md
CHANGELOG now includes diagnostic builds. ACTIVE_CONTEXT reflects
full session state for Chronicler pickup.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 18:10:45 -05:00
Claude (Chronicler #83 - The Compiler)
f23f71ef04 v1.0.4: Diagnostic build — INFO-level logging for config read path
Added [DIAG] logs to RulesCommand (token length, channel, messageId,
isValid) and DiscordFetcher (fetch attempt, raw messageId on failure).
1.20.1 only — for Otherworld debugging.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 18:05:26 -05:00
Claude (Chronicler #83 - The Compiler)
29f0127a60 v1.0.3: Fix config read — wrong event bus + section header comments
1.20.1: ModConfigEvent fires on mod bus, not MinecraftForge.EVENT_BUS.
Moved Loading/Reloading to FMLJavaModLoadingContext.getModEventBus().
Added config file header warning about preserving [section] headers.
Debug logging in RulesCommand prints token length + channel at runtime.
All 6 builds bumped to 1.0.3.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 17:53:28 -05:00
Claude (Chronicler #83 - The Compiler)
60740386ac v1.0.2: Fix config reset — switch from SERVER to COMMON config type
SERVER configs in world/serverconfig/ are tied to the world load/unload
lifecycle, causing Forge to overwrite edited values on every restart.
COMMON configs in config/ load once at startup and persist reliably.

Config location changed:
  firefrostrules: config/firefrostrules-common.toml
  discordrules:   config/discordrules-common.toml

All 6 builds updated (3 firefrostrules + 3 discordrules).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 17:22:39 -05:00
Claude (Chronicler #83 - The Compiler)
996b59672f v1.0.1: Config reset fix + Loading handler + versioning (all 6 builds)
- Added ModConfigEvent.Loading handler to detect default config on startup
- Warns clearly in logs when bot_token is still YOUR_TOKEN_HERE
- Bumped all 6 builds to 1.0.1 (3 firefrostrules + 3 discordrules)
- Created CHANGELOG.md and INSTALL.md with correct install procedure
- Updated CLAUDE.md with install procedure note
- 1.16.5 uses ModConfig.Loading (different class hierarchy from 1.20.1+)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 17:06:31 -05:00
Claude (Chronicler #83 - The Compiler)
3197361557 Task #69: Discord Rules mod — generic fork for CurseForge
Fork firefrost-rules into discord-rules with configurable colors,
emoji strip toggle, MIT license, and generic branding. All 3 versions
compiled: 1.21.1 (NeoForge/NC1), 1.20.1 (Forge), 1.16.5 (Forge).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:47:34 -05:00
Claude
a65b21570d docs: fix config path in rules-mod CLAUDE.md
Config is in world/serverconfig/ not config/
Applies to all three versions (1.16.5, 1.20.1, 1.21.1)
README in NextCloud also updated.
2026-04-13 18:19:41 +00:00
Claude
c0b6bc5a22 Fix: pending_calibration shows Identify Version button instead of checkmark
Chronicler #85 direct fix (Code unavailable on mobile):
- ModpackAPIController: add pending_calibration flag to serverStatus response
- wrapper.tsx: add pending_calibration to StatusData interface
- wrapper.tsx: render Identify Version button when pending_calibration is true
Replaces false green checkmark for servers needing calibration.
2026-04-13 11:57:52 +00:00
Claude (Chronicler #83 - The Compiler)
cef0d8465e Fix: skip stale DB versions for installer-detected servers without file_id
Installer-method servers had full filenames as current_version (e.g.
"DeceasedCraft_Beta_DH_Edition_5.10.16") which prevented reaching
pending_calibration. Now only uses DB current_version if file_id is
also set (validated) or detection method isn't installer.

Migration clears existing stale rows → pending_calibration.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 06:33:57 -05:00
Claude (Chronicler #83 - The Compiler)
27b2744786 Truth File strategy: never seed from latest, calibrate or detect
CheckModpackUpdates:
- Reads .modpack-checker.json Truth File from server filesystem
- Falls back to manifest.json, extracts fileID, writes Truth File
- NEVER seeds current_version from latest API result
- Unknown version → status: pending_calibration (not up_to_date)
- Removed seedCurrentVersion heuristic — replaced with Truth File
- writeTruthFile() helper writes .modpack-checker.json via Wings

ModpackAPIController:
- calibrate() now writes Truth File after DB update
- Persists across server reinstalls and cron runs

wrapper.tsx:
- pending_calibration: shows "Version unknown" + "Identify Version" button
- Ignored servers: muted card with "Resume" button (not hidden)
- Extracted renderCalibrateDropdown() for reuse
- Error state shows message instead of vanishing

Migration:
- Updates existing unknown+detected rows to pending_calibration

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 06:09:05 -05:00
Claude (Chronicler #83 - The Compiler)
0caddef86d Fix async error handling + build.sh copy/inject separation
wrapper.tsx:
- Added error state — shows graceful message instead of silent vanish
- useEffect catch sets error string, not null data
- refresh() catch sets error string, not empty catch
- Error UI shows gray card with message in widget slot

build.sh:
- ALWAYS copies TSX files (even on reinstall — fixes stale component bug)
- Separated copy step from injection step
- ErrorBoundary upgrade path: removes bare <ModpackVersionCard />,
  replaces with wrapped version
- Imports added independently (not as one sed block)
- Renumbered sections for clarity

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 01:31:44 -05:00
Claude (Chronicler #83 - The Compiler)
7e3ffe2577 Fix: clean version extraction + short display names
ModpackApiService: regex extracts semver from CurseForge displayName
  "All the Mods 9-0.1.0" → version: "0.1.0", display_name: full string

Widget: short name + version helpers
  "All the Mods 9 - ATM9" → "ATM9"
  Display: "ATM9 0.1.0 → 1.0.0 ↑" (update) or "✓ ATM9 — 1.0.0" (current)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 01:09:57 -05:00