thread-archive 0.0.2__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.
- thread_archive/__init__.py +34 -0
- thread_archive/_api.py +2235 -0
- thread_archive/_config.py +126 -0
- thread_archive/_importers/__init__.py +81 -0
- thread_archive/_importers/_continuation.py +136 -0
- thread_archive/_importers/_cursor.py +103 -0
- thread_archive/_importers/_events.py +244 -0
- thread_archive/_importers/_line_stream.py +193 -0
- thread_archive/_importers/_read.py +82 -0
- thread_archive/_importers/_result.py +17 -0
- thread_archive/_importers/_sidecar.py +113 -0
- thread_archive/_importers/_state.py +240 -0
- thread_archive/_importers/_titles.py +179 -0
- thread_archive/_importers/antigravity.py +254 -0
- thread_archive/_importers/claude_code.py +293 -0
- thread_archive/_importers/claude_science.py +330 -0
- thread_archive/_importers/cloth.py +20 -0
- thread_archive/_importers/codex.py +324 -0
- thread_archive/_importers/cowork.py +107 -0
- thread_archive/_importers/cursor.py +432 -0
- thread_archive/_importers/exports.py +389 -0
- thread_archive/_importers/grok.py +600 -0
- thread_archive/_importers/opencode.py +538 -0
- thread_archive/_knowledge/__init__.py +67 -0
- thread_archive/_knowledge/_claims.py +116 -0
- thread_archive/_knowledge/_community.py +75 -0
- thread_archive/_knowledge/graph.py +208 -0
- thread_archive/_knowledge/materialize.py +212 -0
- thread_archive/_knowledge/write.py +438 -0
- thread_archive/_launchd.py +167 -0
- thread_archive/_mcp/__init__.py +1 -0
- thread_archive/_mcp/librarian.py +151 -0
- thread_archive/_mcp/server.py +307 -0
- thread_archive/_retrieval/__init__.py +280 -0
- thread_archive/_retrieval/_classify.py +80 -0
- thread_archive/_retrieval/_codex.py +157 -0
- thread_archive/_retrieval/_context.py +123 -0
- thread_archive/_retrieval/_extract.py +184 -0
- thread_archive/_retrieval/embed.py +186 -0
- thread_archive/_retrieval/format.py +149 -0
- thread_archive/_retrieval/fts.py +538 -0
- thread_archive/_retrieval/rank.py +228 -0
- thread_archive/_retrieval/read.py +908 -0
- thread_archive/_retrieval/rerank.py +143 -0
- thread_archive/_retrieval/vectors.py +611 -0
- thread_archive/_scripts/__init__.py +1 -0
- thread_archive/_scripts/backfill_recompute.py +328 -0
- thread_archive/_scripts/backfill_reconcile.py +296 -0
- thread_archive/_scripts/denamespace_dedup_keys.py +120 -0
- thread_archive/_scripts/recover_dropped_events.py +190 -0
- thread_archive/_scripts/repair_grok_tool_names.py +118 -0
- thread_archive/_scripts/repair_grok_tool_names_backup_20260704T155625Z.json +275 -0
- thread_archive/_scripts/repair_grok_tool_names_plan_20260704.json +435 -0
- thread_archive/_setup/__init__.py +12 -0
- thread_archive/_setup/clients.py +89 -0
- thread_archive/_setup/wizard.py +474 -0
- thread_archive/_store/__init__.py +45 -0
- thread_archive/_store/_base.py +173 -0
- thread_archive/_store/_defaults.py +57 -0
- thread_archive/_store/_types.py +38 -0
- thread_archive/_store/models.py +370 -0
- thread_archive/_store/schema.py +84 -0
- thread_archive/_thread_import/__init__.py +40 -0
- thread_archive/_thread_import/api.py +78 -0
- thread_archive/_thread_import/event_builder.py +810 -0
- thread_archive/_thread_import/exporters/__init__.py +9 -0
- thread_archive/_thread_import/exporters/_cursor_kv_mixin.py +166 -0
- thread_archive/_thread_import/exporters/_cursor_parse_mixin.py +149 -0
- thread_archive/_thread_import/exporters/cursor.py +582 -0
- thread_archive/_thread_import/exporters/cursor_parse.py +145 -0
- thread_archive/_thread_import/parsers/__init__.py +191 -0
- thread_archive/_thread_import/parsers/base.py +698 -0
- thread_archive/_thread_import/parsers/chatgpt.py +722 -0
- thread_archive/_thread_import/parsers/chatgpt_content.py +332 -0
- thread_archive/_thread_import/parsers/claude.py +443 -0
- thread_archive/_thread_import/parsers/claude_code.py +1035 -0
- thread_archive/_thread_import/parsers/claude_code_blocks.py +415 -0
- thread_archive/_thread_import/parsers/claude_code_ide.py +122 -0
- thread_archive/_thread_import/parsers/claude_code_sessions.py +90 -0
- thread_archive/_thread_import/parsers/config/__init__.py +26 -0
- thread_archive/_thread_import/parsers/config/base.py +220 -0
- thread_archive/_thread_import/parsers/cursor.py +538 -0
- thread_archive/_thread_import/parsers/cursor_blocks.py +365 -0
- thread_archive/_thread_import/parsers/pipeline/__init__.py +29 -0
- thread_archive/_thread_import/parsers/pipeline/base.py +251 -0
- thread_archive/_thread_import/parsers/pipeline/interfaces.py +191 -0
- thread_archive/_thread_import/parsers/transformers/__init__.py +22 -0
- thread_archive/_thread_import/parsers/transformers/active_path.py +87 -0
- thread_archive/_thread_import/parsers/transformers/coalescing.py +389 -0
- thread_archive/_thread_import/parsers/transformers/ide_context.py +158 -0
- thread_archive/_thread_import/parsers/transformers/thinking_merge.py +68 -0
- thread_archive/_thread_import/parsers/types/__init__.py +56 -0
- thread_archive/_thread_import/parsers/types/chatgpt.py +99 -0
- thread_archive/_thread_import/parsers/types/claude.py +120 -0
- thread_archive/_thread_import/parsers/types/claude_code.py +139 -0
- thread_archive/_thread_import/parsers/types/cursor.py +109 -0
- thread_archive/_thread_import/parsers/validators/__init__.py +83 -0
- thread_archive/_thread_import/parsers/validators/base.py +168 -0
- thread_archive/_thread_import/parsers/validators/content.py +80 -0
- thread_archive/_thread_import/parsers/validators/referential.py +57 -0
- thread_archive/_thread_import/parsers/validators/thinking.py +143 -0
- thread_archive/_thread_import/parsers/validators/types.py +87 -0
- thread_archive/_thread_import/schemas/__init__.py +231 -0
- thread_archive/_thread_import/schemas/chatgpt/v1.json +197 -0
- thread_archive/_thread_import/schemas/chatgpt/v2.json +203 -0
- thread_archive/_thread_import/schemas/claude/v1.json +188 -0
- thread_archive/_thread_import/schemas/claude_code/v1.json +183 -0
- thread_archive/_thread_import/schemas/cursor/v1.json +143 -0
- thread_archive/_thread_import/schemas/cursor/v2.json +200 -0
- thread_archive/_thread_import/timestamps.py +57 -0
- thread_archive/_thread_import/tool_names.py +48 -0
- thread_archive/_truth/__init__.py +40 -0
- thread_archive/_truth/jsonl_log.py +2340 -0
- thread_archive/_truth/repair.py +322 -0
- thread_archive/_watcher/__init__.py +57 -0
- thread_archive/_watcher/base.py +65 -0
- thread_archive/_watcher/daemon.py +289 -0
- thread_archive/_watcher/export_drop.py +203 -0
- thread_archive/_watcher/exthost.py +316 -0
- thread_archive/_watcher/lazy.py +117 -0
- thread_archive/_watcher/sources.py +616 -0
- thread_archive/_web/__init__.py +15 -0
- thread_archive/_web/server.py +299 -0
- thread_archive/_web/static/assets/index-DECSH1Mz.css +10 -0
- thread_archive/_web/static/assets/index-Djq0FK0y.js +101 -0
- thread_archive/_web/static/index.html +13 -0
- thread_archive/cli.py +746 -0
- thread_archive-0.0.2.dist-info/METADATA +296 -0
- thread_archive-0.0.2.dist-info/RECORD +132 -0
- thread_archive-0.0.2.dist-info/WHEEL +4 -0
- thread_archive-0.0.2.dist-info/entry_points.txt +6 -0
- thread_archive-0.0.2.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: thread-archive
|
|
3
|
+
Version: 0.0.2
|
|
4
|
+
Summary: Serverless-native local archive for AI conversations: JSONL truth log + rebuildable SQLite index, searched and read locally, exposed over MCP.
|
|
5
|
+
Project-URL: Repository, https://github.com/ellamental/thread_archive
|
|
6
|
+
Project-URL: Changelog, https://github.com/ellamental/thread_archive/blob/main/CHANGELOG.md
|
|
7
|
+
Author: Ella
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: archive,conversations,jsonl,mcp,serverless,sqlite
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Operating System :: MacOS
|
|
15
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Text Processing :: Indexing
|
|
21
|
+
Classifier: Topic :: Utilities
|
|
22
|
+
Requires-Python: >=3.11
|
|
23
|
+
Requires-Dist: leidenalg>=0.10
|
|
24
|
+
Requires-Dist: mcp>=1.0
|
|
25
|
+
Requires-Dist: networkx>=3.2
|
|
26
|
+
Requires-Dist: numpy>=1.26
|
|
27
|
+
Requires-Dist: python-igraph>=0.11
|
|
28
|
+
Requires-Dist: scipy>=1.11
|
|
29
|
+
Requires-Dist: sqlalchemy>=2.0
|
|
30
|
+
Provides-Extra: dev
|
|
31
|
+
Requires-Dist: build>=1.2; extra == 'dev'
|
|
32
|
+
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
|
|
33
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
34
|
+
Requires-Dist: ruff>=0.6; extra == 'dev'
|
|
35
|
+
Provides-Extra: embeddings
|
|
36
|
+
Requires-Dist: einops>=0.7; extra == 'embeddings'
|
|
37
|
+
Requires-Dist: sentence-transformers>=3.0; extra == 'embeddings'
|
|
38
|
+
Description-Content-Type: text/markdown
|
|
39
|
+
|
|
40
|
+
# thread-archive
|
|
41
|
+
|
|
42
|
+
A serverless-native, single-user local archive for AI conversations.
|
|
43
|
+
|
|
44
|
+
It watches local AI-tool stores, imports provider transcripts into one event
|
|
45
|
+
model, writes an append-only **JSONL truth log**, rebuilds a **SQLite** index from
|
|
46
|
+
that truth, and searches/reads conversations locally — exposed as a Python library
|
|
47
|
+
and over MCP (`thread_search`, `thread_read`).
|
|
48
|
+
|
|
49
|
+
There is one storage/runtime path: **JSONL + SQLite**. No Postgres, no Neo4j, no
|
|
50
|
+
external search engines, no ops service. JSONL is truth; SQLite is a rebuildable
|
|
51
|
+
projection — deleting `index.db` and running `archive reindex` loses nothing.
|
|
52
|
+
|
|
53
|
+
It is a standalone, dependency-free package: a conversation-archive engine with
|
|
54
|
+
no server, no external services, and no ties to any host application.
|
|
55
|
+
|
|
56
|
+
## Install
|
|
57
|
+
|
|
58
|
+
Needs Python ≥ 3.11. Installs the `thread_archive` setup command, the
|
|
59
|
+
`archive` operator CLI, both MCP servers (`archive-mcp`,
|
|
60
|
+
`archive-librarian-mcp`), and the pre-built web viewer — no node.
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
pip install thread-archive # lexical core (+ Leiden community detection)
|
|
64
|
+
pip install 'thread-archive[embeddings]' # optional: local semantic search (heavy: torch)
|
|
65
|
+
thread_archive # then: run setup
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
`thread_archive` is the front door. On first run it discovers this machine's
|
|
69
|
+
conversation stores and shows what it found — counts, sizes, date ranges —
|
|
70
|
+
*before* touching anything, then asks: import (all, a selection, or skip),
|
|
71
|
+
install the always-on watcher (macOS LaunchAgent; includes the web viewer at
|
|
72
|
+
:8787), and wire the MCP servers into detected clients (the `claude` CLI, or
|
|
73
|
+
it prints the JSON block for any other client). Every choice is skippable and
|
|
74
|
+
persists in `<home>/config.json`; a disabled source stays disabled across
|
|
75
|
+
every ingest path. Re-running `thread_archive` shows status; `thread_archive
|
|
76
|
+
setup` revisits the choices. Non-interactive (agents, scripts):
|
|
77
|
+
`thread_archive --yes` accepts every default — without `--yes`, a non-TTY run
|
|
78
|
+
only prints guidance and never ingests.
|
|
79
|
+
|
|
80
|
+
Skipped the watcher? Still covered: `archive-mcp` cohosts **lazy catch-up
|
|
81
|
+
ingest** — a background pass at startup and (throttled) around tool calls
|
|
82
|
+
imports whatever landed in your local AI-tool stores since the last pass. On
|
|
83
|
+
a fresh archive give the first pass a minute to chew before expecting search
|
|
84
|
+
hits; the watcher install (`thread_archive setup`, or `archive daemon
|
|
85
|
+
install`) is the always-fresh upgrade. With the daemon installed, the MCP
|
|
86
|
+
servers' lazy passes degrade to no-op lock probes — exactly one process
|
|
87
|
+
ingests at a time, however many Claude Code sessions are open.
|
|
88
|
+
|
|
89
|
+
**The clone path — for curation.** Clone the repo, open it in Claude Code, and
|
|
90
|
+
say *"install this — follow claude-install.md"*. The clone carries what a pip
|
|
91
|
+
install doesn't: the `.mcp.json` template and the `/librarian` skill (+ its
|
|
92
|
+
enforcement hook) that drives topic-graph curation. Take this route when you
|
|
93
|
+
want the knowledge layer worked, not just search.
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
git clone https://github.com/ellamental/thread_archive.git thread-archive && cd thread-archive
|
|
97
|
+
claude # then: "install this, following claude-install.md"
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
**Manual path (from a clone).**
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
python3 -m venv .venv
|
|
104
|
+
.venv/bin/pip install -e . # lexical core (+ Leiden community detection)
|
|
105
|
+
.venv/bin/pip install -e '.[embeddings]' # optional: local semantic search (heavy: torch)
|
|
106
|
+
.venv/bin/pytest tests/ -q # confirm green (add `-m package` for the wheel/sdist release lane)
|
|
107
|
+
|
|
108
|
+
# wire the two MCP servers into this clone's .mcp.json (absolute venv paths)
|
|
109
|
+
sed "s|ABSOLUTE_REPO_PATH|$(pwd)|g" .mcp.json.example > .mcp.json
|
|
110
|
+
|
|
111
|
+
# bring conversations in, then check
|
|
112
|
+
.venv/bin/archive watch --once # or: archive import <path> --provider <name>
|
|
113
|
+
.venv/bin/archive status
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Restart Claude Code in the repo so it loads `.mcp.json` (the search + librarian MCP
|
|
117
|
+
servers) and `.claude/` (the `/librarian` skill + its enforcement hook). Then curate the
|
|
118
|
+
topic graph — `/librarian` interactively, or for a large backlog the bulk driver:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
.venv/bin/python scripts/librarian_backfill.py --workers 4 --batch 25
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## CLI
|
|
125
|
+
|
|
126
|
+
Two commands, split human from operator. **`thread_archive`** is the human
|
|
127
|
+
front door — first-run setup (discover → consent → import → watcher → MCP
|
|
128
|
+
wiring), then the status view; `thread_archive setup` re-enters the flow.
|
|
129
|
+
**`archive`** is the operator seam:
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
archive import <path> # import a transcript / provider store
|
|
133
|
+
archive watch # watch local AI-tool stores and import incrementally
|
|
134
|
+
archive reindex # rebuild index.db from the JSONL truth directory
|
|
135
|
+
archive verify # integrity check: truth parses + matches the index
|
|
136
|
+
archive repair # quarantine damaged truth lines; restore committed content from the index
|
|
137
|
+
archive backup <dest> # mirror the truth dir (keeps hardlink generations under <dest>/.generations)
|
|
138
|
+
archive restore-drill <dest> # prove the backup restores: rebuild an index from the mirror + smoke read/search
|
|
139
|
+
archive nightly <dest> # the scheduled pipeline: backup → verify (age-gated escalation) → restore drill
|
|
140
|
+
archive status # archive health / counts / last verify + backup + drill outcomes
|
|
141
|
+
archive daemon <action> # macOS: install/uninstall/restart/status the always-on watcher LaunchAgent
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
The CLI is private operational tooling (see Stability below) — the process
|
|
145
|
+
seam the LaunchAgents, cron, and operators use. Retrieval deliberately has no
|
|
146
|
+
CLI verbs: search and read are the public `archive-mcp` tools, and the web
|
|
147
|
+
viewer is cohosted by `archive watch --web`.
|
|
148
|
+
|
|
149
|
+
## Layout
|
|
150
|
+
|
|
151
|
+
```text
|
|
152
|
+
src/thread_archive/
|
|
153
|
+
_api.py # internal coordination layer the CLI / MCP / web call into
|
|
154
|
+
cli.py # the `archive` command
|
|
155
|
+
_setup/ # the `thread_archive` command: first-run setup + status
|
|
156
|
+
_config.py # truth dir + index path resolution, config.json (source opt-outs)
|
|
157
|
+
_store/ # SQLite store + schema
|
|
158
|
+
_truth/ # JSONL truth log + reindex
|
|
159
|
+
_importers/ # incremental import orchestration
|
|
160
|
+
_retrieval/ # FTS5 + vector search, read reconstruction
|
|
161
|
+
_knowledge/ # topic graph: event-sourced curation + Leiden analytics
|
|
162
|
+
_watcher/ # local-source watcher (self-feeding ingest)
|
|
163
|
+
_mcp/ # library-native MCP servers (read + librarian)
|
|
164
|
+
_web/ # read-only viewer: stdlib server + built bundle (cohosted by `watch --web`)
|
|
165
|
+
_launchd.py # `archive daemon`: generates + loads the watcher LaunchAgent (macOS)
|
|
166
|
+
_thread_import/ # vendored provider parsers (a clean, dependency-free island)
|
|
167
|
+
frontend/ # the viewer's React+Vite source (dev-only; builds into _web/static/)
|
|
168
|
+
host/ # operator layer: Makefile over `archive daemon`, backup agent, family-manifest writer
|
|
169
|
+
scripts/ # operator tools (e.g. the librarian backfill driver)
|
|
170
|
+
tests/install/ # isolated Docker install test + fixtures
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## Stability
|
|
174
|
+
|
|
175
|
+
The public API is exactly two things:
|
|
176
|
+
|
|
177
|
+
- **the retrieval MCP tools** — `thread_search` and `thread_read`, served by
|
|
178
|
+
`archive-mcp`;
|
|
179
|
+
- **the on-disk truth format** — versioned by `manifest.json`'s `version` and
|
|
180
|
+
specified in [docs/format.md](https://github.com/ellamental/thread_archive/blob/main/docs/format.md).
|
|
181
|
+
Data written by one release
|
|
182
|
+
stays readable by the next; a reader refuses a truth directory newer than it
|
|
183
|
+
understands. Programmatic read access to the documented stores (`index.db`
|
|
184
|
+
is plain SQLite; the truth directory is documented JSONL) rides on this
|
|
185
|
+
contract.
|
|
186
|
+
|
|
187
|
+
Everything else is private support machinery and may change without notice:
|
|
188
|
+
the `thread_archive` and `archive` CLIs, the librarian MCP server, the web
|
|
189
|
+
viewer, and every Python module — there is **no public Python API**. More surface gets exposed
|
|
190
|
+
deliberately as it matures. `tests/test_public_api.py` ratchets the boundary.
|
|
191
|
+
|
|
192
|
+
## Web viewer
|
|
193
|
+
|
|
194
|
+
The always-on watcher cohosts a local search + reader UI: `archive watch --web`
|
|
195
|
+
(the shipped LaunchAgent passes it) serves at `http://127.0.0.1:8787` — a stdlib
|
|
196
|
+
HTTP server handing out a pre-built React bundle plus a few JSON endpoints, in
|
|
197
|
+
the watcher's *own* process. One process, one SQLite engine — the viewer reads
|
|
198
|
+
concurrently with the watcher's writes, which WAL makes safe (`store/_base.py`).
|
|
199
|
+
No second daemon, and no standalone `web` verb: the viewer exists where the
|
|
200
|
+
persistent URL is.
|
|
201
|
+
|
|
202
|
+
**Runtime is node-free**: the bundle is built ahead of time and committed under
|
|
203
|
+
`web/static/`, so `pip install` never touches node. Node is a *build*-only tool:
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
# rebuild the bundle after editing the frontend (node only here):
|
|
207
|
+
cd frontend && npm install && npm run build # → ../src/thread_archive/web/static/
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
**Archive-links.** With that persistent server, the archive owns the editor
|
|
211
|
+
"open this conversation" link itself: `GET /api/archive-link?id=<session-uuid>&source=claude-code`
|
|
212
|
+
resolves the session to its thread via `ImportState` and returns `{thread_id, url}`,
|
|
213
|
+
or `&redirect=1` → a `302` to `/archive/<id>`. (Local — no separate backend
|
|
214
|
+
involved.) `id` may repeat — a caller that cannot tell which uuid it holds is the
|
|
215
|
+
session id sends every candidate, best guess first, and the first that resolves
|
|
216
|
+
wins; ids that were never imported are skipped, not fatal.
|
|
217
|
+
|
|
218
|
+
## What it does
|
|
219
|
+
|
|
220
|
+
- **Ingests 9 providers** into one event model — Claude Code, Codex, Grok, Antigravity,
|
|
221
|
+
cloth, Cowork (transcript line-streams) and Cursor, OpenCode, Claude Science (SQLite
|
|
222
|
+
scanners). Imports are idempotent, atomic, and survive a full reindex losslessly. A
|
|
223
|
+
`cc-exthost` watcher also recovers mid-turn Claude Code steering messages that never
|
|
224
|
+
reach the session JSONL.
|
|
225
|
+
- **Self-feeds** — the watcher tails local stores and ingests incrementally; events land
|
|
226
|
+
in the JSONL truth *before* their commit (no checkpoint in the hot loop). Zero-daemon
|
|
227
|
+
by default (`archive-mcp` cohosts lazy catch-up ingest), with a one-command macOS
|
|
228
|
+
LaunchAgent upgrade (`archive daemon install`) for always-fresh — no external service
|
|
229
|
+
either way.
|
|
230
|
+
- **Declares itself** — the installer writes the thread-family manifest
|
|
231
|
+
`<home>/product.json` (`host/write-manifest.py`; `make install-agent` runs
|
|
232
|
+
it), so family consumers discover the archive by enumeration. Spec:
|
|
233
|
+
`docs/spec/product-json.md` in the thread monorepo.
|
|
234
|
+
- **Searches locally** — FTS5 lexical (boolean / phrase / pipe-OR / code-identifier),
|
|
235
|
+
optionally fused with local semantic vectors and a cross-encoder re-rank; plus
|
|
236
|
+
transcript reconstruction for reading.
|
|
237
|
+
- **Rebuilds losslessly** — `rm index.db && archive reindex` reconstructs the entire
|
|
238
|
+
index from the JSONL truth; a `cp`/`rsync` of the truth dir *is* the backup.
|
|
239
|
+
- **Curatable** — an event-sourced topic graph with Leiden communities (see below),
|
|
240
|
+
driven on demand by the `/librarian` skill.
|
|
241
|
+
|
|
242
|
+
## MCP
|
|
243
|
+
|
|
244
|
+
Two servers, split read from write. **`thread-archive`** (`archive-mcp`) serves the
|
|
245
|
+
read-only tools — `thread_search` / `thread_read` — and cohosts lazy catch-up
|
|
246
|
+
ingest in its own process (throttled, cross-process-safe via the ingest-owner
|
|
247
|
+
lock; `THREAD_ARCHIVE_MCP_INGEST=0` disables it). **`thread-archive-librarian`**
|
|
248
|
+
(`archive-librarian-mcp`) is the curatorial *write* surface — topic/link/citation
|
|
249
|
+
writes + the reads a librarian needs (`review_queue`, `topic_search`,
|
|
250
|
+
`thread_user_messages`). Keeping them separate means a read-only client never gets
|
|
251
|
+
curation power. Client config:
|
|
252
|
+
|
|
253
|
+
```json
|
|
254
|
+
{
|
|
255
|
+
"mcpServers": {
|
|
256
|
+
"thread-archive": {
|
|
257
|
+
"command": "archive-mcp",
|
|
258
|
+
"env": { "THREAD_ARCHIVE_HOME": "~/.thread/archive" }
|
|
259
|
+
},
|
|
260
|
+
"thread-archive-librarian": {
|
|
261
|
+
"command": "archive-librarian-mcp",
|
|
262
|
+
"env": { "THREAD_ARCHIVE_HOME": "~/.thread/archive" }
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
## Knowledge layer (the topic graph)
|
|
269
|
+
|
|
270
|
+
There are exactly two kinds of thread: imported **conversations** and curated **topics**
|
|
271
|
+
(`thread_type='topic'`). A topic is modeled as a thread on purpose — so the graph's edges
|
|
272
|
+
(`thread_links`) and message→topic citations (`topic_messages`) reference one id space.
|
|
273
|
+
Reads/analytics live in the knowledge layer (`_knowledge/`) — PageRank,
|
|
274
|
+
communities (**Leiden**, the algorithm Neo4j GDS ran, with a networkx-Louvain fail-soft
|
|
275
|
+
fallback), bridges, peers.
|
|
276
|
+
|
|
277
|
+
Curation is **event-sourced**. Every write (`create_topic`, `link_threads`,
|
|
278
|
+
`add_topic_evidence`, `merge_topics`, …) appends a `KgEvent` to an
|
|
279
|
+
append-only `truth/kg_events.jsonl` and folds it into the SQLite projection in one
|
|
280
|
+
transaction. The log is the source of truth for curation; `thread_links` / `topic_messages`
|
|
281
|
+
are rebuildable from it — `reindex` replays the log (idempotent upsert + tombstone) to
|
|
282
|
+
reconstruct them, so an unlink/merge/archive is recorded history, never silent loss. The
|
|
283
|
+
librarian skill (`.claude/skills/librarian/`) drives the write MCP to clear the
|
|
284
|
+
citation backlog on demand (a conversation is 'reviewed' once it gains its first
|
|
285
|
+
citation/link — there is no per-thread summary).
|
|
286
|
+
|
|
287
|
+
## License
|
|
288
|
+
|
|
289
|
+
MIT — see [LICENSE](https://github.com/ellamental/thread_archive/blob/main/LICENSE).
|
|
290
|
+
|
|
291
|
+
## Origin
|
|
292
|
+
|
|
293
|
+
thread-archive is the standalone member of a larger personal project ("thread"), built to
|
|
294
|
+
stand on its own — serverless, dependency-free, no backend or external services. The
|
|
295
|
+
package is self-contained, but it's young: expect the occasional rough edge or stray
|
|
296
|
+
reference to its parent project.
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
thread_archive/__init__.py,sha256=1YtZeHc1ZrjnIZde0t1QkUPEqRPGaorkzRpsaHEJGEM,1581
|
|
2
|
+
thread_archive/_api.py,sha256=VHR198pQUEt1EJBc5PXBVqugxEkEBIIp_qWDYUmkJiY,103578
|
|
3
|
+
thread_archive/_config.py,sha256=51DKgkYDTY88KVxotc5-Va4pxjNG0fOvQhojuV6aquU,4795
|
|
4
|
+
thread_archive/_launchd.py,sha256=Cr9AeUXCLn4bIm0H2B4VtyXbgXoQfVA0hPoWJw1p6Tg,5887
|
|
5
|
+
thread_archive/cli.py,sha256=gCrim9tkPpc7EEjYzqDRGDJszU7xpgHp110HjnvB2vo,31582
|
|
6
|
+
thread_archive/_importers/__init__.py,sha256=E8F5-GwjQh8upq-kxCSRDAbyAOo5zUbgDkdOkpp8NxY,2709
|
|
7
|
+
thread_archive/_importers/_continuation.py,sha256=XAyG-THeOIaWWdwGz8JfDLySqtAbBv3U99inVTxOZQw,5522
|
|
8
|
+
thread_archive/_importers/_cursor.py,sha256=3Izh5SS9tSX6pq3V_ycxUG86EZ0YhQ8jAnb6ODtqGCo,4545
|
|
9
|
+
thread_archive/_importers/_events.py,sha256=79mzog_ftaAW_J5ELc_vTvLCvwXB6ET9lNDG18MAF-w,9713
|
|
10
|
+
thread_archive/_importers/_line_stream.py,sha256=d8uQBLViIblb8Pl1NN8TbOx9-aU5Q5kzu62mL-wXJ4A,6790
|
|
11
|
+
thread_archive/_importers/_read.py,sha256=OzgqxJkGvoO5siBoa6dGT2GAfoCbFtYCg4OHDUejYn0,3201
|
|
12
|
+
thread_archive/_importers/_result.py,sha256=Uko5Vi97SHk5hEPnhisiN-Qp8meq2PhlResc2FCRmro,379
|
|
13
|
+
thread_archive/_importers/_sidecar.py,sha256=SxW_Gm2wrJicXkzGFPsoF32D4nBbi2EJos1sly-zIRU,3993
|
|
14
|
+
thread_archive/_importers/_state.py,sha256=jqrniKpnNovskFHkuCoBODI6Eil9WqqUF11IaLgBvgw,9294
|
|
15
|
+
thread_archive/_importers/_titles.py,sha256=PRtiAEq3w5cZaxF3i9HnGKtRPfT8E-jvarFHrT3lmFM,7124
|
|
16
|
+
thread_archive/_importers/antigravity.py,sha256=O0_Bts8Ak8PTi1xpk0GzWATagwy7cYyT0f035jwzRVk,9488
|
|
17
|
+
thread_archive/_importers/claude_code.py,sha256=Bqz3tmhhCfsoWZQEt-3sEyOm9EDukgPd1wBhomknS74,12486
|
|
18
|
+
thread_archive/_importers/claude_science.py,sha256=bS6tpSwW_q3N9nm1d5DA2ZUy2Ekg3M0fgEpq1OLUZDU,13321
|
|
19
|
+
thread_archive/_importers/cloth.py,sha256=Xwy8nqkVPeEEs42x7tHSkUB4X_guY8P4aXSmBniNvUg,1107
|
|
20
|
+
thread_archive/_importers/codex.py,sha256=YuB5SjwxCheixbSAqUxDVxsqnw7DNCfc3FE-vBXmztI,11915
|
|
21
|
+
thread_archive/_importers/cowork.py,sha256=vwlEefqMoKmbn9YZUYz7QD6DxhXfQ_4wFFpRRWxmUyQ,4222
|
|
22
|
+
thread_archive/_importers/cursor.py,sha256=DAGR30vsKLN8UHpTxikTuXQXB_-QY8cQ0-OLCelNaUg,17695
|
|
23
|
+
thread_archive/_importers/exports.py,sha256=LmUI4Ip-Mxy71pIyzy5gFHP5cIibvp-RevdeJxBP1OE,16154
|
|
24
|
+
thread_archive/_importers/grok.py,sha256=4VQg7sIrKXjyz8DhhnEFoa5GCPhcCJKEB1mn4_mG9_E,22079
|
|
25
|
+
thread_archive/_importers/opencode.py,sha256=NG-tFmb6FjpQWM3W0N9xuJZrRiGc0kQx8SPWUwM8-P4,22949
|
|
26
|
+
thread_archive/_knowledge/__init__.py,sha256=cnSYqwdQ87c1jekkl_DxoSW5wX9sKGXQ-g4vp8qyUNo,1825
|
|
27
|
+
thread_archive/_knowledge/_claims.py,sha256=3_usBaoTSjqYD-9qol3y1oSQPlYJt1qVf_EfDKx2YwA,4484
|
|
28
|
+
thread_archive/_knowledge/_community.py,sha256=SspOc0H3kFEY1dowlYEIKaU_IerSZ8md2oqqTO0my04,3030
|
|
29
|
+
thread_archive/_knowledge/graph.py,sha256=bP34HkFCndcXkSrqqNOMYxf0ve9BxcYURLt7yoCldug,7437
|
|
30
|
+
thread_archive/_knowledge/materialize.py,sha256=s9bbiLMN2zBtoAoz2ChOGQn0k8jQkLy6GvHnukKXifM,9273
|
|
31
|
+
thread_archive/_knowledge/write.py,sha256=KcOZtDoFSzlA-XG1SDz3AcbuISiZ29hZ3x5CaBpFsM4,19193
|
|
32
|
+
thread_archive/_mcp/__init__.py,sha256=6PSpxiOHcC2T8kz3HeYhLOJRtwuTBnxzv88WRsvVPDo,89
|
|
33
|
+
thread_archive/_mcp/librarian.py,sha256=vMmNlfcYjmecGhn1g_CIHVGO20uqTjEXb6Yx4RLG1uc,6094
|
|
34
|
+
thread_archive/_mcp/server.py,sha256=mjE9ENyxYCzUdhgMuXtY6xklKvB36ug_4vVxdRG1-IM,14577
|
|
35
|
+
thread_archive/_retrieval/__init__.py,sha256=xv2EMZrtMQ1JTqqptFOa8ht4a5ghcw4-vmqp5Q7iyuI,13355
|
|
36
|
+
thread_archive/_retrieval/_classify.py,sha256=bUMTHTkZXUs-bg945sBIgUAIFg-abPMPmSZLCt7aNZI,3053
|
|
37
|
+
thread_archive/_retrieval/_codex.py,sha256=0RTn90Etdz8nr6e56KQEGClieNK_32WorAQQsPhHO78,6199
|
|
38
|
+
thread_archive/_retrieval/_context.py,sha256=b3mXGaxMag90vlSgEm7PiwrveD4HyT4A88Re-8rFBv4,5199
|
|
39
|
+
thread_archive/_retrieval/_extract.py,sha256=Gj5TAZSfHVu3mMB4FD5ECZ5HsVTt_58Js4-ln0OZJ8I,7506
|
|
40
|
+
thread_archive/_retrieval/embed.py,sha256=_lhaWkEwmocF3lksjvQIUt5qzmXoIeFrIhsyVShiAkY,7304
|
|
41
|
+
thread_archive/_retrieval/format.py,sha256=gwTRut2Z-8TZzXHAXdvBSMw353sOEoEZj8PJkBCrNP0,5803
|
|
42
|
+
thread_archive/_retrieval/fts.py,sha256=MOfBVhcIKal_MZuQm7WXOBCh0ZKm08O0ylqIzNQ6eTA,23647
|
|
43
|
+
thread_archive/_retrieval/rank.py,sha256=xNl35MUGY3KQhDShsmEHZrPnfKul3uykV_pO4io1jP8,10268
|
|
44
|
+
thread_archive/_retrieval/read.py,sha256=jD2QGWzPazaqsP3H138suBnZxFIev0RqJdJL0mn6vlg,40982
|
|
45
|
+
thread_archive/_retrieval/rerank.py,sha256=q2x5_p7gxv6y6ReuNB2rODGC2-PtUGfWA0U1qIq2YA4,5604
|
|
46
|
+
thread_archive/_retrieval/vectors.py,sha256=0HDlcSkH3AR_6Y4nH0DkeUvTcaYZtCE5Gp9vIoF1drA,26391
|
|
47
|
+
thread_archive/_scripts/__init__.py,sha256=BawS1JIk0h9jfCS39xSZVmxL5f_wK9CsVhgiob6BztM,63
|
|
48
|
+
thread_archive/_scripts/backfill_recompute.py,sha256=--rYFaZijXt1ySWWmmRzelEemXrOjUgoC1wfQYUAe-c,16322
|
|
49
|
+
thread_archive/_scripts/backfill_reconcile.py,sha256=5BkG2FwXb-n2qrbyjoGOPtAWD7x0CrgC1lo63FDiRwY,13285
|
|
50
|
+
thread_archive/_scripts/denamespace_dedup_keys.py,sha256=70z_ESpq8sKhbk0DvbdfLY_niceBGeoNhFAPvZ0vb4U,5211
|
|
51
|
+
thread_archive/_scripts/recover_dropped_events.py,sha256=2_lCwMjow8XZwRnyU5Ch8i3lua2f7j--hTw4Xw-s2qE,8562
|
|
52
|
+
thread_archive/_scripts/repair_grok_tool_names.py,sha256=f5oBLIC6phCUgJ5uT0p1wx8_N126gltI3JgfUSinPTw,5253
|
|
53
|
+
thread_archive/_scripts/repair_grok_tool_names_backup_20260704T155625Z.json,sha256=2T05ysx16NFvn5B3nTbNdTm-fcz3dF9lRy74Ae9PvaU,42961
|
|
54
|
+
thread_archive/_scripts/repair_grok_tool_names_plan_20260704.json,sha256=gCVYZKLAzhOnWuMskkP09FhygzLg1Ju9sKuK2EZTnOs,163203
|
|
55
|
+
thread_archive/_setup/__init__.py,sha256=qPb6X0ydZAix5afnprGNeB3zD1R0mSHx6hmNCeeQbsM,367
|
|
56
|
+
thread_archive/_setup/clients.py,sha256=ETGbNcsFKUzuCXUspEJbJo_1WacI4rM3qTuSj_9uLQQ,3088
|
|
57
|
+
thread_archive/_setup/wizard.py,sha256=gcrIMHGBTnrvc4TiPPmd6Yi6LOXm3kKOatywP0vo9I4,20003
|
|
58
|
+
thread_archive/_store/__init__.py,sha256=5cyA3Ym9A09I3WoGl9X-7BcaV5OeV428gKwgCDRpu5k,863
|
|
59
|
+
thread_archive/_store/_base.py,sha256=eAQ8rRFZPkn3kS5QYh1bg2pfbalqa35CmfsxbBEOBMM,5838
|
|
60
|
+
thread_archive/_store/_defaults.py,sha256=Ka7FhzF52pIG9hL1OaKXsPFHeOYp2VP9KxowACGOODA,1497
|
|
61
|
+
thread_archive/_store/_types.py,sha256=x5RU9vCCAReplCKpIkTaG9ig0YCD44svfQgHSSY-GdM,1828
|
|
62
|
+
thread_archive/_store/models.py,sha256=Wvd-Em8A3JQi1s20o2_ZKsjdCmKOcgyoZ_x-AjXVf6c,18496
|
|
63
|
+
thread_archive/_store/schema.py,sha256=6Fl9GsluiTJSodi44qVxpvkP1YTg6oNRISlt75iS_xg,3699
|
|
64
|
+
thread_archive/_thread_import/__init__.py,sha256=0jBlCqhcygUcIqFm8sKJ6AY59N8UeHRAUeqlyWpk9Gw,1177
|
|
65
|
+
thread_archive/_thread_import/api.py,sha256=zLEoSmuEy51FZG_VYuvbZFt84bI6yg-1b8JVOk7xoGs,2314
|
|
66
|
+
thread_archive/_thread_import/event_builder.py,sha256=nNPEn0N-fokyNkBBUzpteOc7hJd2KpXziu5XjatS2gM,33209
|
|
67
|
+
thread_archive/_thread_import/timestamps.py,sha256=QB1rUK0BMMaGs5Y5uN7mrLPdBE0V7CYNRoV5x-1O_O4,2030
|
|
68
|
+
thread_archive/_thread_import/tool_names.py,sha256=SppZCIvgxC1cjQmxkLdnss9E3J7u9io2Eh0vO44vy54,1696
|
|
69
|
+
thread_archive/_thread_import/exporters/__init__.py,sha256=lQy_oUdYkXXEUzEfhq96Va5BXnh3a0MaORcJZ83Vp18,155
|
|
70
|
+
thread_archive/_thread_import/exporters/_cursor_kv_mixin.py,sha256=c3-QzLAmEL16V6Cow53Cdvn5Oh-7Ip2DkMiDMsk8ELA,6209
|
|
71
|
+
thread_archive/_thread_import/exporters/_cursor_parse_mixin.py,sha256=dmKfno75SgnIqS0LafugVQJysT3_6TJRN_5IC6DP_iI,5970
|
|
72
|
+
thread_archive/_thread_import/exporters/cursor.py,sha256=BvRY_OiQXFqpd5_5a7cv1a8GrCxnBhv4HkOD0D2CEfE,21011
|
|
73
|
+
thread_archive/_thread_import/exporters/cursor_parse.py,sha256=Vgb2Y5prKfKHXMAoDT9ZS6IBGOJL-sPfXCLKnSCwWRE,5129
|
|
74
|
+
thread_archive/_thread_import/parsers/__init__.py,sha256=djz7PVrCUMF57IQh2JAAaqR13C-rKfzjxgNKLyPrHts,4683
|
|
75
|
+
thread_archive/_thread_import/parsers/base.py,sha256=S1vLZg5w7R07C1pxddSmNFU6awTHNH3Hg-KmLW4qglY,24065
|
|
76
|
+
thread_archive/_thread_import/parsers/chatgpt.py,sha256=32uxzpOSPyZ1ZgexwKajYza0pJO_dKaRh8lzjpHYJ5Q,27899
|
|
77
|
+
thread_archive/_thread_import/parsers/chatgpt_content.py,sha256=YhwZiJQb2f34g6fQjfP0nUmbYdAQ7UeZsIsdjwhLzTc,11473
|
|
78
|
+
thread_archive/_thread_import/parsers/claude.py,sha256=S8YRq8oaU7hEtEBxdr1w0denorgv1pXz9U2mZBWLK3o,16594
|
|
79
|
+
thread_archive/_thread_import/parsers/claude_code.py,sha256=J9fXP9bVaccqAJ0bY28z9KT7Cp-0ZtCd6FdXaAyYi7Q,42236
|
|
80
|
+
thread_archive/_thread_import/parsers/claude_code_blocks.py,sha256=RMjjYaIBGpQpJEh6Mwgh2mF6wVukaBCviaJQzyXeV3E,15296
|
|
81
|
+
thread_archive/_thread_import/parsers/claude_code_ide.py,sha256=JjVWdpkPxBiM8exQwZ3yA0aKIEIvd8FEmY8QNMfH6NI,4509
|
|
82
|
+
thread_archive/_thread_import/parsers/claude_code_sessions.py,sha256=1FPnWyPTEnhLHqVU9qg9B54OJPLFqivUn-WKcXhQ5z8,2911
|
|
83
|
+
thread_archive/_thread_import/parsers/cursor.py,sha256=3UTCfiDinW_razvdO46dC_O4tqayl8Ts9DzLWWcnwkc,18845
|
|
84
|
+
thread_archive/_thread_import/parsers/cursor_blocks.py,sha256=zDto4MkmFzi-5Q0Y0qoKiWdKdxxonInb39HjTH-EZU4,13650
|
|
85
|
+
thread_archive/_thread_import/parsers/config/__init__.py,sha256=a2sScw18UxdsCjxt9Z_TkEHq_XJD5RICzlDuqpxlWW8,543
|
|
86
|
+
thread_archive/_thread_import/parsers/config/base.py,sha256=XkWanwBbXPzkMGcwVX1Howr8pkhiatUpDTwYM8I7CdI,7184
|
|
87
|
+
thread_archive/_thread_import/parsers/pipeline/__init__.py,sha256=gE3A8Zp8v-BHraL091WrmTbgbwf5DSPN7KFVtsHyUq0,698
|
|
88
|
+
thread_archive/_thread_import/parsers/pipeline/base.py,sha256=XOKGnVcnXI4tMFWB3tz1a-Znib2sHAOnwC2NCPs_1Uw,8081
|
|
89
|
+
thread_archive/_thread_import/parsers/pipeline/interfaces.py,sha256=94lQs_eocP8BHYggo4V-8VExa-9fTrzyIwfcNQ_4fi4,6139
|
|
90
|
+
thread_archive/_thread_import/parsers/transformers/__init__.py,sha256=Bsv_BmGcS_lEPGN_ocFzE_OwoW9HRncYNSk_iuhqxEA,633
|
|
91
|
+
thread_archive/_thread_import/parsers/transformers/active_path.py,sha256=S7Wz4BQ96IKoM0QKVXAc_GMOxdTGFIyafMWJ681c8Yo,2792
|
|
92
|
+
thread_archive/_thread_import/parsers/transformers/coalescing.py,sha256=SWLOCHGFBTq1pHCFfV364JhWXtjLkwWVYtY2KW4Vk5E,13470
|
|
93
|
+
thread_archive/_thread_import/parsers/transformers/ide_context.py,sha256=djA0VFa_s9VE5BvfU20WrT20NxVqjyVqYxJ3wdxbHTE,5227
|
|
94
|
+
thread_archive/_thread_import/parsers/transformers/thinking_merge.py,sha256=0pBAd1-t96cHc2u_KZxB1PDnYRnycSNj9cFaOiy8SzY,2374
|
|
95
|
+
thread_archive/_thread_import/parsers/types/__init__.py,sha256=6NLXrGmSChcN63qRBSyz0eWUEkq00vhOa8oLl9-FXtU,1136
|
|
96
|
+
thread_archive/_thread_import/parsers/types/chatgpt.py,sha256=MGWK5gi0Gbs6J1ZRB7j7iOkdtr7Al6PaclMxqURcKoU,3283
|
|
97
|
+
thread_archive/_thread_import/parsers/types/claude.py,sha256=vEnd3wlRLIqNuzA0HUQ_CRY7lb4FHrD1Xc9PRgLjgAQ,3628
|
|
98
|
+
thread_archive/_thread_import/parsers/types/claude_code.py,sha256=Ql_JfUiQ4Z36z9GImJsWAF5HYykcjZpEKi1UzIPa7c4,4627
|
|
99
|
+
thread_archive/_thread_import/parsers/types/cursor.py,sha256=bOty8b070yGNE6amgdAvWxOTA9teN1VIDHxviKl7ajw,3867
|
|
100
|
+
thread_archive/_thread_import/parsers/validators/__init__.py,sha256=RuMVB7DeGIAb8HO5cY4S-eey8r62l85WHgcX4TZAYPo,3272
|
|
101
|
+
thread_archive/_thread_import/parsers/validators/base.py,sha256=VieqEJLc6daZDOrVyF_s-IdoM5jcvYJjgHWOQVJ1kIQ,5223
|
|
102
|
+
thread_archive/_thread_import/parsers/validators/content.py,sha256=9eB4UOedRMaKgOBYy7qubQQUT4qj0cDWPFGBB3uJtrA,2746
|
|
103
|
+
thread_archive/_thread_import/parsers/validators/referential.py,sha256=01i8EbOZ9XSDCLsUeGefqeLpX4V7rdhCZsK5RLTqTMo,1936
|
|
104
|
+
thread_archive/_thread_import/parsers/validators/thinking.py,sha256=gqBzN9iVm1FPPzBqnabomAD2jorBY7joVHUySdLTTu4,5351
|
|
105
|
+
thread_archive/_thread_import/parsers/validators/types.py,sha256=qM99w6pIxFRCj66L8P4m3cgh_cQBU_2fLBOid3JLLqg,2810
|
|
106
|
+
thread_archive/_thread_import/schemas/__init__.py,sha256=YK23WcIDX9d8v_YwkmMGVyYnIvcMogZDvrUYIE1wE6c,6905
|
|
107
|
+
thread_archive/_thread_import/schemas/chatgpt/v1.json,sha256=-0g9cpRCdpSUVKTucdgDCERp1mNGgIXg_Yr__CMtLg4,4980
|
|
108
|
+
thread_archive/_thread_import/schemas/chatgpt/v2.json,sha256=EDYDnqalPDGGOPFuWXJVXkp_ns9uZiSJh2qPtWaWEwc,5367
|
|
109
|
+
thread_archive/_thread_import/schemas/claude/v1.json,sha256=vcpuXiDQo7TnLoZ_dB8fA6fXBzlcTwSJqVYrYY1eu_M,4338
|
|
110
|
+
thread_archive/_thread_import/schemas/claude_code/v1.json,sha256=kDLBgIJYCDd66fAnD0ts7SedpeeyhaNbhBFW4fac-3w,4769
|
|
111
|
+
thread_archive/_thread_import/schemas/cursor/v1.json,sha256=YYRP7uCHsPUBErZDY4ayDmKcp1CsGatGLh3tVcx-TWg,3705
|
|
112
|
+
thread_archive/_thread_import/schemas/cursor/v2.json,sha256=XYEZiDoNqgh3yZZBWL8PJrQ7qDC3johTMUnUkwunT1g,5273
|
|
113
|
+
thread_archive/_truth/__init__.py,sha256=AD_01J7xRtoi6Vgsx0VdQgXb4ArzOUbR1hTRkILZ4VM,861
|
|
114
|
+
thread_archive/_truth/jsonl_log.py,sha256=a44C5fnAybZ_hfMqdC-Z3GInv0aTfgPzqXrRSfVrNpg,112625
|
|
115
|
+
thread_archive/_truth/repair.py,sha256=6ucXIdwDfIf9cRFB0d84xhoz_qSRBhJvLYY8inlwl7U,13946
|
|
116
|
+
thread_archive/_watcher/__init__.py,sha256=UrB72M14OMceMnLHb0w5GRv4hRrd6TuEKd_Bk4ZhuZo,1646
|
|
117
|
+
thread_archive/_watcher/base.py,sha256=7Gr8mYatuWNHAhyyTY13qgDjZd5V4VGXxHVoB9USfBI,2090
|
|
118
|
+
thread_archive/_watcher/daemon.py,sha256=LL1Yia61r0SmOSd3yOUj1lMi_f8FwjmVFYRvolRLC7w,14057
|
|
119
|
+
thread_archive/_watcher/export_drop.py,sha256=091W0oSaKk3XAfgNpYLtoHsMQWrXp_-ZXnccsnG8N0U,8299
|
|
120
|
+
thread_archive/_watcher/exthost.py,sha256=mn_tEJ3C-cao1ut4TVrPVhPi0fzvdmG3FVje2_aSW3E,14169
|
|
121
|
+
thread_archive/_watcher/lazy.py,sha256=vIgov52JXvPi6VtK_uD8ExWQPqtmW3QHNry8vjxRSEE,4381
|
|
122
|
+
thread_archive/_watcher/sources.py,sha256=njMKFnmJFqNS3tgae1QrWoFXVBpPl-mtpgeTc26Prt8,24835
|
|
123
|
+
thread_archive/_web/__init__.py,sha256=1V2Wgv6-t4LVSJsqfU5osC6q4JI1ezJ-lnHXtFvnruE,658
|
|
124
|
+
thread_archive/_web/server.py,sha256=nh56fIahpgvLruO-dOgA_8ei-ltVC49rNS7x67YL2G8,12236
|
|
125
|
+
thread_archive/_web/static/index.html,sha256=pirPsnwD7f181FtpGG-4TToCPE-1rlj044ZW30Twn6k,399
|
|
126
|
+
thread_archive/_web/static/assets/index-DECSH1Mz.css,sha256=SFnjTv3L91novFjCV7U1bmdKTBW-J2qFqeO0Jn2X1Ms,9386
|
|
127
|
+
thread_archive/_web/static/assets/index-Djq0FK0y.js,sha256=gOz_YDHPDYrgXFSOg8YyC01VlrEytoiFce81eIsfMAU,511764
|
|
128
|
+
thread_archive-0.0.2.dist-info/METADATA,sha256=Cp370oTP1Cj7c0eBbSmZVKvluGNOGeMEl-oLJUz-b8o,14991
|
|
129
|
+
thread_archive-0.0.2.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
|
|
130
|
+
thread_archive-0.0.2.dist-info/entry_points.txt,sha256=QjJSKuUc-5HM01pMPReWzLqTXvPH5HGEScGwAPwuSvM,245
|
|
131
|
+
thread_archive-0.0.2.dist-info/licenses/LICENSE,sha256=XcDY4f99OtZKWxDBAAAasHoz5dgYFAHMdv2X9pjDt-0,1061
|
|
132
|
+
thread_archive-0.0.2.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ella
|
|
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.
|