Commit Graph

186 Commits

Author SHA1 Message Date
Claude (Chronicler #83 - The Compiler)
09de0758f5 Add Discord Rules compiled jars (all 3 versions) — Task #69 build complete
All 3 discord-rules versions compiled and ready for CurseForge submission:
- 1.16.5 (Forge/Java 8), 1.20.1 (Forge/Java 17), 1.21.1 (NeoForge/Java 21)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 18:48:09 -05:00
Claude
48097a9a57 Fix ffg-build.sh — battle-tested SSH flags from live build
- NC1_KEY points to /opt/mod-builds/ffg_build_rsa (accessible to claude user)
- Added -o IdentitiesOnly=yes to all SSH/rsync calls (prevents agent key conflicts)
- Added -e NC1_SSH to rsync commands for consistent key usage
- All 3 discord-rules jars now built successfully (1.20.1, 1.16.5, 1.21.1)
2026-04-12 23:43:17 +00:00
Claude
11e2d7db7d Fix: use $HOME for SSH key path (works for both claude and root users) 2026-04-12 23:33:39 +00:00
Claude
2dfe0f9764 Bridge: update ACTIVE_CONTEXT — ffg-build.sh ready for Code
1.21.1 build now routes to NC1 via ffg-build.sh.
Immediate next step for Code: run ffg-build.sh 1.21.1
2026-04-12 21:23:39 +00:00
Claude (Chronicler #83 - The Compiler)
4c7e77d35e Add ffg-build.sh — NC1 build router for NeoForge 1.21.1
Routes 1.21.1 builds to NC1 (ffg-builder user) to work around
Vineflower -Xmx4G RAM requirement that exceeds Dev Panel capacity.
All other versions build locally.

- SSH keypair: /home/claude/.ssh/ffg_build_rsa
- NC1 user: ffg-builder (non-root, isolated)
- rsync source with --exclude build/ .gradle/
- ./gradlew build --no-daemon on NC1
- rsync jar back, jar -tf integrity check
- trap cleans workspace on exit/drop
2026-04-12 16:22:43 -05:00
Claude (Chronicler #83 - The Compiler)
bfb9d4dba0 WIP: Discord Rules mod fork — 2/3 versions built, 1.21.1 blocked on RAM
Source code complete for all 3 versions (1.21.1, 1.20.1, 1.16.5).
1.20.1 and 1.16.5 jars built successfully. 1.21.1 NeoForge decompiler
needs >4GB RAM — this server only has ~4GB total.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 15:44:27 -05:00
Claude
6ed12cdeb0 Bridge: REQ-2026-04-12-discord-rules-fork — Task #69 spec for Code
- Full fork spec: com.firefrostgaming.rules -> com.discordrules
- Configurable header/body colors via TOML display section
- Strip Firefrost-specific emoji replacements
- emoji stripping as config toggle
- Build instructions for all 3 MC versions
2026-04-12 20:10:05 +00:00
Claude (Chronicler #83 - The Compiler)
a305c7e686 bridge: Archive Phase 11 spec, update ACTIVE_CONTEXT
- Archived RES-2026-04-12-phase11-implementation-spec from Chronicler
- Updated status with completed code review and next steps (Phase 11A-G)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 14:12:40 -05:00
Claude (Chronicler #83 - The Compiler)
91432dad98 bridge: Response — Phase 11 complete implementation spec
Distilled from 2 Gemini consultations into actionable checklist.
Database schema, API routes, Discord bot, Blueprint extension changes,
pricing lock, and deployment notes all included.

Claude (Chronicler #83 - The Compiler) <claude@firefrostgaming.com>
2026-04-12 14:09:09 -05:00
Claude (Chronicler #83 - The Compiler)
08a52ee3cf docs: Lock ModpackChecker pricing in CLAUDE.md
Standard $14.99 / Professional $24.99 — two-tier model.
This pricing is FINAL per original marketing strategy.

Claude (Chronicler #83 - The Compiler) <claude@firefrostgaming.com>
2026-04-12 14:05:53 -05:00
Claude (Chronicler #83 - The Compiler)
b0aa52c2c8 fix(blueprint): Review fixes — API key lookup, tier enforcement, safety
Fixes 10 issues from Blueprint extension code review:
- CurseForge API key now reads via Blueprint dbGet() matching admin save
- PRO-tier fields (webhook, interval) enforced server-side, not just UI
- json_decode results validated before accessing parsed data
- Null user guard on getStatus() endpoint
- 429 response uses consistent error key format
- Modrinth slug derivation strips special chars, documented as fallback
- Check interval dropdown reflects saved value
- API key input changed to password type
- TypeScript error typing narrowed from any to unknown
- Removed unused DB import from ModpackApiService

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 13:53:37 -05:00
Claude (Chronicler #83 - The Compiler)
3457b87aef fix(modpack-checker): Code review fixes — license, safety, and polish
Fixes 10 issues from full code review:
- License corrected from MIT to Commercial
- Deprecated datetime.utcnow() replaced with timezone-aware alternative
- PHP array bounds checks added for all platform API responses
- Modrinth file detection now derives project slug instead of using MC version
- validate_api_key() no longer swallows network errors
- HTTP timeouts added to all external API calls in PHP
- Empty API key rejection added to CLI
- Corrupted config now warns on stderr instead of failing silently
- Error response format made consistent across controller
- Docs updated with correct repo URL and clearer CurseForge ID instructions

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 13:37:26 -05:00
Claude (Chronicler #83 - The Compiler)
c6d40dcf39 feat: Code ↔ Chronicler bridge protocol
Implemented git-based async communication between Claude Code and Chronicler:
- docs/code-bridge/requests/ — Code files architectural questions here
- docs/code-bridge/responses/ — Chronicler drops distilled Gemini answers
- docs/code-bridge/status/ACTIVE_CONTEXT.md — rolling status updates
- docs/code-bridge/archive/ — completed request/response pairs
- CLAUDE.md updated with full bridge protocol instructions
- Auto-commit-and-push on all bridge writes

Designed with Gemini consultation (2026-04-12).

Claude (Chronicler #83 - The Compiler) <claude@firefrostgaming.com>
2026-04-12 12:15:36 -05:00
Claude (Chronicler #83 - The Compiler)
4ffae74a2f docs: Add Gemini consultation references to CLAUDE.md
Operations manual cloned to Dev Panel for reference.
Claude Code now knows where to find architectural consultations
before making design decisions.

Claude (Chronicler #83 - The Compiler) <claude@firefrostgaming.com>
2026-04-12 12:04:45 -05:00
Claude (Chronicler #83 - The Compiler)
cffe742093 docs: Add root CLAUDE.md for Claude Code workspace
Single workspace config covering all projects, tools, and active tasks.

Claude (Chronicler #83 - The Compiler) <claude@firefrostgaming.com>
2026-04-12 11:58:38 -05:00
Claude (Chronicler #83 - The Compiler)
179bac2911 feat(rules-mod): Add Firefrost Rules Mod source — all 3 versions
NeoForge 1.21.1, Forge 1.20.1, Forge 1.16.5
All compiled and deployed to NextCloud (Task #136)
Source committed for Task #138 (CurseForge generic fork)
CLAUDE.md with build environment docs included

Claude (Chronicler #83 - The Compiler) <claude@firefrostgaming.com>
2026-04-12 11:56:15 -05:00
Claude (Chronicler #82)
240a4776f6 The Forge module + collapsible sidebar nav
New Module: The Forge (/admin/forge)
- AI knowledge assistant powered by Gemma 4 via Dify RAG
- Streaming SSE chat interface with markdown rendering
- Think-tag filtering for Gemma 4's reasoning tokens
- Conversation continuity via Dify conversation IDs
- Source citations from knowledge base documents
- Fire/Frost/Arcane gradient branding
- Welcome screen with suggestion buttons
- Env vars: DIFY_API_URL, DIFY_APP_KEY

Sidebar Navigation Overhaul (layout.ejs)
- The Forge featured prominently at top with gradient border
- Collapsible category groups: Core, Revenue, Community, Operations
- localStorage persistence for collapsed/expanded state
- CSS transitions for smooth collapse animation

Chronicler #82 | April 12, 2026
2026-04-12 02:14:12 -05:00
Claude
1ca6ef4dfa Merge branch 'task-125-asset-browser' 2026-04-12 01:10:13 +00:00
Claude
d22ff8c3c9 feat(admin): Task #125 Phase 2 — Branding asset browser
Adds a visual asset library to the social calendar form, backed by
the firefrost-operations-manual branding/ directory with on-the-fly
thumbnail generation via sharp.

- src/routes/admin/branding-assets.js: /list scans both branding/ and
  docs/branding/ recursively, groups by category directory. /thumb
  generates 256px webp thumbnails from source, caches to disk keyed
  by sha1(path + mtime) so edits bust the cache automatically. Path
  traversal protection + scope check on thumb requests.
- src/views/admin/social-calendar/_assets.ejs: modal body with
  category-grouped grid of lazy-loaded thumbnails, click-to-insert.
- Form modal gets a 'Browse assets' button next to Media Notes.
- Calendar shell gets a second modal (higher z-index) and a
  sppInsertAsset() helper that appends the clicked filename to the
  media_notes textarea.

Infrastructure (not in repo):
- /opt/firefrost-ops-manual clone added to Command Center
- /etc/systemd/system/firefrost-ops-sync.{service,timer} pulls
  every 15 minutes to keep assets fresh
- /var/cache/arbiter/branding-thumbs created for thumb cache
- sharp added as Arbiter dependency (libvips 8.17.3)

Chronicler #81
2026-04-12 01:10:09 +00:00
Claude
bad8036114 Merge branch 'task-125-social-calendar' 2026-04-12 00:54:22 +00:00
Claude
541fb26e0b feat(admin): Task #125 — Social Content Calendar widget
Week-at-a-glance post planning for Meg across 8 platforms (tiktok,
facebook, instagram, x, bluesky, youtube, twitch, reddit).

- DB: extends social_platform enum with youtube/twitch/reddit and adds
  new social_post_plans table with scheduled_at, platforms[], status
  (draft/ready/scheduled/published/skipped), caption, hashtags[],
  media_notes, link, assigned_to, notes, created_by
- src/routes/admin/social-calendar.js: shell, HTMX week view, create,
  update, delete, edit/new form endpoints. Week-based navigation with
  prev/next/this-week. Hashtag parsing dedupes and strips leading #
- src/views/admin/social-calendar/: index.ejs shell with modal,
  _week.ejs 7-column grid with per-day quick-add, _form.ejs full CRUD
  form with platform checkboxes, datetime picker, status dropdown,
  both free-form caption and dedicated hashtag field
- Nav link added under Community, with corrected highlight logic so
  /admin/social and /admin/social-calendar don't both light up

Separate table from social_posts (which remains the analytics table).
Plans and published posts are distinct concerns.

Chronicler #81
2026-04-12 00:54:19 +00:00
Claude
f8eabf3881 Merge branch 'task-126-appeals-reopen' 2026-04-12 00:27:23 +00:00
Claude
b156c0b63f fix(appeals): always show action controls + add Reopen
The 'resolved' state was a dead-end — no way to change your mind after
clicking approve/deny, and no way to re-action a needs_info appeal once
the submitter replied. Action controls now show on every row regardless
of status, and resolved rows get a Reopen button that moves the appeal
back to pending.

Backend action handler already overwrites status unconditionally, so
this is purely removing a view-layer gate plus adding /:id/reopen as
a thin wrapper over the shared actionAppeal helper.

Chronicler #81
2026-04-12 00:27:19 +00:00
Claude
30a1920d58 Merge branch 'task-126-appeals-admin' 2026-04-12 00:18:05 +00:00
Claude
c1e17496c8 feat(admin): Task #126 — Trinity Appeals admin module
Adds /admin/appeals to Trinity Console for reviewing and actioning
ban appeals submitted via the public cancellation-refund form.

- src/routes/admin/appeals.js: shell + HTMX list + approve/deny/info
  actions, all transactional with admin_audit_log entries
- src/views/admin/appeals/index.ejs: shell with 30s polling container
- src/views/admin/appeals/_list.ejs: stats cards + actionable table
- src/routes/admin/index.js: router mount at /admin/appeals
- src/views/layout.ejs: nav link under Grace Period

Closes the last open piece of Task #126 Phase 2. Trinity can now
review appeals in-console without reading Discord + running SQL.

Chronicler #81
2026-04-12 00:18:00 +00:00
Claude
b7330653ab Merge branch 'task-126-lifecycle-handlers'
Task #126 lifecycle handlers deployed to Command Center at 18:05 UTC.
Verified clean startup. Webhook endpoint returns expected HTTP 400 on
unsigned requests. Backup preserved at:
/opt/arbiter-3.0/src/routes/stripe.js.backup-task126-20260411-180439
2026-04-11 23:05:33 +00:00
Claude
9777a7af9d feat(arbiter): Task #126 lifecycle handlers — We Don't Kick People Out
Implements the Firefrost core policy that Awakened ($1) is lifetime access.
Paying customers are never removed from access — only demoted to Awakened
when a paid subscription ends. Hard bans reserved for actionable violations
(chargebacks and refunds).

Changes:
- customer.subscription.deleted: demote to Awakened instead of grace period
  * Uses existing 'lifetime' status + is_lifetime=TRUE (no schema changes,
    no touches to other filters in servers.js/roles.js/financials.js)
  * Calls downgradeToAwakened() to strip tier role and assign Awakened
  * Audit log entry tagged with policy
- New charge.refunded handler: hard ban with Trinity appeal eligibility
  * Mirrors charge.dispute.created pattern
  * appeal_eligible: true flag in banned_users.notes
  * removeAllRoles() (NOT demote — refund is a hard ban)
- Added downgradeToAwakened to stripe.js imports

Left unchanged (intentionally):
- invoice.payment_failed: marks past_due, trust Stripe's retry logic
- invoice.payment_succeeded: clears grace period (harmless legacy field reset)
- charge.dispute.created: already correct under new policy
- checkout.session.completed: syncRole already handles Model A (Awakened
  automatically assigned on any first purchase via tier role replacement)

Co-authored with Michael (The Wizard)
Task #126 — Soft launch blocker
2026-04-11 23:04:30 +00:00
Claude (Chronicler #78)
c07c29c60c feat: Add servers-api Cloudflare Worker to git (recovered from dashboard)
Worker proxies Pterodactyl client API for website server list.
Live status + player counts, CORS-locked, 60s cache.
Was only in Cloudflare Dashboard — known gap now closed.
Recovered via Cloudflare MCP connector audit.

Chronicler #78 | firefrost-services
2026-04-11 18:00:44 +00:00
Claude (Chronicler #78)
aca7669243 feat: Add spec_path field — link tasks to git documentation
- spec_path column added to tasks table
- API POST/PATCH support spec_path field
- Discord /tasks detail view shows '📄 Full Spec' link to Gitea when spec exists
- Backfilled 7 existing tasks with spec directory paths

Architecture: Database tracks state, Git stores documentation, they link to each other.

Chronicler #78 | firefrost-services
2026-04-11 14:38:24 +00:00
Claude (Chronicler #78)
b8f9926e9b feat: Task #116 — Trinity Console Tasks Module
- Tasks page at /admin/tasks with filterable table
- Status/owner inline dropdowns (change via form submit)
- + New Task modal with title, description, priority, owner
- ✓ Done button on hover per row
- Stats bar: active, in progress, blocked, high priority, completed
- Show All toggle for done/obsolete tasks
- Sidebar link under Operations (right after Dashboard)
- Added to About page module registry

Source of truth: PostgreSQL tasks table (shared with Discord /tasks)

Chronicler #78 | firefrost-services
2026-04-11 14:22:21 +00:00
Claude (Chronicler #78)
78179de2bc feat: /tasks detail view + In Progress button
- /tasks number:26 shows full task detail embed
  (description, tags, status, priority, owner, dates)
- Mark Done, In Progress, and Take Task buttons on detail view
- task_progress_ button handler sets status to in_progress

Chronicler #78 | firefrost-services
2026-04-11 14:13:16 +00:00
Claude (Chronicler #78)
48f74e8658 feat: ChatOps Task Management System (Gemini-architected)
Database:
- tasks table in PostgreSQL (id, task_number, title, status, priority, owner, tags)
- 45 tasks migrated from BACKLOG.md + tasks-index files
- Indexes on status, priority, owner, task_number

API (for Chroniclers/Catalysts):
- GET /api/internal/tasks — list with filters (status, priority, owner)
- GET /api/internal/tasks/summary — stats by status and priority
- POST /api/internal/tasks — create new task (auto-numbers)
- PATCH /api/internal/tasks/:id — update status/priority/owner

Discord (for Meg/Holly/Michael):
- /tasks command with filter options (open, in_progress, mine, high, active, done, all)
- Mark Done buttons — one tap to complete a task
- Take Task buttons — claim unassigned tasks
- Color-coded priority and status emoji
- Staff-only access

Architecture: PostgreSQL → Arbiter API → Discord buttons (ChatOps)
Gemini consultation: gemini-task-management-redesign-2026-04-11.md

Chronicler #78 | firefrost-services
2026-04-11 13:56:45 +00:00
Claude (Chronicler #78)
075ab899c5 fix: Add MCP Logs to About page module registry
Chronicler #78 | firefrost-services
2026-04-11 13:18:05 +00:00
Claude (Chronicler #78)
03974d1f13 feat: Task #109 — MCP Logging in Trinity Console (v2.3.0)
Arbiter changes:
- POST /api/internal/mcp/log endpoint in api.js
- MCP Logs admin route (/admin/mcp-logs) with filters, stats, pagination
- EJS view with expandable detail rows, server color badges
- Sidebar link under System group

Trinity Core v2.3.0:
- logToArbiter() function POSTs to Arbiter after every command
- Both MCP (Claude.ai) and REST (/exec) paths log with execution timing
- Async logging — doesn't block command response

Database:
- mcp_logs table created on Command Center (indexes on server, time, success)

Architecture:
  Trinity Core → command → response + async POST → Arbiter → PostgreSQL → Trinity Console

Chronicler #78 | firefrost-services
2026-04-11 11:55:22 +00:00
Claude (Chronicler #78)
0b61d38419 feat: Dashboard — Social Overview above New Features, add new modules
- Moved Social Overview card above New Features card
- Added Infrastructure module to New Features (topology map)
- Added Social Analytics to New Features (engagement tracking)
- Added About & Deploy to New Features (version info)
- Kept Discord Dashboard in New Features
- Removed Financials from New Features (it's established now)

Chronicler #78 | firefrost-services
2026-04-11 10:51:22 +00:00
Claude (Chronicler #78)
bd783093a9 feat: Sidebar reorganization + About page
Sidebar changes:
- Grouped nav items: Operations, Business, Community, Infrastructure, System
- Section labels with uppercase tracking
- Removed Deploy button from sidebar
- Cleaner layout with overflow scroll

About page (/admin/about):
- Console version, Node.js version, Arbiter uptime, module count
- Module registry with version and status badges (stable/new/beta)
- Deploy Arbiter button (moved from sidebar)
- Health check polling after deploy
- Credits footer

Header bar:
- Added ℹ️ About icon next to dark mode toggle
- Active state highlighting when on About page

Chronicler #78 | firefrost-services
2026-04-11 10:46:42 +00:00
Claude (Chronicler #78)
4788140c2c fix: Node clicks blocked after dragging — reset dragMoved on mouseup/touchend
dragMoved flag was only reset in wrap mousedown, which skips for node clicks.
After any drag, dragMoved stayed true forever, blocking all showServer/showExternal calls.
Fix: setTimeout reset on mouseup/touchend (10ms delay lets click fire first).

Chronicler #78 | firefrost-services
2026-04-11 10:38:32 +00:00
Claude (Chronicler #78)
0c7dad36ea feat: Add zoom/pan/pinch to Infrastructure topology
- Mouse wheel zoom (centered on cursor position)
- Click-drag to pan
- Touch pinch-zoom for mobile
- Touch drag to pan on mobile
- Zoom controls: +, −, percentage display, reset (⌂)
- Zoom range: 50% to 300%
- Drag guard prevents accidental clicks after panning
- Canvas connections redraw correctly at all zoom levels
- Smooth CSS transitions on zoom, disabled during drag

Chronicler #78 | firefrost-services
2026-04-11 10:35:03 +00:00
Claude (Chronicler #78)
2e3d272e26 fix: RAM percentage parsing — handle Mi vs Gi units
Panel VPS and Trinity Core report used RAM in Mi (e.g. 703Mi)
while total is in Gi (e.g. 1.9Gi). parseFloat gave 703/1.9 = 37000%.
Now normalizes both values to Gi before calculating percentage.

Chronicler #78 | firefrost-services
2026-04-11 10:30:43 +00:00
Claude (Chronicler #78)
55385634f2 feat: Add REST API endpoints to Trinity Core (v2.2.0)
- GET /servers — list available servers (for Arbiter)
- POST /exec — execute command on server (for Arbiter)
- REST endpoints run alongside MCP protocol
- MCP for Claude.ai connector, REST for Arbiter internal calls
- Fixes Infrastructure module 404 errors
- Version bump 2.1.0 → 2.2.0

Chronicler #78 | firefrost-services
2026-04-11 10:27:08 +00:00
Claude (Chronicler #78)
a83766efb4 feat: Add Infrastructure module to Trinity Console
New module: /admin/infrastructure
- Interactive topology map showing all 8 servers + external services
- Live data from Trinity Core MCP API (cached 60s)
- Bezier curve connections color-coded by type (external/internal/SSH/MCP)
- Hover highlights all connections to/from a node
- Click to drill into server detail (CPU, RAM, disk, load, services)
- Game server list for TX1/NC1 with RAM allocation totals
- External service detail (Cloudflare, Stripe, Discord, Claude.ai)
- Fleet summary bar (8 servers, 22 games, ~42 containers)
- Refresh button forces cache clear + re-audit
- Mobile responsive grid layout
- JetBrains Mono typography, Fire/Frost/Arcane color scheme

Files:
- src/routes/admin/infrastructure.js (route + Trinity Core API client)
- src/views/admin/infrastructure/index.ejs (topology + detail views)
- Modified: src/routes/admin/index.js (registered infrastructure router)
- Modified: src/views/layout.ejs (added nav link)

Chronicler #78 | firefrost-services
2026-04-11 10:24:05 +00:00
Claude (Chronicler #78)
5c980ea681 feat: Add Trinity Core MCP server to version control (v2.1.0)
- Added services/trinity-core/ with index.js, package.json, .gitignore
- v2.1.0 adds local self-execution (trinity-core can audit itself)
- Added executeLocal() function for localhost commands
- SERVERS object now includes trinity-core with local: true flag
- Version bumped from 2.0.0 to 2.1.0
- Previously lived only on Pi at ~/mcp-server/ with no backup

Deployment: Edit here, push to Gitea, curl raw file to Pi, restart service

Chronicler #78 | firefrost-services
2026-04-11 10:07:32 +00:00
Claude
483d12c34d Archive obsolete services (arbiter v2.0, whitelist-manager)
Moved to services/_archived/:
- arbiter/ (v2.0.0) - superseded by arbiter-3.0/
- whitelist-manager/ - merged into Trinity Console

Added README explaining what's archived and why.

DO NOT DEPLOY archived services - kept for historical reference only.

Chronicler #76
2026-04-11 08:00:17 +00:00
Claude
7c534b53a4 Fix: Add socialTotals to correct dashboard route file
Was editing wrong file (admin.js vs admin/index.js)

Chronicler #76
2026-04-10 22:26:10 +00:00
Claude
918fb99b87 Add Social Overview card to Trinity Console dashboard
- Shows cross-platform totals (posts, views, likes, comments)
- Breaks down by platform with icons
- Clickable link to full Social Analytics page

Chronicler #76
2026-04-10 22:23:21 +00:00
Claude
74f7876955 Fix social sync: update post_title and post_url on existing posts
Previously only INSERT included these fields, UPDATE ignored them.

Chronicler #76
2026-04-10 22:20:06 +00:00
Claude
274edccf8a Add post_title to TikTok sync
- Request title field from TikTok API
- Truncate to 80 chars for clean display
- Send post_title in sync payload

Chronicler #76
2026-04-10 22:18:14 +00:00
Claude
21b6fa9788 Fix TikTok sync payload to match Arbiter API
- Use platform_post_id + metrics object for sync endpoint
- Use total_followers for snapshot endpoint

Chronicler #76
2026-04-10 22:15:24 +00:00
Claude
942335156f Fix TikTok max_count: API limit is 20, not 50
Chronicler #76
2026-04-10 22:12:08 +00:00
Claude
c0750ea2c1 Fix TikTok sync: use jq instead of Python heredoc
Python heredoc was breaking on emoji characters in video titles.
jq handles JSON parsing properly.

Chronicler #76
2026-04-10 22:08:58 +00:00