fast-resume 1.12.8__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,545 @@
1
+ Metadata-Version: 2.4
2
+ Name: fast-resume
3
+ Version: 1.12.8
4
+ Summary: Fuzzy finder for coding agent session history
5
+ License-File: LICENSE
6
+ Requires-Python: >=3.14
7
+ Requires-Dist: click>=8.0.0
8
+ Requires-Dist: humanize>=4.14.0
9
+ Requires-Dist: orjson>=3.10.0
10
+ Requires-Dist: rich>=13.0.0
11
+ Requires-Dist: tantivy>=0.25.0
12
+ Requires-Dist: textual-image>=0.8.4
13
+ Requires-Dist: textual>=0.47.0
14
+ Description-Content-Type: text/markdown
15
+
16
+ <p align="center">
17
+ <img src="assets/logo.png" alt="fast-resume" width="120" height="120">
18
+ </p>
19
+
20
+ # fast-resume
21
+
22
+ [![PyPI version](https://img.shields.io/pypi/v/fast-resume)](https://pypi.org/project/fast-resume/)
23
+ [![PyPI downloads](https://img.shields.io/pypi/dm/fast-resume)](https://pypi.org/project/fast-resume/)
24
+
25
+ Search and resume conversations across Claude Code, Codex, and more, all from a single place.
26
+
27
+ ## Why fast-resume?
28
+
29
+ Coding agents are really good right now, so I'm using a bunch of them. Sometimes I remember I, or the LLM, mentioned something specific in a previous session, and I want to go back to it.
30
+
31
+ The problem is that currently, agents do have a resume feature, but either they don't support searching, or the search is very basic (e.g., title only).
32
+
33
+ That's why I built `fast-resume`: a command-line tool that aggregates all your coding agent sessions into a single searchable index, so you can quickly find and resume any session.
34
+
35
+ ![demo](https://github.com/user-attachments/assets/5ea9c2a5-a7c0-41bf-9357-394aeaaa0a06)
36
+
37
+ ## Features
38
+
39
+ - **Unified Search**: One search box to find sessions across all your coding agents
40
+ - **Full-Text Search**: Search not just titles, but the entire conversation content (user messages and assistant responses)
41
+ - **Very fast**: Built on the Rust-powered Tantivy search engine for blazing-fast indexing and searching
42
+ - **Fuzzy Matching**: Typo-tolerant search with smart ranking (exact matches boosted)
43
+ - **Direct Resume**: Select, Enter, you're back in your session
44
+ - **Beautiful TUI**: fzf-style interface with agent icons, color-coded results, and live preview
45
+ - **Update Notifications**: Get notified when a new version is available
46
+
47
+ ## Supported Agents
48
+
49
+ | Agent | Data Location | Resume Command |
50
+ | ------------------- | --------------------------------------------- | ------------------------------- |
51
+ | **Claude Code** | `~/.claude/projects/` | `claude --resume <id>` |
52
+ | **Codex CLI** | `~/.codex/sessions/` | `codex resume <id>` |
53
+ | **Copilot CLI** | `~/.copilot/session-state/` | `copilot --resume <id>` |
54
+ | **VS Code Copilot** | `~/Library/Application Support/Code/` (macOS) | `code <directory>` |
55
+ | **Crush** | `~/.local/share/crush/projects.json` | _(interactive only)_ |
56
+ | **OpenCode** | `~/.local/share/opencode/storage/` | `opencode <dir> --session <id>` |
57
+ | **Vibe** | `~/.vibe/logs/session/` | `vibe --resume <id>` |
58
+
59
+ ## Installation
60
+
61
+ ```bash
62
+ # Run directly (no install needed)
63
+ uvx --from fast-resume fr
64
+
65
+ # Or install permanently
66
+ uv tool install fast-resume
67
+ fr
68
+ ```
69
+
70
+ ## Usage
71
+
72
+ ### Interactive TUI
73
+
74
+ ```bash
75
+ # Open the TUI with all sessions
76
+ fr
77
+
78
+ # Pre-filter search query
79
+ fr "authentication bug"
80
+
81
+ # Filter by agent
82
+ fr -a claude
83
+ fr -a codex
84
+
85
+ # Filter by directory
86
+ fr -d myproject
87
+
88
+ # Combine filters
89
+ fr -a claude -d backend "api error"
90
+ ```
91
+
92
+ ### Keyword Search Syntax
93
+
94
+ Filter directly in the search box using keywords:
95
+
96
+ ```bash
97
+ agent:claude # Filter by agent
98
+ agent:claude,codex # Multiple agents (OR)
99
+ -agent:vibe # Exclude agent
100
+ agent:claude,!codex # Include claude, exclude codex
101
+
102
+ dir:myproject # Filter by directory (substring)
103
+ dir:backend,!test # Include backend, exclude test
104
+
105
+ date:today # Sessions from today
106
+ date:yesterday # Sessions from yesterday
107
+ date:<1h # Within the last hour
108
+ date:<2d # Within the last 2 days
109
+ date:>1w # Older than 1 week
110
+ date:week # Within the last week
111
+ date:month # Within the last month
112
+ ```
113
+
114
+ Combine keywords with free-text search:
115
+
116
+ ```bash
117
+ fr "agent:claude date:<1d api bug"
118
+ fr "dir:backend -agent:vibe auth"
119
+ ```
120
+
121
+ **Autocomplete**: Type `agent:cl` and press `Tab` to complete to `agent:claude`.
122
+
123
+ ### Non-Interactive Mode
124
+
125
+ ```bash
126
+ # List sessions in terminal (no TUI)
127
+ fr --no-tui
128
+
129
+ # Just list, don't offer to resume
130
+ fr --list
131
+
132
+ # Force rebuild the index
133
+ fr --rebuild
134
+
135
+ # View your usage statistics
136
+ fr --stats
137
+ ```
138
+
139
+ ### Yolo Mode
140
+
141
+ Resume sessions with auto-approve / skip-permissions flags:
142
+
143
+ | Agent | Flag Added | Auto-detected |
144
+ | --------------- | -------------------------------------------- | ------------- |
145
+ | Claude | `--dangerously-skip-permissions` | No |
146
+ | Codex | `--dangerously-bypass-approvals-and-sandbox` | Yes |
147
+ | Copilot CLI | `--allow-all-tools --allow-all-paths` | No |
148
+ | Vibe | `--auto-approve` | Yes |
149
+ | OpenCode | _(config-based)_ | — |
150
+ | Crush | _(no CLI resume)_ | — |
151
+ | VS Code Copilot | _(n/a)_ | — |
152
+
153
+ **Auto-detection:** Codex and Vibe store the permissions mode in their session files. Sessions originally started in yolo mode are automatically resumed in yolo mode.
154
+
155
+ **Interactive prompt:** For agents that support yolo but don't store it (Claude, Copilot CLI), you'll see a modal asking whether to resume in yolo mode. Use Tab to toggle, Enter to confirm.
156
+
157
+ **Force yolo:** Use `fr --yolo` to skip the prompt and always resume in yolo mode, if supported.
158
+
159
+ ### Command Reference
160
+
161
+ ```
162
+ Usage: fr [OPTIONS] [QUERY]
163
+
164
+ Arguments:
165
+ QUERY Search query (optional)
166
+
167
+ Options:
168
+ -a, --agent [claude|codex|copilot-cli|copilot-vscode|crush|opencode|vibe]
169
+ Filter by agent
170
+ -d, --directory TEXT Filter by directory (substring match)
171
+ --no-tui Output list to stdout instead of TUI
172
+ --list Just list sessions, don't resume
173
+ --rebuild Force rebuild the session index
174
+ --stats Show index statistics
175
+ --yolo Resume with auto-approve/skip-permissions flags
176
+ --version Show version
177
+ --help Show this message and exit
178
+ ```
179
+
180
+ ## Keybindings
181
+
182
+ ### Navigation
183
+
184
+ | Key | Action |
185
+ | ----------------------- | ---------------------------------- |
186
+ | `↑` / `↓` | Move selection up/down |
187
+ | `j` / `k` | Move selection up/down (vim-style) |
188
+ | `Page Up` / `Page Down` | Move by 10 rows |
189
+ | `Enter` | Resume selected session |
190
+ | `/` | Focus search input |
191
+
192
+ ### Preview & Actions
193
+
194
+ | Key | Action |
195
+ | --------- | ------------------------------------- |
196
+ | `Ctrl+\`` | Toggle preview pane |
197
+ | `+` / `-` | Resize preview pane |
198
+ | `Tab` | Accept autocomplete suggestion |
199
+ | `c` | Copy full resume command to clipboard |
200
+ | `Ctrl+P` | Open command palette |
201
+ | `q`/`Esc` | Quit |
202
+
203
+ ### Yolo Mode Modal
204
+
205
+ | Key | Action |
206
+ | --------------- | ----------------- |
207
+ | `Tab` / `←` `→` | Toggle selection |
208
+ | `Enter` | Confirm selection |
209
+ | `y` | Select Yolo |
210
+ | `n` | Select No |
211
+ | `Esc` | Cancel |
212
+
213
+ ## Statistics Dashboard
214
+
215
+ Run `fr --stats` to see analytics about your coding sessions:
216
+
217
+ ```
218
+ Index Statistics
219
+
220
+ Total sessions 751
221
+ Total messages 13,799
222
+ Avg messages/session 18.4
223
+ Index size 15.5 MB
224
+ Index location ~/.cache/fast-resume/tantivy_index
225
+ Date range 2023-11-15 to 2025-12-22
226
+
227
+ Data by Agent
228
+
229
+ ┌────────────────┬───────┬──────────┬──────────┬──────────┬──────────┬─────────────┐
230
+ │ Agent │ Files │ Disk │ Sessions │ Messages │ Content │ Data Dir │
231
+ ├────────────────┼───────┼──────────┼──────────┼──────────┼──────────┼─────────────┤
232
+ │ claude │ 477 │ 312.9 MB │ 377 │ 10,415 │ 3.1 MB │ ~/.claude/… │
233
+ │ copilot-vscode │ 191 │ 146.0 MB │ 189 │ 954 │ 1.4 MB │ ~/Library/… │
234
+ │ codex │ 107 │ 23.6 MB │ 89 │ 321 │ 890.6 kB │ ~/.codex/… │
235
+ │ opencode │ 9275 │ 46.3 MB │ 72 │ 1,912 │ 597.7 kB │ ~/.local/… │
236
+ │ vibe │ 12 │ 858.2 kB │ 12 │ 138 │ 380.0 kB │ ~/.vibe/… │
237
+ │ crush │ 3 │ 1.0 MB │ 7 │ 44 │ 15.2 kB │ ~/.local/… │
238
+ │ copilot-cli │ 5 │ 417.1 kB │ 5 │ 15 │ 6.9 kB │ ~/.copilot… │
239
+ └────────────────┴───────┴──────────┴──────────┴──────────┴──────────┴─────────────┘
240
+
241
+ Activity by Day
242
+
243
+ Mon ██████████ 89
244
+ Tue ██████████ 86
245
+ Wed █████ 44
246
+ Thu ██████████████ 115
247
+ Fri █████████████ 112
248
+ Sat ████████████████████ 163
249
+ Sun █████████████████ 142
250
+
251
+ Activity by Hour
252
+
253
+ 0h ▄▁ ▄▄▅▂▂▂▂▂▃▃▃▅▅█ 23h
254
+ Peak hours: 23:00 (99), 22:00 (63), 12:00 (63)
255
+
256
+ Top Directories
257
+
258
+ ┌───────────────────────┬──────────┬──────────┐
259
+ │ Directory │ Sessions │ Messages │
260
+ ├───────────────────────┼──────────┼──────────┤
261
+ │ ~/git/openvpn-install │ 234 │ 5,597 │
262
+ │ ~/lab/larafeed │ 158 │ 2,590 │
263
+ │ ~/lab/fast-resume │ 81 │ 2,027 │
264
+ │ ... │ │ │
265
+ └───────────────────────┴──────────┴──────────┘
266
+ ```
267
+
268
+ ## How It Works
269
+
270
+ ### Architecture
271
+
272
+ ```
273
+ ┌────────────────────────────────────────────────────────────────────────────────────────┐
274
+ │ SessionSearch │
275
+ │ │
276
+ │ • Orchestrates adapters in parallel (ThreadPoolExecutor) │
277
+ │ • Compares file mtimes to detect changes (incremental updates) │
278
+ │ • Delegates search queries to Tantivy index │
279
+ └────────────────────────────────────────────────────────────────────────────────────────┘
280
+ │ │
281
+ ┌────────────┴────────────┐ │
282
+ ▼ ▼ ▼
283
+ ┌──────────────────┐ ┌───────────────────────────────────────────────────────────────────────────────┐
284
+ │ TantivyIndex │ │ Adapters │
285
+ │ │ │ ┌────────┐ ┌───────┐ ┌───────┐ ┌─────────┐ ┌───────┐ ┌────────┐ ┌────┐ │
286
+ │ • Fuzzy search │◄───│ │ Claude │ │ Codex │ │Copilot│ │ Copilot │ │ Crush │ │OpenCode│ │Vibe│ │
287
+ │ • mtime tracking │ │ │ │ │ │ │ CLI │ │ VS Code │ │ │ │ │ │ │ │
288
+ │ │ │ └───┬────┘ └───┬───┘ └───┬───┘ └────┬────┘ └───┬───┘ └───┬────┘ └─┬──┘ │
289
+ │ ~/.cache/ │ │ │ │ │ │ │ │ │ │
290
+ │ fast-resume/ │ └──────┼──────────┼─────────┼──────────┼──────────┼─────────┼────────┼───────────┘
291
+ └──────────────────┘ ▼ ▼ ▼ ▼ ▼ ▼ ▼
292
+ ~/.claude/ ~/.codex/ ~/.copilot/ VS Code/ crush.db opencode/ ~/.vibe/
293
+ ```
294
+
295
+ ### Session Parsing
296
+
297
+ Each agent stores sessions differently. Adapters normalize them into a common `Session` structure:
298
+
299
+ | Agent | Format | Parsing Strategy |
300
+ | -------------- | ---------------------------------------------------- | ------------------------------------------------------------------------------------------- |
301
+ | Claude Code | JSONL in `~/.claude/projects/<project>/*.jsonl` | Stream line-by-line, extract `user`/`assistant` messages, skip `agent-*` subprocess files |
302
+ | Codex | JSONL in `~/.codex/sessions/**/*.jsonl` | Line-by-line parsing, extract from `session_meta`, `response_item`, and `event_msg` entries |
303
+ | Copilot CLI | JSONL in `~/.copilot/session-state/*.jsonl` | Line-by-line parsing, extract `user.message` and `assistant.message` types |
304
+ | Copilot VSCode | JSON in VS Code's `workspaceStorage/*/chatSessions/` | Parse `requests` array with message text and response values |
305
+ | Crush | SQLite DB at `<project>/crush.db` | Query `sessions` and `messages` tables directly, parse JSON `parts` column |
306
+ | OpenCode | Split JSON in `~/.local/share/opencode/storage/` | Join `session/<hash>/ses_*.json` + `message/<id>/msg_*.json` + `part/<id>/*.json` |
307
+ | Vibe | JSON in `~/.vibe/logs/session/session_*.json` | Parse `messages` array with role-based content |
308
+
309
+ **The normalized Session structure:**
310
+
311
+ ```python
312
+ @dataclass
313
+ class Session:
314
+ id: str # Unique identifier (usually filename or UUID)
315
+ agent: str # "claude", "codex", "copilot-cli", "copilot-vscode", "crush", "opencode", "vibe"
316
+ title: str # Summary or first user message (max 100 chars)
317
+ directory: str # Working directory where session was created
318
+ timestamp: datetime # Last modified time
319
+ preview: str # First 500 chars for preview pane
320
+ content: str # Full conversation text (» user, ␣␣ assistant)
321
+ message_count: int # Conversation turns (user + assistant, excludes tool results)
322
+ mtime: float # File mtime for incremental update detection
323
+ ```
324
+
325
+ **What gets indexed:**
326
+
327
+ - User text messages (the actual prompts you typed)
328
+ - Assistant text responses
329
+
330
+ **What's excluded from indexing:**
331
+
332
+ - Tool results (file contents, command outputs, API responses)
333
+ - Tool use/calls (function invocations)
334
+ - Meta messages (system prompts, context summaries)
335
+ - Local command outputs (slash commands like `/context`)
336
+
337
+ This keeps the index focused on the actual conversation and avoids bloating it with large tool outputs that are rarely useful for search.
338
+
339
+ ### Indexing
340
+
341
+ **Incremental updates** avoid re-parsing on every launch:
342
+
343
+ 1. Load known sessions from Tantivy index with their `mtime` values
344
+ 2. Scan session files, compare mtimes against known values
345
+ 3. Only parse files where `current_mtime > known_mtime + 0.001`
346
+ 4. Detect deleted sessions (in index but not on disk)
347
+ 5. Apply changes atomically: delete removed, upsert modified
348
+
349
+ **Parallel loading** via `ThreadPoolExecutor`:
350
+
351
+ ```python
352
+ with ThreadPoolExecutor(max_workers=len(self.adapters)) as executor:
353
+ futures = {executor.submit(get_incremental, a): a for a in self.adapters}
354
+ for future in as_completed(futures):
355
+ new_or_modified, deleted_ids = future.result()
356
+ self._index.update_sessions(new_or_modified)
357
+ on_progress() # TUI updates as each adapter completes
358
+ ```
359
+
360
+ **Schema versioning**: A `.schema_version` file tracks the index schema. If it doesn't match the code's `SCHEMA_VERSION` constant, the entire index is deleted and rebuilt. This prevents deserialization errors after upgrades.
361
+
362
+ ### Search
363
+
364
+ [Tantivy](https://github.com/quickwit-oss/tantivy) is a Rust full-text search library (powers Quickwit, similar to Lucene). We use it via [tantivy-py](https://github.com/quickwit-oss/tantivy-py).
365
+
366
+ **Hybrid search** combines exact and fuzzy matching for best results:
367
+
368
+ ```python
369
+ # Exact match (boosted 5x) - uses BM25 scoring
370
+ exact_query = index.parse_query(query, ["title", "content"])
371
+ boosted_exact = tantivy.Query.boost_query(exact_query, 5.0)
372
+
373
+ # Fuzzy match (edit distance 1) - for typo tolerance
374
+ for term in query.split():
375
+ fuzzy_title = tantivy.Query.fuzzy_term_query(schema, "title", term, distance=1, prefix=True)
376
+ fuzzy_content = tantivy.Query.fuzzy_term_query(schema, "content", term, distance=1, prefix=True)
377
+ ...
378
+
379
+ # Combine: exact OR fuzzy (exact scores higher due to boost)
380
+ tantivy.Query.boolean_query([
381
+ (tantivy.Occur.Should, boosted_exact),
382
+ (tantivy.Occur.Should, fuzzy_query),
383
+ ])
384
+ ```
385
+
386
+ This ensures exact matches rank first while still finding typos like `auth midleware` → "authentication middleware".
387
+
388
+ **Query lifecycle:**
389
+
390
+ ```
391
+ ┌─────────────┐ 50ms ┌─────────────┐ background ┌─────────────┐
392
+ │ Keystroke │ ────────► │ Debounce │ ───────────► │ Worker │
393
+ └─────────────┘ timer └─────────────┘ thread └──────┬──────┘
394
+
395
+ ┌─────────────┐ ┌──────▼──────┐
396
+ │ Render │ ◄─────────── │ Tantivy │
397
+ │ Table │ results │ Query │
398
+ └─────────────┘ └─────────────┘
399
+ ```
400
+
401
+ ### TUI
402
+
403
+ **Streaming results**: Sessions appear as each adapter completes, not after all finish.
404
+
405
+ - **Fast path**: Index up-to-date → load synchronously, no spinner
406
+ - **Slow path**: Changes detected → spinner, stream results via `on_progress()` callback
407
+
408
+ **Preview context**: When searching, the preview pane jumps to the matching portion:
409
+
410
+ ```python
411
+ for term in query.lower().split():
412
+ pos = content.lower().find(term)
413
+ if pos != -1:
414
+ start = max(0, pos - 100) # Show ~100 chars before match
415
+ preview_text = content[start:start + 1500]
416
+ break
417
+ ```
418
+
419
+ Matching terms are highlighted with Rich's `Text.stylize()`.
420
+
421
+ ### Resume Handoff
422
+
423
+ When you press Enter on a session, fast-resume hands off to the original agent:
424
+
425
+ ```python
426
+ # In cli.py after TUI exits
427
+ resume_cmd, resume_dir = run_tui(query=query, agent_filter=agent)
428
+
429
+ if resume_cmd:
430
+ # 1. Change to the session's original working directory
431
+ os.chdir(resume_dir)
432
+
433
+ # 2. Replace current process with agent's resume command
434
+ os.execvp(resume_cmd[0], resume_cmd)
435
+ ```
436
+
437
+ `os.execvp()` replaces the Python process entirely with the agent CLI. This means:
438
+
439
+ - No subprocess overhead
440
+ - Shell history shows `claude --resume xyz`, not `fr`
441
+ - Agent inherits the correct working directory
442
+ - fast-resume process is gone after handoff
443
+
444
+ Each adapter returns the appropriate command:
445
+
446
+ | Agent | Resume Command | With `--yolo` |
447
+ | -------------- | ------------------------------- | -------------------------------------------------------------- |
448
+ | Claude | `claude --resume <id>` | `claude --dangerously-skip-permissions --resume <id>` |
449
+ | Codex | `codex resume <id>` | `codex --dangerously-bypass-approvals-and-sandbox resume <id>` |
450
+ | Copilot CLI | `copilot --resume <id>` | `copilot --allow-all-tools --allow-all-paths --resume <id>` |
451
+ | Copilot VSCode | `code <directory>` | _(no change)_ |
452
+ | OpenCode | `opencode <dir> --session <id>` | _(no change)_ |
453
+ | Vibe | `vibe --resume <id>` | `vibe --auto-approve --resume <id>` |
454
+ | Crush | `crush` | _(no change)_ |
455
+
456
+ ### Performance
457
+
458
+ Why fast-resume feels instant:
459
+
460
+ - **Tantivy (Rust)**: Search engine written in Rust, accessed via Python bindings. Handles fuzzy queries over 10k+ sessions in <10ms
461
+ - **Incremental updates**: Only re-parse files where `mtime` changed. Second launch with no changes: ~50ms total
462
+ - **Parallel adapters**: All adapters run simultaneously in ThreadPoolExecutor. Total time = slowest adapter, not sum
463
+ - **Debounced search**: 50ms debounce prevents wasteful searches while typing
464
+ - **Background workers**: Search runs in thread, UI never blocks
465
+ - **orjson**: Rust-based JSON parsing, ~10x faster than stdlib json
466
+ - **Streaming results**: Sessions appear as each adapter completes, not after all finish
467
+
468
+ Typical performance on a machine with ~500 sessions:
469
+
470
+ - Cold start (empty index): ~2s
471
+ - Warm start (no changes): ~50ms
472
+ - Search query: <10ms
473
+
474
+ ## Development
475
+
476
+ ```bash
477
+ # Clone and setup
478
+ git clone https://github.com/angristan/fast-resume.git
479
+ cd fast-resume
480
+ uv sync
481
+
482
+ # Run locally
483
+ uv run fr
484
+
485
+ # Install pre-commit hooks
486
+ uv run pre-commit install
487
+
488
+ # Run tests
489
+ uv run pytest -v
490
+
491
+ # Lint and format
492
+ uv run ruff check .
493
+ uv run ruff format .
494
+ ```
495
+
496
+ ### Project Structure
497
+
498
+ ```
499
+ fast-resume/
500
+ ├── src/fast_resume/
501
+ │ ├── cli.py # Click CLI entry point
502
+ │ ├── config.py # Constants, colors, paths
503
+ │ ├── index.py # TantivyIndex - search engine
504
+ │ ├── search.py # SessionSearch - adapter orchestration
505
+ │ ├── tui.py # Textual TUI application
506
+ │ ├── assets/ # Agent icons (PNG)
507
+ │ └── adapters/
508
+ │ ├── base.py # Session dataclass, AgentAdapter protocol
509
+ │ ├── claude.py # Claude Code adapter
510
+ │ ├── codex.py # Codex CLI adapter
511
+ │ ├── copilot.py # GitHub Copilot CLI adapter
512
+ │ ├── copilot_vscode.py # VS Code Copilot Chat adapter
513
+ │ ├── crush.py # Crush adapter
514
+ │ ├── opencode.py # OpenCode adapter
515
+ │ └── vibe.py # Vibe adapter
516
+ ├── tests/ # pytest test suite
517
+ ├── pyproject.toml # Dependencies and build config
518
+ └── README.md
519
+ ```
520
+
521
+ ### Tech Stack
522
+
523
+ | Component | Library |
524
+ | ------------------- | ------------------------------------------------------------------- |
525
+ | TUI Framework | [Textual](https://textual.textualize.io/) |
526
+ | Terminal Formatting | [Rich](https://rich.readthedocs.io/) |
527
+ | CLI Framework | [Click](https://click.palletsprojects.com/) |
528
+ | Search Engine | [Tantivy](https://github.com/quickwit-oss/tantivy) (via tantivy-py) |
529
+ | JSON Parsing | [orjson](https://github.com/ijl/orjson) (fast) |
530
+ | Date Formatting | [humanize](https://python-humanize.readthedocs.io/) |
531
+
532
+ ## Configuration
533
+
534
+ fast-resume uses sensible defaults and requires no configuration.
535
+
536
+ To clear the index and rebuild from scratch:
537
+
538
+ ```bash
539
+ rm -rf ~/.cache/fast-resume/
540
+ fr --rebuild
541
+ ```
542
+
543
+ ## License
544
+
545
+ MIT
@@ -0,0 +1,38 @@
1
+ fast_resume/__init__.py,sha256=gW5lJLa_i_nUqDxC0_G04J-qG0E0tj3Wa86XBSVuwU8,144
2
+ fast_resume/cli.py,sha256=6HlL1-qjuN3nuzST_maKmd9HjmNrLhVua4k-Xz9W7Pc,11008
3
+ fast_resume/config.py,sha256=95fWD6Ly_c6NwuaqqdLVSEoEGcqeWaB2lUKHs1R8_Gs,1185
4
+ fast_resume/index.py,sha256=36nO3NMBYaA5u3oMM9NKH868_gudzmH8ydRIUDngeTs,27969
5
+ fast_resume/logging_config.py,sha256=SfNTLwlM1_iuOyTPTDvJNk32FslP1DzeE4kdkWltRXM,1772
6
+ fast_resume/query.py,sha256=uv3ONZiAy5ghp8BxwwMv5h0BVa6gQ1gXhu2UrndNiOM,8677
7
+ fast_resume/search.py,sha256=sn7h6LbcCFDd5eKFIyWlqJ7K5bb6yJaityca7WLThMA,10520
8
+ fast_resume/adapters/__init__.py,sha256=mE2yN2IcL6SRfv2frCZ0ji4ewkeRp_r2Oxnbh28JQCM,650
9
+ fast_resume/adapters/base.py,sha256=AeMvjhTLH_wVivMfWnIWGuEM8JInHsHgrz9XIwewaB0,7974
10
+ fast_resume/adapters/claude.py,sha256=cR609NCyIX2LWmdT1-WaQpGdRPTezjAo-AKfDHk8WCA,8346
11
+ fast_resume/adapters/codex.py,sha256=J46p0qMAuYQiMpU2uHXhP4sINJ2MX4HjUOJeGouzlJY,8586
12
+ fast_resume/adapters/copilot.py,sha256=cHkWDSJUDJxz9_V_UM2kwtzAGv0Rcs-KpGuI4g_LFeI,6553
13
+ fast_resume/adapters/copilot_vscode.py,sha256=LdK1qDm9kfgqLHO8juN5Z6ZfAn-eCzt4SXgKd_68KR0,11956
14
+ fast_resume/adapters/crush.py,sha256=ulGPP28J4XhWfcFpVN7i-ur-D2h2-37t_JgCHfRKdj0,11862
15
+ fast_resume/adapters/opencode.py,sha256=jyv6BR6HwBBm4zKhVpHt37EpMHssJVRXqNN-k04XcqA,12730
16
+ fast_resume/adapters/vibe.py,sha256=y2ucU_PnX_9Q-DDJjs7-p5UVjNtqNN3EnkiYexERZ5E,6677
17
+ fast_resume/assets/claude.png,sha256=B6qA9yNcCZz1yPymGQEmxAROmLPCrPFsaBzA0eZOtfU,5179
18
+ fast_resume/assets/codex.png,sha256=gvziwdq8T7w7INSePYV3-w4Z41ALCUhm9hgbiEfiuzo,4472
19
+ fast_resume/assets/copilot-cli.png,sha256=gjxS4lWPlRjM8s8snrYK1EaajzDGNmpxG_RPJ9FubHs,10760
20
+ fast_resume/assets/copilot-vscode.png,sha256=AplrxQqrl51XbpNm3xKCaahBGo3N1lQyRNWnJVCX-98,5115
21
+ fast_resume/assets/crush.png,sha256=5U95uAk3qVUzmVO4XWa7JxCNACZunFagmycocuakwFQ,2540
22
+ fast_resume/assets/opencode.png,sha256=JU9M9brAT5Z1sGvkvm6gKLqf1IoRB_1wMJgzFOBxFkI,558
23
+ fast_resume/assets/vibe.png,sha256=SoFyIKHyXQmih3IDqvslp8EQtBxXjgVpkZMaE9A_drw,2011
24
+ fast_resume/tui/__init__.py,sha256=-mcEXE_rk2YYeCUgwXaOlTaYFL1nMq_2a4o6M79D6-0,1384
25
+ fast_resume/tui/app.py,sha256=sRnd_-V_9RNfrcGD5Bcy2LOOIMOG22dIiYeqKf55MEQ,25183
26
+ fast_resume/tui/filter_bar.py,sha256=LWDwquIajmn8XDSthaSl0U473GHBAYWI3C9vsfOUSkY,4484
27
+ fast_resume/tui/modal.py,sha256=wWlIMKRnLphStZUKL4JQV1RtYauwlMnTHVvotRJ3WQY,2398
28
+ fast_resume/tui/preview.py,sha256=lOEjW_GJDXCT_CJrEIVBjCj4_zFXHO6oZz2RV-mx0Gc,14124
29
+ fast_resume/tui/query.py,sha256=U9-Xth8EqRCLQSBovPEYAGpn-AHjoobbJO9zd1CJVA8,2782
30
+ fast_resume/tui/results_table.py,sha256=Du0bIuYJS87nGaKr6-W5JFAMJuuwpOm6Lhqb2rtqQyI,5860
31
+ fast_resume/tui/search_input.py,sha256=3ZiEtZ54ZuLTGOLiEp3kfUwsoeV3LTKX30u7aryYy7k,4136
32
+ fast_resume/tui/styles.py,sha256=l6yZiGbvo7yyFUG7cFyl3IrL6JOn46VxBRIUb8Ps2EQ,4304
33
+ fast_resume/tui/utils.py,sha256=9gXBEqWSi2yYzCt3DUSTO5rpdfwCThLCdmuz7OSHAgw,4773
34
+ fast_resume-1.12.8.dist-info/METADATA,sha256=KJSlG_bY4aA1177v-mJPV115qssUI3q7x0vKjJ65OkU,25923
35
+ fast_resume-1.12.8.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
36
+ fast_resume-1.12.8.dist-info/entry_points.txt,sha256=O8g4Bf32_NGRj6nJta6Om1r8jFIhclJv_pMM1CE-kIA,79
37
+ fast_resume-1.12.8.dist-info/licenses/LICENSE,sha256=p2Mw1d6DdK5a6-ScBMPkuf4lEmI-e2CrebVA-9aYjkw,1072
38
+ fast_resume-1.12.8.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.28.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ fast-resume = fast_resume.cli:main
3
+ fr = fast_resume.cli:main
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Stanislas Lange
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.