this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Fix duplicate launchd agent conflict

Keep com.alice.claude-plan-saver naming.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

alice 96fc330b 96f7ec26

+85
+85
.claude/plans/0002-circle-tweet-cleaner-web-app.md
··· 1 + # Circle Tweet Cleaner Web App 2 + 3 + ## Overview 4 + Port the CLI circle-tweet-cleaner to a standalone Vite + React static site where users can drop in their Twitter archive zip and get back a cleaned zip with circle tweets removed. 5 + 6 + ## Tech Stack 7 + - Vite + React + TypeScript 8 + - JSZip (browser zip handling) 9 + - idb-keyval (IndexedDB for progress persistence > 5MB localStorage limit) 10 + - No backend needed - syndication API is CORS-enabled 11 + 12 + ## Project Structure 13 + ``` 14 + circle-tweet-cleaner-web/ 15 + ├── src/ 16 + │ ├── main.tsx 17 + │ ├── App.tsx 18 + │ ├── components/ 19 + │ │ ├── DropZone.tsx # Zip upload + resume detection 20 + │ │ ├── ProgressBar.tsx # Detection progress 21 + │ │ ├── StatsPanel.tsx # Real-time stats 22 + │ │ ├── StatusLog.tsx # Scrolling event log 23 + │ │ └── DownloadButton.tsx # Cleaned zip download 24 + │ ├── lib/ 25 + │ │ ├── syndication.ts # Port from CLI (token calc, API) 26 + │ │ ├── types.ts # Port from CLI 27 + │ │ ├── zip.ts # JSZip wrapper 28 + │ │ ├── parse-tweets.ts # Parse window.YTD format 29 + │ │ ├── detection.ts # Detection orchestration 30 + │ │ ├── cleaning.ts # Filter + rebuild zip 31 + │ │ └── storage.ts # IndexedDB persistence 32 + │ └── hooks/ 33 + │ ├── useDetection.ts # Detection state machine 34 + │ └── useProgress.ts # Persistence layer 35 + ``` 36 + 37 + ## Implementation Steps 38 + 39 + ### Phase 1: Project Setup 40 + 1. Create new Vite + React + TS project in `circle-tweet-cleaner-web/` 41 + 2. Install deps: `jszip`, `idb-keyval` 42 + 3. Port `src/types.ts` verbatim from CLI 43 + 4. Port `src/syndication.ts` (remove console.log, keep BigInt token calc) 44 + 45 + ### Phase 2: Zip I/O 46 + 1. Create `lib/zip.ts` - JSZip wrapper for parseArchive/generateCleanedZip 47 + 2. Create `lib/parse-tweets.ts` - Parse `window.YTD.tweets.part0 = [...]` format 48 + 3. Filter out `__MACOSX` entries (same bug we just fixed in community-archive) 49 + 50 + ### Phase 3: Detection Logic 51 + 1. Create `lib/detection.ts` - async generator yielding progress events 52 + 2. Port date filtering (May 2022 - Nov 2023), RT skipping, deleted-tweets exclusion 53 + 3. Batch processing with 20 concurrent requests 54 + 4. Exponential backoff on 429s 55 + 56 + ### Phase 4: Persistence 57 + 1. Create `lib/storage.ts` - IndexedDB via idb-keyval 58 + 2. Hash archive (SHA-256) to identify same file on resume 59 + 3. Save progress every 100 tweets 60 + 4. Resume flow: detect existing progress, offer resume or fresh start 61 + 62 + ### Phase 5: UI Components 63 + 1. DropZone - drag/drop + click to select, validates zip, shows resume prompt 64 + 2. ProgressBar - % complete, ETA, rate limit indicator 65 + 3. StatsPanel - candidates, checked, circle found, public, errors 66 + 4. StatusLog - scrolling log of `[CIRCLE] id`, `[ERROR] id`, rate limit warnings 67 + 5. DownloadButton - generates cleaned zip blob, triggers download 68 + 69 + ### Phase 6: Polish 70 + 1. Error states (invalid archive, network failures) 71 + 2. Pause/resume controls 72 + 3. Mobile-friendly layout 73 + 4. Accessible (aria labels) 74 + 75 + ## Key Files to Port From CLI 76 + - `src/syndication.ts` - BigInt token calculation, retry logic (lines 1-80) 77 + - `src/types.ts` - Tweet, Progress, SyndicationResult interfaces 78 + - `src/detect.ts` - Date range constants, candidate filtering logic 79 + - `src/clean.ts` - tweets.js serialization format preservation 80 + 81 + ## Deployment 82 + Static site - deploy to Vercel/Netlify/GitHub Pages with zero config. 83 + 84 + ## Location 85 + New branch `web` in current repo (circle-tweet-cleaner). Web app code goes in `web/` folder to keep it separate from CLI code in `src/`.