thread-archive 0.0.2__tar.gz
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-0.0.2/.gitignore +39 -0
- thread_archive-0.0.2/.mcp.json.example +13 -0
- thread_archive-0.0.2/CHANGELOG.md +328 -0
- thread_archive-0.0.2/LICENSE +21 -0
- thread_archive-0.0.2/PKG-INFO +296 -0
- thread_archive-0.0.2/README.md +257 -0
- thread_archive-0.0.2/claude-install.md +144 -0
- thread_archive-0.0.2/docs/format.md +130 -0
- thread_archive-0.0.2/docs/plans/reindex-atomic-swap.md +120 -0
- thread_archive-0.0.2/frontend/.gitignore +1 -0
- thread_archive-0.0.2/frontend/index.html +12 -0
- thread_archive-0.0.2/frontend/package-lock.json +4599 -0
- thread_archive-0.0.2/frontend/package.json +34 -0
- thread_archive-0.0.2/frontend/src/App.tsx +24 -0
- thread_archive-0.0.2/frontend/src/api.ts +103 -0
- thread_archive-0.0.2/frontend/src/components/Landing.tsx +7 -0
- thread_archive-0.0.2/frontend/src/components/Markdown.tsx +20 -0
- thread_archive-0.0.2/frontend/src/components/Message.tsx +242 -0
- thread_archive-0.0.2/frontend/src/components/RawMode.tsx +8 -0
- thread_archive-0.0.2/frontend/src/components/SearchView.tsx +80 -0
- thread_archive-0.0.2/frontend/src/components/Sidebar.tsx +77 -0
- thread_archive-0.0.2/frontend/src/components/StatusBar.tsx +21 -0
- thread_archive-0.0.2/frontend/src/components/ThreadView.tsx +99 -0
- thread_archive-0.0.2/frontend/src/main.tsx +14 -0
- thread_archive-0.0.2/frontend/src/modelColor.ts +63 -0
- thread_archive-0.0.2/frontend/src/styles.css +222 -0
- thread_archive-0.0.2/frontend/src/test/Message.test.tsx +147 -0
- thread_archive-0.0.2/frontend/src/test/SearchView.test.tsx +100 -0
- thread_archive-0.0.2/frontend/src/test/ThreadView.test.tsx +111 -0
- thread_archive-0.0.2/frontend/src/test/setup.ts +10 -0
- thread_archive-0.0.2/frontend/tsconfig.json +21 -0
- thread_archive-0.0.2/frontend/vite.config.ts +25 -0
- thread_archive-0.0.2/pyproject.toml +118 -0
- thread_archive-0.0.2/scripts/coverage_gate.py +94 -0
- thread_archive-0.0.2/scripts/golden_from_usage.py +173 -0
- thread_archive-0.0.2/scripts/librarian_backfill.py +160 -0
- thread_archive-0.0.2/scripts/retrieval_eval.py +170 -0
- thread_archive-0.0.2/src/thread_archive/__init__.py +34 -0
- thread_archive-0.0.2/src/thread_archive/_api.py +2235 -0
- thread_archive-0.0.2/src/thread_archive/_config.py +126 -0
- thread_archive-0.0.2/src/thread_archive/_importers/__init__.py +81 -0
- thread_archive-0.0.2/src/thread_archive/_importers/_continuation.py +136 -0
- thread_archive-0.0.2/src/thread_archive/_importers/_cursor.py +103 -0
- thread_archive-0.0.2/src/thread_archive/_importers/_events.py +244 -0
- thread_archive-0.0.2/src/thread_archive/_importers/_line_stream.py +193 -0
- thread_archive-0.0.2/src/thread_archive/_importers/_read.py +82 -0
- thread_archive-0.0.2/src/thread_archive/_importers/_result.py +17 -0
- thread_archive-0.0.2/src/thread_archive/_importers/_sidecar.py +113 -0
- thread_archive-0.0.2/src/thread_archive/_importers/_state.py +240 -0
- thread_archive-0.0.2/src/thread_archive/_importers/_titles.py +179 -0
- thread_archive-0.0.2/src/thread_archive/_importers/antigravity.py +254 -0
- thread_archive-0.0.2/src/thread_archive/_importers/claude_code.py +293 -0
- thread_archive-0.0.2/src/thread_archive/_importers/claude_science.py +330 -0
- thread_archive-0.0.2/src/thread_archive/_importers/cloth.py +20 -0
- thread_archive-0.0.2/src/thread_archive/_importers/codex.py +324 -0
- thread_archive-0.0.2/src/thread_archive/_importers/cowork.py +107 -0
- thread_archive-0.0.2/src/thread_archive/_importers/cursor.py +432 -0
- thread_archive-0.0.2/src/thread_archive/_importers/exports.py +389 -0
- thread_archive-0.0.2/src/thread_archive/_importers/grok.py +600 -0
- thread_archive-0.0.2/src/thread_archive/_importers/opencode.py +538 -0
- thread_archive-0.0.2/src/thread_archive/_knowledge/__init__.py +67 -0
- thread_archive-0.0.2/src/thread_archive/_knowledge/_claims.py +116 -0
- thread_archive-0.0.2/src/thread_archive/_knowledge/_community.py +75 -0
- thread_archive-0.0.2/src/thread_archive/_knowledge/graph.py +208 -0
- thread_archive-0.0.2/src/thread_archive/_knowledge/materialize.py +212 -0
- thread_archive-0.0.2/src/thread_archive/_knowledge/write.py +438 -0
- thread_archive-0.0.2/src/thread_archive/_launchd.py +167 -0
- thread_archive-0.0.2/src/thread_archive/_mcp/__init__.py +1 -0
- thread_archive-0.0.2/src/thread_archive/_mcp/librarian.py +151 -0
- thread_archive-0.0.2/src/thread_archive/_mcp/server.py +307 -0
- thread_archive-0.0.2/src/thread_archive/_retrieval/__init__.py +280 -0
- thread_archive-0.0.2/src/thread_archive/_retrieval/_classify.py +80 -0
- thread_archive-0.0.2/src/thread_archive/_retrieval/_codex.py +157 -0
- thread_archive-0.0.2/src/thread_archive/_retrieval/_context.py +123 -0
- thread_archive-0.0.2/src/thread_archive/_retrieval/_extract.py +184 -0
- thread_archive-0.0.2/src/thread_archive/_retrieval/embed.py +186 -0
- thread_archive-0.0.2/src/thread_archive/_retrieval/format.py +149 -0
- thread_archive-0.0.2/src/thread_archive/_retrieval/fts.py +538 -0
- thread_archive-0.0.2/src/thread_archive/_retrieval/rank.py +228 -0
- thread_archive-0.0.2/src/thread_archive/_retrieval/read.py +908 -0
- thread_archive-0.0.2/src/thread_archive/_retrieval/rerank.py +143 -0
- thread_archive-0.0.2/src/thread_archive/_retrieval/vectors.py +611 -0
- thread_archive-0.0.2/src/thread_archive/_scripts/__init__.py +1 -0
- thread_archive-0.0.2/src/thread_archive/_scripts/backfill_recompute.py +328 -0
- thread_archive-0.0.2/src/thread_archive/_scripts/backfill_reconcile.py +296 -0
- thread_archive-0.0.2/src/thread_archive/_scripts/denamespace_dedup_keys.py +120 -0
- thread_archive-0.0.2/src/thread_archive/_scripts/recover_dropped_events.py +190 -0
- thread_archive-0.0.2/src/thread_archive/_scripts/repair_grok_tool_names.py +118 -0
- thread_archive-0.0.2/src/thread_archive/_scripts/repair_grok_tool_names_backup_20260704T155625Z.json +275 -0
- thread_archive-0.0.2/src/thread_archive/_scripts/repair_grok_tool_names_plan_20260704.json +435 -0
- thread_archive-0.0.2/src/thread_archive/_setup/__init__.py +12 -0
- thread_archive-0.0.2/src/thread_archive/_setup/clients.py +89 -0
- thread_archive-0.0.2/src/thread_archive/_setup/wizard.py +474 -0
- thread_archive-0.0.2/src/thread_archive/_store/__init__.py +45 -0
- thread_archive-0.0.2/src/thread_archive/_store/_base.py +173 -0
- thread_archive-0.0.2/src/thread_archive/_store/_defaults.py +57 -0
- thread_archive-0.0.2/src/thread_archive/_store/_types.py +38 -0
- thread_archive-0.0.2/src/thread_archive/_store/models.py +370 -0
- thread_archive-0.0.2/src/thread_archive/_store/schema.py +84 -0
- thread_archive-0.0.2/src/thread_archive/_thread_import/__init__.py +40 -0
- thread_archive-0.0.2/src/thread_archive/_thread_import/api.py +78 -0
- thread_archive-0.0.2/src/thread_archive/_thread_import/event_builder.py +810 -0
- thread_archive-0.0.2/src/thread_archive/_thread_import/exporters/__init__.py +9 -0
- thread_archive-0.0.2/src/thread_archive/_thread_import/exporters/_cursor_kv_mixin.py +166 -0
- thread_archive-0.0.2/src/thread_archive/_thread_import/exporters/_cursor_parse_mixin.py +149 -0
- thread_archive-0.0.2/src/thread_archive/_thread_import/exporters/cursor.py +582 -0
- thread_archive-0.0.2/src/thread_archive/_thread_import/exporters/cursor_parse.py +145 -0
- thread_archive-0.0.2/src/thread_archive/_thread_import/parsers/__init__.py +191 -0
- thread_archive-0.0.2/src/thread_archive/_thread_import/parsers/base.py +698 -0
- thread_archive-0.0.2/src/thread_archive/_thread_import/parsers/chatgpt.py +722 -0
- thread_archive-0.0.2/src/thread_archive/_thread_import/parsers/chatgpt_content.py +332 -0
- thread_archive-0.0.2/src/thread_archive/_thread_import/parsers/claude.py +443 -0
- thread_archive-0.0.2/src/thread_archive/_thread_import/parsers/claude_code.py +1035 -0
- thread_archive-0.0.2/src/thread_archive/_thread_import/parsers/claude_code_blocks.py +415 -0
- thread_archive-0.0.2/src/thread_archive/_thread_import/parsers/claude_code_ide.py +122 -0
- thread_archive-0.0.2/src/thread_archive/_thread_import/parsers/claude_code_sessions.py +90 -0
- thread_archive-0.0.2/src/thread_archive/_thread_import/parsers/config/__init__.py +26 -0
- thread_archive-0.0.2/src/thread_archive/_thread_import/parsers/config/base.py +220 -0
- thread_archive-0.0.2/src/thread_archive/_thread_import/parsers/cursor.py +538 -0
- thread_archive-0.0.2/src/thread_archive/_thread_import/parsers/cursor_blocks.py +365 -0
- thread_archive-0.0.2/src/thread_archive/_thread_import/parsers/pipeline/__init__.py +29 -0
- thread_archive-0.0.2/src/thread_archive/_thread_import/parsers/pipeline/base.py +251 -0
- thread_archive-0.0.2/src/thread_archive/_thread_import/parsers/pipeline/interfaces.py +191 -0
- thread_archive-0.0.2/src/thread_archive/_thread_import/parsers/transformers/__init__.py +22 -0
- thread_archive-0.0.2/src/thread_archive/_thread_import/parsers/transformers/active_path.py +87 -0
- thread_archive-0.0.2/src/thread_archive/_thread_import/parsers/transformers/coalescing.py +389 -0
- thread_archive-0.0.2/src/thread_archive/_thread_import/parsers/transformers/ide_context.py +158 -0
- thread_archive-0.0.2/src/thread_archive/_thread_import/parsers/transformers/thinking_merge.py +68 -0
- thread_archive-0.0.2/src/thread_archive/_thread_import/parsers/types/__init__.py +56 -0
- thread_archive-0.0.2/src/thread_archive/_thread_import/parsers/types/chatgpt.py +99 -0
- thread_archive-0.0.2/src/thread_archive/_thread_import/parsers/types/claude.py +120 -0
- thread_archive-0.0.2/src/thread_archive/_thread_import/parsers/types/claude_code.py +139 -0
- thread_archive-0.0.2/src/thread_archive/_thread_import/parsers/types/cursor.py +109 -0
- thread_archive-0.0.2/src/thread_archive/_thread_import/parsers/validators/__init__.py +83 -0
- thread_archive-0.0.2/src/thread_archive/_thread_import/parsers/validators/base.py +168 -0
- thread_archive-0.0.2/src/thread_archive/_thread_import/parsers/validators/content.py +80 -0
- thread_archive-0.0.2/src/thread_archive/_thread_import/parsers/validators/referential.py +57 -0
- thread_archive-0.0.2/src/thread_archive/_thread_import/parsers/validators/thinking.py +143 -0
- thread_archive-0.0.2/src/thread_archive/_thread_import/parsers/validators/types.py +87 -0
- thread_archive-0.0.2/src/thread_archive/_thread_import/schemas/__init__.py +231 -0
- thread_archive-0.0.2/src/thread_archive/_thread_import/schemas/chatgpt/v1.json +197 -0
- thread_archive-0.0.2/src/thread_archive/_thread_import/schemas/chatgpt/v2.json +203 -0
- thread_archive-0.0.2/src/thread_archive/_thread_import/schemas/claude/v1.json +188 -0
- thread_archive-0.0.2/src/thread_archive/_thread_import/schemas/claude_code/v1.json +183 -0
- thread_archive-0.0.2/src/thread_archive/_thread_import/schemas/cursor/v1.json +143 -0
- thread_archive-0.0.2/src/thread_archive/_thread_import/schemas/cursor/v2.json +200 -0
- thread_archive-0.0.2/src/thread_archive/_thread_import/timestamps.py +57 -0
- thread_archive-0.0.2/src/thread_archive/_thread_import/tool_names.py +48 -0
- thread_archive-0.0.2/src/thread_archive/_truth/__init__.py +40 -0
- thread_archive-0.0.2/src/thread_archive/_truth/jsonl_log.py +2340 -0
- thread_archive-0.0.2/src/thread_archive/_truth/repair.py +322 -0
- thread_archive-0.0.2/src/thread_archive/_watcher/__init__.py +57 -0
- thread_archive-0.0.2/src/thread_archive/_watcher/base.py +65 -0
- thread_archive-0.0.2/src/thread_archive/_watcher/daemon.py +289 -0
- thread_archive-0.0.2/src/thread_archive/_watcher/export_drop.py +203 -0
- thread_archive-0.0.2/src/thread_archive/_watcher/exthost.py +316 -0
- thread_archive-0.0.2/src/thread_archive/_watcher/lazy.py +117 -0
- thread_archive-0.0.2/src/thread_archive/_watcher/sources.py +616 -0
- thread_archive-0.0.2/src/thread_archive/_web/__init__.py +15 -0
- thread_archive-0.0.2/src/thread_archive/_web/server.py +299 -0
- thread_archive-0.0.2/src/thread_archive/_web/static/assets/index-DECSH1Mz.css +10 -0
- thread_archive-0.0.2/src/thread_archive/_web/static/assets/index-Djq0FK0y.js +101 -0
- thread_archive-0.0.2/src/thread_archive/_web/static/index.html +13 -0
- thread_archive-0.0.2/src/thread_archive/cli.py +746 -0
- thread_archive-0.0.2/tests/__init__.py +0 -0
- thread_archive-0.0.2/tests/conftest.py +68 -0
- thread_archive-0.0.2/tests/goldens/providers/antigravity.json +134 -0
- thread_archive-0.0.2/tests/goldens/providers/claude-code.json +258 -0
- thread_archive-0.0.2/tests/goldens/providers/cloth.json +120 -0
- thread_archive-0.0.2/tests/goldens/providers/codex.json +83 -0
- thread_archive-0.0.2/tests/goldens/providers/cursor.json +184 -0
- thread_archive-0.0.2/tests/goldens/providers/grok.json +177 -0
- thread_archive-0.0.2/tests/goldens/providers/opencode.json +86 -0
- thread_archive-0.0.2/tests/helpers.py +74 -0
- thread_archive-0.0.2/tests/install/Dockerfile +32 -0
- thread_archive-0.0.2/tests/install/README.md +56 -0
- thread_archive-0.0.2/tests/install/e2e_check.py +102 -0
- thread_archive-0.0.2/tests/install/make_fixtures.py +176 -0
- thread_archive-0.0.2/tests/install/obfuscate_fixtures.py +204 -0
- thread_archive-0.0.2/tests/install/run_in_container.sh +26 -0
- thread_archive-0.0.2/tests/install/run_install_test.sh +24 -0
- thread_archive-0.0.2/tests/mp_child.py +91 -0
- thread_archive-0.0.2/tests/test_api.py +75 -0
- thread_archive-0.0.2/tests/test_backfill_dedup_key.py +156 -0
- thread_archive-0.0.2/tests/test_backup_mirror.py +300 -0
- thread_archive-0.0.2/tests/test_chatgpt_timestamps.py +65 -0
- thread_archive-0.0.2/tests/test_cli_smoke.py +69 -0
- thread_archive-0.0.2/tests/test_codex_render.py +151 -0
- thread_archive-0.0.2/tests/test_continuation.py +149 -0
- thread_archive-0.0.2/tests/test_dedup_collapse_and_deep_verify.py +241 -0
- thread_archive-0.0.2/tests/test_drain_intent.py +186 -0
- thread_archive-0.0.2/tests/test_durability_and_homes.py +161 -0
- thread_archive-0.0.2/tests/test_event_builder.py +376 -0
- thread_archive-0.0.2/tests/test_event_builder_fidelity.py +100 -0
- thread_archive-0.0.2/tests/test_export_drop.py +204 -0
- thread_archive-0.0.2/tests/test_exports.py +85 -0
- thread_archive-0.0.2/tests/test_exthost.py +142 -0
- thread_archive-0.0.2/tests/test_import_ratchet.py +103 -0
- thread_archive-0.0.2/tests/test_import_state_watermarks.py +99 -0
- thread_archive-0.0.2/tests/test_importer_claude_code.py +537 -0
- thread_archive-0.0.2/tests/test_importer_claude_science.py +205 -0
- thread_archive-0.0.2/tests/test_importer_cowork.py +69 -0
- thread_archive-0.0.2/tests/test_importer_providers.py +319 -0
- thread_archive-0.0.2/tests/test_ingest_cursor_hardening.py +173 -0
- thread_archive-0.0.2/tests/test_integrity_hardening.py +343 -0
- thread_archive-0.0.2/tests/test_kg_materialize.py +131 -0
- thread_archive-0.0.2/tests/test_kg_write.py +278 -0
- thread_archive-0.0.2/tests/test_knowledge.py +86 -0
- thread_archive-0.0.2/tests/test_launchd.py +41 -0
- thread_archive-0.0.2/tests/test_lazy_ingest.py +97 -0
- thread_archive-0.0.2/tests/test_librarian_claims.py +113 -0
- thread_archive-0.0.2/tests/test_librarian_gate.py +107 -0
- thread_archive-0.0.2/tests/test_manifest.py +53 -0
- thread_archive-0.0.2/tests/test_mcp.py +140 -0
- thread_archive-0.0.2/tests/test_mcp_librarian.py +75 -0
- thread_archive-0.0.2/tests/test_migration_scripts.py +303 -0
- thread_archive-0.0.2/tests/test_multiprocess_durability.py +192 -0
- thread_archive-0.0.2/tests/test_nightly.py +270 -0
- thread_archive-0.0.2/tests/test_package_artifact.py +269 -0
- thread_archive-0.0.2/tests/test_preserve_antigravity.py +96 -0
- thread_archive-0.0.2/tests/test_preserve_cc_builder.py +122 -0
- thread_archive-0.0.2/tests/test_preserve_codex.py +88 -0
- thread_archive-0.0.2/tests/test_preserve_cursor_import.py +242 -0
- thread_archive-0.0.2/tests/test_preserve_exports.py +200 -0
- thread_archive-0.0.2/tests/test_preserve_grok.py +119 -0
- thread_archive-0.0.2/tests/test_preserve_opencode.py +254 -0
- thread_archive-0.0.2/tests/test_provider_goldens.py +300 -0
- thread_archive-0.0.2/tests/test_public_api.py +85 -0
- thread_archive-0.0.2/tests/test_read.py +400 -0
- thread_archive-0.0.2/tests/test_read_queued_slotting.py +117 -0
- thread_archive-0.0.2/tests/test_read_unknown_events.py +77 -0
- thread_archive-0.0.2/tests/test_recover_dropped_events.py +83 -0
- thread_archive-0.0.2/tests/test_reindex_fail_closed.py +255 -0
- thread_archive-0.0.2/tests/test_rerank.py +170 -0
- thread_archive-0.0.2/tests/test_retrieval_meta_and_filters.py +163 -0
- thread_archive-0.0.2/tests/test_search.py +321 -0
- thread_archive-0.0.2/tests/test_setup_wizard.py +256 -0
- thread_archive-0.0.2/tests/test_shard_twins.py +107 -0
- thread_archive-0.0.2/tests/test_store.py +193 -0
- thread_archive-0.0.2/tests/test_structured_model_split.py +196 -0
- thread_archive-0.0.2/tests/test_transformer_coalescing.py +287 -0
- thread_archive-0.0.2/tests/test_truth.py +543 -0
- thread_archive-0.0.2/tests/test_truth_manifest.py +112 -0
- thread_archive-0.0.2/tests/test_truth_repair.py +248 -0
- thread_archive-0.0.2/tests/test_vector_sidecar.py +84 -0
- thread_archive-0.0.2/tests/test_vectors.py +230 -0
- thread_archive-0.0.2/tests/test_vendor_thread_import.py +38 -0
- thread_archive-0.0.2/tests/test_verify.py +424 -0
- thread_archive-0.0.2/tests/test_watch.py +308 -0
- thread_archive-0.0.2/tests/test_web.py +348 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# venvs
|
|
2
|
+
.venv/
|
|
3
|
+
venv/
|
|
4
|
+
|
|
5
|
+
# python
|
|
6
|
+
__pycache__/
|
|
7
|
+
*.py[cod]
|
|
8
|
+
*.egg-info/
|
|
9
|
+
/dist/
|
|
10
|
+
.pytest_cache/
|
|
11
|
+
.ruff_cache/
|
|
12
|
+
.mypy_cache/
|
|
13
|
+
|
|
14
|
+
# Archive data lives in the user's home (~/.thread/archive), NEVER in the repo.
|
|
15
|
+
# These are belt-and-suspenders in case a run is pointed at the repo by mistake.
|
|
16
|
+
# All anchored to the repo root so they can't shadow the source tree (e.g. the
|
|
17
|
+
# `src/thread_archive/truth/` module must stay tracked).
|
|
18
|
+
/data/
|
|
19
|
+
/index.db
|
|
20
|
+
/index.db-*
|
|
21
|
+
/truth/
|
|
22
|
+
/*.sqlite
|
|
23
|
+
|
|
24
|
+
# Machine-specific MCP client config — generated at install time with absolute paths
|
|
25
|
+
# to this clone's venv (see claude-install.md). The tracked template is .mcp.json.example.
|
|
26
|
+
/.mcp.json
|
|
27
|
+
|
|
28
|
+
# Obfuscated corpus built from real local stores by tests/install/obfuscate_fixtures.py.
|
|
29
|
+
# Private even after obfuscation — never commit it.
|
|
30
|
+
tests/install/fixtures-real/
|
|
31
|
+
|
|
32
|
+
# coverage data (pytest --cov; the CI pytest row reports coverage per run,
|
|
33
|
+
# and writes coverage.json for the coverage-gate row)
|
|
34
|
+
/.coverage
|
|
35
|
+
/.coverage.*
|
|
36
|
+
/coverage.json
|
|
37
|
+
|
|
38
|
+
# os
|
|
39
|
+
.DS_Store
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_comment": "Template. Copy to .mcp.json and replace ABSOLUTE_REPO_PATH with this clone's absolute path (the install step does this for you). The two servers split read from write: thread-archive is read-only (search/read); thread-archive-librarian carries the curation writes + the librarian skill's reads.",
|
|
3
|
+
"mcpServers": {
|
|
4
|
+
"thread-archive": {
|
|
5
|
+
"command": "ABSOLUTE_REPO_PATH/.venv/bin/archive-mcp",
|
|
6
|
+
"env": { "THREAD_ARCHIVE_HOME": "~/.thread/archive" }
|
|
7
|
+
},
|
|
8
|
+
"thread-archive-librarian": {
|
|
9
|
+
"command": "ABSOLUTE_REPO_PATH/.venv/bin/archive-librarian-mcp",
|
|
10
|
+
"env": { "THREAD_ARCHIVE_HOME": "~/.thread/archive" }
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.0.2 — 2026-07-11
|
|
4
|
+
|
|
5
|
+
First release published to PyPI: `pip install thread-archive`.
|
|
6
|
+
|
|
7
|
+
- **`thread_archive` — first-run setup and the human status view (2026-07-11).**
|
|
8
|
+
The consumer front door the pip story was missing: `pip install
|
|
9
|
+
thread-archive` then `thread_archive` runs an interactive setup that
|
|
10
|
+
*discovers* the machine's conversation stores (stat-only dry run: counts,
|
|
11
|
+
sizes, date ranges — new `SourceWatcher.discover()`), shows what it found
|
|
12
|
+
and where copies will live before touching anything, imports with per-source
|
|
13
|
+
narration (importer log noise routed to `<home>/logs/setup.log`), then
|
|
14
|
+
offers the launchd watcher and MCP wiring (`claude mcp add` run for you at
|
|
15
|
+
user scope, or the JSON block printed for any other client). Every step is
|
|
16
|
+
skippable; choices persist in the new `<home>/config.json`, and disabled
|
|
17
|
+
sources are honored by every ingest path (daemon, lazy MCP catch-up,
|
|
18
|
+
`archive watch`) via `enabled_watchers()`. Re-running lands on a status
|
|
19
|
+
view; `thread_archive setup` re-enters the flow; `--yes` is the
|
|
20
|
+
non-interactive twin (a non-TTY run without it only prints guidance — and
|
|
21
|
+
checking "is this set up?" no longer scaffolds an empty home as a side
|
|
22
|
+
effect). Both `thread_archive` and `thread-archive` console scripts ship.
|
|
23
|
+
`archive` stays the operator seam.
|
|
24
|
+
|
|
25
|
+
- **Verify's index self-check no longer false-alarms "malformed inverted index"
|
|
26
|
+
(2026-07-11).** Both of today's nightly `verify` failures — the
|
|
27
|
+
highest-severity alarm the system has, fired twice on a healthy archive —
|
|
28
|
+
came from running `PRAGMA quick_check` on a pooled connection: FTS5's
|
|
29
|
+
integrity check consults per-connection segment-structure state, and a
|
|
30
|
+
connection that lives across the watcher's continuous `event_search` rewrites
|
|
31
|
+
can report a healthy index as malformed (reproduced 3-of-5 on a warm pool
|
|
32
|
+
while a simultaneous fresh connection said `ok` every time; likely an
|
|
33
|
+
upstream SQLite 3.51 bug in the FTS5 xIntegrity path). The pragma now runs on
|
|
34
|
+
a private, just-opened connection to the engine's own database file
|
|
35
|
+
(`_api.verify`). Corruption that surfaces as a *raised* `DatabaseError`
|
|
36
|
+
(rather than result rows) is now also captured as a red `quick_check`
|
|
37
|
+
verdict instead of crashing verify; locked/can't-open stays an error so
|
|
38
|
+
environmental trouble can't impersonate corruption. A new test corrupts an
|
|
39
|
+
index page on disk and requires verify to name `quick_check` red.
|
|
40
|
+
|
|
41
|
+
- **The package lane now drives the installed `archive-mcp` binary the way a
|
|
42
|
+
consumer's client does (2026-07-11):** JSON-RPC over stdio against the
|
|
43
|
+
clean-venv install — tools/list, the first `thread_search` on a virgin home
|
|
44
|
+
(the regression shape of the first-open schema race below), and search+read
|
|
45
|
+
over imported data. The lane's CLI lifecycle test also caught up with the
|
|
46
|
+
retrieval-verb removal (it still called `archive search`/`read`; it now
|
|
47
|
+
exercises ingest + the durability kit, with retrieval covered via MCP).
|
|
48
|
+
|
|
49
|
+
- **First search on a virgin archive no longer dies with "table already exists"
|
|
50
|
+
(2026-07-11).** `init_db`'s `create_all` existence check isn't atomic with its
|
|
51
|
+
CREATEs, so the MCP server's warm-models search (a background thread at
|
|
52
|
+
startup) racing the first tool call on an empty home made one of them lose the
|
|
53
|
+
CREATE and error — breaking the very first `thread_search` of a fresh install.
|
|
54
|
+
`init_db` now serializes openers in-process and retries a lost cross-process
|
|
55
|
+
race (`_store/schema.py`).
|
|
56
|
+
|
|
57
|
+
- **`archive-mcp` cohosts lazy catch-up ingest, and the watcher LaunchAgent
|
|
58
|
+
installs from the package (2026-07-11).** The zero-daemon install path:
|
|
59
|
+
`pip install thread-archive` + `claude mcp add thread-archive -- archive-mcp`
|
|
60
|
+
is now the whole setup — the MCP server runs a throttled background ingest
|
|
61
|
+
pass at startup and around tool calls (`_watcher/lazy.py`;
|
|
62
|
+
`THREAD_ARCHIVE_MCP_INGEST=0` disables), so search sees current
|
|
63
|
+
conversations with nothing else installed. Cross-process safety is a new
|
|
64
|
+
ingest-owner flock (`<home>/.ingest-owner.lock`): a lazy pass runs only
|
|
65
|
+
while holding it exclusively, and the watcher daemon holds it for its whole
|
|
66
|
+
lifetime — so with the daemon alive (or several MCP servers racing), exactly
|
|
67
|
+
one process ingests and the rest skip, losing nothing (sources replay from
|
|
68
|
+
import state; dedup_key collapses any overlap).
|
|
69
|
+
The always-fresh upgrade is now `archive daemon install|uninstall|restart|
|
|
70
|
+
status` (`_launchd.py`, macOS-only): the plist is generated in-package,
|
|
71
|
+
pointing at the installed `archive` console script — no repo checkout, no
|
|
72
|
+
sed. `host/Makefile` delegates its watcher targets to the verb (its template
|
|
73
|
+
plist is deleted; the Makefile's remaining value-add is the thread-family
|
|
74
|
+
manifest and the backup agent). Mac-only is a deliberate product decision.
|
|
75
|
+
|
|
76
|
+
- **The public API is narrowed to exactly two things (2026-07-11): the
|
|
77
|
+
retrieval MCP tools (`thread_search` / `thread_read`, served by
|
|
78
|
+
`archive-mcp`) and the on-disk truth format (docs/format.md).** Everything
|
|
79
|
+
else is now declared private support machinery — the `archive` CLI, the
|
|
80
|
+
librarian MCP server, the web viewer, and all Python modules. Not ready ≠
|
|
81
|
+
not shipped: the private pieces keep running (launchd, cron, and the /ci
|
|
82
|
+
skill drive the CLI), they just carry no external stability promise; more
|
|
83
|
+
surface gets exposed deliberately as it matures.
|
|
84
|
+
As part of the same narrowing, `archive search`, `archive read`, and
|
|
85
|
+
`archive web` are removed (with `_web.serve`, the foreground server only
|
|
86
|
+
`web` called): retrieval traffic belongs to the public MCP tools, and the
|
|
87
|
+
viewer's persistent URL was already the watcher's (`archive watch --web`),
|
|
88
|
+
so the standalone verbs were extra doors onto the same surface. The CLI
|
|
89
|
+
keeps only ingest (`import`, `import-export`, `watch`, `embed`) and the
|
|
90
|
+
durability kit (`backup`, `verify`, `restore-drill`, `reindex`, `repair`,
|
|
91
|
+
`status`, `nightly`). `tests/test_public_api.py` pins the verb set — as
|
|
92
|
+
internal-wiring coordination (plists, cron, skills reference these verbs),
|
|
93
|
+
not as public API — and pins the *absence* of retrieval verbs.
|
|
94
|
+
|
|
95
|
+
- **A proven-fixed stage retires its own failure (2026-07-11).** The only thing
|
|
96
|
+
that could clear a failed nightly was another full nightly (~1h, restore-drill
|
|
97
|
+
dominated), so an archive that had been fixed *and re-verified at full strength*
|
|
98
|
+
went on announcing itself unprotected until 04:00 came around. `nightly` now
|
|
99
|
+
publishes a **verdict** rather than a transcript: `_pipeline_verdict` takes the
|
|
100
|
+
last nightly's `failed_stages` and subtracts every stage a later, at-least-as-
|
|
101
|
+
strong run has since proven good, and `_stamp_heartbeat` republishes it — called
|
|
102
|
+
from `verify` / `backup` / `restore_drill` as well as `nightly`, so re-running a
|
|
103
|
+
stage on its own clears the board.
|
|
104
|
+
The strength comparison is the guard, and it matters for verify alone: the
|
|
105
|
+
nightly escalates verify on age gates (`deep`, `hashes`, and the mirror
|
|
106
|
+
parse-scan, which rides `--backup` exactly when deep is due), so a later *basic*
|
|
107
|
+
verify passing says nothing about a deep tier that failed. `verify_last` now
|
|
108
|
+
records its tier (`deep` / `hashes` / `backup`) for that comparison to read;
|
|
109
|
+
without it, a cheap green would launder an expensive red. A rerun weaker than
|
|
110
|
+
the check that failed retires nothing — by design.
|
|
111
|
+
The heartbeat gained `nightly_at` (when the pipeline last *ran*) alongside `at`
|
|
112
|
+
(when the file was last written), because those stopped being the same fact the
|
|
113
|
+
moment a lone stage rerun could rewrite it: thread-monitor anchors its
|
|
114
|
+
"backups have stopped happening" staleness check on `nightly_at`, so a hand-run
|
|
115
|
+
verify can no longer mask a dead 04:00 job.
|
|
116
|
+
|
|
117
|
+
- The test suite grew the boundaries a review flagged as untested — the places
|
|
118
|
+
where reality differs from the in-process synthetic environment:
|
|
119
|
+
- A **package lane** (`tests/test_package_artifact.py`, `-m package`,
|
|
120
|
+
deselected from the default run) builds the wheel + sdist, asserts their
|
|
121
|
+
contents (vendored parsers, provider JSON schemas, pre-built web assets, no
|
|
122
|
+
stray top-level packages), installs the wheel into a clean venv, and runs
|
|
123
|
+
the real `archive` CLI lifecycle from it. The Docker install test now
|
|
124
|
+
builds and installs the wheel instead of `pip install -e`.
|
|
125
|
+
- A **multiprocess durability suite** (`tests/test_multiprocess_durability.py`)
|
|
126
|
+
exercises the flock/fsync/drain-intent protocol with real processes:
|
|
127
|
+
writers SIGKILLed at each drain window (via `tests/mp_child.py`), four
|
|
128
|
+
concurrent importers, and a same-session import race — each converging to a
|
|
129
|
+
verified, single-copy store.
|
|
130
|
+
- **Provider goldens** (`tests/test_provider_goldens.py` +
|
|
131
|
+
`tests/goldens/providers/`): every importer's full normalized truth output
|
|
132
|
+
is locked against a reviewed golden file (regenerate with
|
|
133
|
+
`UPDATE_GOLDENS=1`), so an importer change shows as a reviewable diff.
|
|
134
|
+
- **Migration/repair script tests** (`tests/test_migration_scripts.py`) cover
|
|
135
|
+
the run()/apply/backup/idempotence paths of the `_scripts` migrations,
|
|
136
|
+
including `repair_grok_tool_names` (previously 0% — its committed plan file
|
|
137
|
+
doubles as the fixture).
|
|
138
|
+
- **Frontend component tests** (Vitest + Testing Library, `npm test` /
|
|
139
|
+
the `frontend-test` CI row): block rendering, loading/error/empty states,
|
|
140
|
+
search grouping, uuid→thread redirects, model grouping. Previously the SPA
|
|
141
|
+
only had a typecheck.
|
|
142
|
+
- **Coverage became a gate**: the CI pytest row measures branch coverage and
|
|
143
|
+
`scripts/coverage_gate.py` (its own CI row) enforces per-package floors — a
|
|
144
|
+
regression ratchet calibrated just under measured coverage, instead of one
|
|
145
|
+
global threshold that dormant vendored parser code would render meaningless.
|
|
146
|
+
- Pytest markers with `--strict-markers`: `integration` (real sockets /
|
|
147
|
+
subprocesses; deselectable for hermetic sandboxes) and `package`.
|
|
148
|
+
|
|
149
|
+
- The family-manifest writer left the package: `thread_archive/manifest.py` is
|
|
150
|
+
now `host/write-manifest.py`. It was the one member of the public surface that
|
|
151
|
+
made no sense to a `pip install` consumer — a thread-family integration point,
|
|
152
|
+
and one that resolved its MCP command paths from a repo checkout (meaningless
|
|
153
|
+
under `site-packages`, where it silently emitted a manifest with no `mcp`
|
|
154
|
+
block). `host/` is installer machinery and is never packaged, which is exactly
|
|
155
|
+
what this is; `make install-agent` and `make manifest` (add `WEB=0` for
|
|
156
|
+
`--no-web`) call it there. `cli` is now the only public module name.
|
|
157
|
+
|
|
158
|
+
- The public Python API is gone — deliberately. `api.py` became `_api.py`, a
|
|
159
|
+
private coordination layer the CLI, MCP servers, and web viewer call into;
|
|
160
|
+
`thread_archive.__all__` shrank to `__version__`. Nothing outside the repo
|
|
161
|
+
imported the Python surface, and the durability promise was always the
|
|
162
|
+
on-disk truth format, not function signatures. The supported surface is now
|
|
163
|
+
exactly: the `archive` CLI, the two MCP servers, and the truth format
|
|
164
|
+
(docs/format.md). Programmatic read access goes through the
|
|
165
|
+
documented stores (index.db is plain SQLite; truth is documented JSONL).
|
|
166
|
+
The ratchet test now pins the surface at empty.
|
|
167
|
+
|
|
168
|
+
- The public surface is now locked down to what's deliberately advertised:
|
|
169
|
+
every internal subpackage is underscore-private (`_store`, `_truth`,
|
|
170
|
+
`_retrieval`, `_knowledge`, `_importers`, `_watcher`, `_mcp`, `_web`,
|
|
171
|
+
`_scripts`, `_config`), leaving only `api`, `cli`, and `manifest` at public
|
|
172
|
+
names. `api.embed` (the `archive embed` backend) joined `__all__` — it was
|
|
173
|
+
the one public-named api function not re-exported. A ratchet test
|
|
174
|
+
(`tests/test_public_api.py`) pins `__all__`, the api-module surface, and the
|
|
175
|
+
set of public module names, so widening the API is an edit to a pinned list,
|
|
176
|
+
never a naming accident. README gained a Stability section stating the
|
|
177
|
+
supported surface.
|
|
178
|
+
|
|
179
|
+
- The truth storage format is now versioned and specified: `docs/format.md`
|
|
180
|
+
documents the truth directory (manifest, per-thread files, sharding, record
|
|
181
|
+
shapes, dedup-key form, overlays, kg log, import cursors), the manifest's
|
|
182
|
+
existing `version: 1` is declared as the format version with a bump policy
|
|
183
|
+
(only for changes an existing reader would misinterpret), and readers now
|
|
184
|
+
*refuse* a truth directory declaring a newer version (`TruthFormatError`)
|
|
185
|
+
instead of guessing at unknown layout semantics.
|
|
186
|
+
|
|
187
|
+
- The vendored provider-parser island moved from a public top-level
|
|
188
|
+
`thread_import` package to `thread_archive._thread_import` — a pip install
|
|
189
|
+
no longer plants a second, generically named public package in
|
|
190
|
+
site-packages, and the parser API stays private until it's deliberately
|
|
191
|
+
exposed.
|
|
192
|
+
|
|
193
|
+
- PyPI release readiness: version single-sourced from `thread_archive.__version__`
|
|
194
|
+
(pyproject declares it dynamic); `[project.urls]` added;
|
|
195
|
+
sdist contents pinned via `[tool.hatch.build.targets.sdist]` `only-include`
|
|
196
|
+
(hatchling only reads the root `.gitignore`, so `frontend/node_modules` —
|
|
197
|
+
ignored only by the nested `frontend/.gitignore` — was ballooning the sdist
|
|
198
|
+
to 17 MB; it and repo-local dirs like `host/` and `.claude/` are now
|
|
199
|
+
excluded). README gains a `pip install thread-archive` path and the real
|
|
200
|
+
clone URL. Built distributions land in `dist/` (gitignored) for
|
|
201
|
+
`twine upload`.
|
|
202
|
+
|
|
203
|
+
- Integrity hardening (from the self-review in thread 3716422), four gates at
|
|
204
|
+
the transaction/content seams: (1) the backup mirror traversal now runs under
|
|
205
|
+
the truth-write mutex, so a copy can never capture a mid-drain partial batch
|
|
206
|
+
or a pre-rollback append that the shrink guard would then pin in the mirror;
|
|
207
|
+
(2) `verify --hashes --backup` now *fails* on a mirror hash-mismatch count
|
|
208
|
+
above the previous run's for that destination (it was report-only), with the
|
|
209
|
+
same fails-once baseline absorption as the live scan (`backup_hashes`
|
|
210
|
+
component, `backup_hashes_last` in health); (3) `rebuild_truth_from_store`
|
|
211
|
+
grew two content pre-flights behind the existing containment gate — it
|
|
212
|
+
refuses when any store payload fails the content hash in its own dedup_key
|
|
213
|
+
(a corrupted index row that kept its id/key must not replace the good truth
|
|
214
|
+
line) and when truth records carry fields the running code's models don't map
|
|
215
|
+
(an older binary must not lossily re-emit newer truth); `force=True` remains
|
|
216
|
+
the deliberate override; (4) `repair_truth` self-validates restore candidates
|
|
217
|
+
the same way — a failing payload is still restored (it's the only copy left)
|
|
218
|
+
but counted (`restored_hash_mismatches`) and logged, and the next
|
|
219
|
+
`verify --hashes` reports it. Plus a fifth, report-only seam: reindex counts
|
|
220
|
+
and logs same-id event content it is about to overwrite in the index
|
|
221
|
+
(`content_overwrites` + sample ids in its result, salvage or not). A blocking
|
|
222
|
+
content gate was rejected (below), but for an *unkeyed* event the index row
|
|
223
|
+
can be the last good copy of a truth line rotted in place, and once the swap
|
|
224
|
+
lands the two stores agree — cross-store parity can never see it again; the
|
|
225
|
+
publication report is the last observable moment of the overwrite.
|
|
226
|
+
Reviewed but deliberately not adopted: a durable per-drain transaction ledger
|
|
227
|
+
(truth-ahead-of-index is the designed safe direction; dedup collapses
|
|
228
|
+
resurrections), a *blocking* content-equality reindex gate (would invert
|
|
229
|
+
truth's authority over the index; cross-store parity in `verify --hashes` is
|
|
230
|
+
the detector, and the report-only counter above covers the laundering
|
|
231
|
+
window), and sticky-red-until-acknowledged hash semantics (the fails-once
|
|
232
|
+
baseline + failure ledger is the documented tradeoff).
|
|
233
|
+
|
|
234
|
+
- Ingest hardening (from the self-review in thread 3716420): the line-stream
|
|
235
|
+
cursor no longer assumes its source is append-only. The watermark carries a
|
|
236
|
+
sha256 of the bytes it was computed over (`import_state.last_content_hash`), and
|
|
237
|
+
each poll re-hashes the file's prefix to prove the imported lines are still the
|
|
238
|
+
file's first lines — a mismatch rewinds to line 0 and re-imports, dedup_key
|
|
239
|
+
collapsing what's already held. This closes three silent-loss paths that all
|
|
240
|
+
looked like "nothing changed" to the old size-equality check: a line rewritten
|
|
241
|
+
to the same serialized length, a truncate-and-regrow between polls, and — the
|
|
242
|
+
sharp one — a malformed *interior* line later repaired, which shifted every
|
|
243
|
+
later line's index out from under a cursor that counts parsed, not physical,
|
|
244
|
+
lines. A torn final line still reads as the append it is, not a rewrite.
|
|
245
|
+
- A turn split across polls stays one turn: the assistant reply whose user line
|
|
246
|
+
landed in an earlier poll now inherits that turn's `stream_id` instead of
|
|
247
|
+
opening its own.
|
|
248
|
+
- Per-item failures inside the Cursor / OpenCode / Claude Science DB scans reach
|
|
249
|
+
the watcher's health instead of only the log — a caught-and-logged failure left
|
|
250
|
+
the scan looking like a clean "nothing new" while a conversation was missing.
|
|
251
|
+
- The import loop asks the index only about the dedup keys it built this pass,
|
|
252
|
+
rather than loading every key in the thread — a poll of a long session no longer
|
|
253
|
+
pays for the whole session's history.
|
|
254
|
+
- `init_db` ALTERs in columns added after a table shipped (`create_all` only ever
|
|
255
|
+
issues `CREATE TABLE`, so a live index never grew one). Missing *indexes* stay
|
|
256
|
+
with verify/reindex.
|
|
257
|
+
- A red verify names its cause and keeps its evidence: results carry
|
|
258
|
+
`failed_components`, the full result of any failing run is appended to
|
|
259
|
+
`<home>/verify-failures.jsonl`, and the deep/hashes health records now carry
|
|
260
|
+
their own tier's verdict (prompted by a nightly that went red with nothing
|
|
261
|
+
persisted to say why).
|
|
262
|
+
- `verify --hashes` grew cross-store payload parity: truth and index payloads
|
|
263
|
+
are fingerprint-compared per id, so rot in an *unkeyed* payload (most
|
|
264
|
+
pre-dedup-key history) is detectable instead of being silently promoted over
|
|
265
|
+
the good index row by the next reindex. Deep verify does the same for the kg
|
|
266
|
+
log's content.
|
|
267
|
+
- The curatorial log joined the daily tier: shallow verify parse-scans
|
|
268
|
+
`kg_events.jsonl` and count-checks it against the table (it previously waited
|
|
269
|
+
up to a week for the deep pass), and the deep kg id-diff is now
|
|
270
|
+
watermark-bounded so a live librarian write can't false-alarm it.
|
|
271
|
+
- `verify --backup` fails on a mirror whose effective count dropped since the
|
|
272
|
+
previous scan (the drill's coverage floor only sees drops ≥2%).
|
|
273
|
+
- Watcher poll errors surface in health.json / `archive status` instead of
|
|
274
|
+
living only in stderr logs.
|
|
275
|
+
|
|
276
|
+
## 0.0.1 — 2026-07-11
|
|
277
|
+
|
|
278
|
+
- Retrieval correctness pass (from the self-review in thread 3716414): the
|
|
279
|
+
semantic arm now sits out of `tool_name`-scoped, count, and oldest searches
|
|
280
|
+
(tool docs aren't embedded, so every fused hit violated the filter);
|
|
281
|
+
`exclude_content_type` narrows the KNN scope itself instead of discarding
|
|
282
|
+
candidates post-top-k; vector chunk max-pooling moved *before* the top-k cut
|
|
283
|
+
so one long doc can't eat candidate slots; natural-language queries get a
|
|
284
|
+
bm25 OR-fallback tier over meaningful terms when the strict all-terms MATCH
|
|
285
|
+
under-fills (fixes hard zero-recall on conversational queries, lexical-only
|
|
286
|
+
installs especially); `sort='oldest'` scans the index chronologically so the
|
|
287
|
+
pool holds true first mentions; the vector matrix cache is canonicalized by
|
|
288
|
+
scope and bounded.
|
|
289
|
+
- Crash-safe truth appends: drain intent journal, all-or-nothing batches,
|
|
290
|
+
torn-tail repair, exclusive cross-process truth-write locking, and dedup
|
|
291
|
+
enforced as a DB constraint (`(thread_id, dedup_key)` unique).
|
|
292
|
+
- Reindex fails closed: committed-content regression gates, `quick_check` +
|
|
293
|
+
foreign-key checks before the index swap, citations repointed across dedup
|
|
294
|
+
collapse, and vectors survive a plain reindex.
|
|
295
|
+
- `verify` grew tiers: shallow daily parity, `--deep` truth↔index diffs and
|
|
296
|
+
search-surface checks, `--hashes` content self-validation with baselines,
|
|
297
|
+
`--backup` mirror scans, and declared-schema parity.
|
|
298
|
+
- Backup hardened: atomic publishes, shrink guard, bounded deletions, per-run
|
|
299
|
+
hardlink generations, and restore drills; `archive nightly` runs
|
|
300
|
+
backup → verify → drill with per-stage health records and a heartbeat stamp
|
|
301
|
+
for monitoring.
|
|
302
|
+
- `archive repair`: quarantines unparseable truth lines and restores committed
|
|
303
|
+
content — the sanctioned path from a red verify back to green.
|
|
304
|
+
- One-time duplicate repair: ~27k duplicated turns collapsed, ~237k dedup keys
|
|
305
|
+
backfilled, and rebuilds now reproduce the repair instead of undoing it.
|
|
306
|
+
- Retrieval overhaul: thread titles/summaries indexed as searchable docs,
|
|
307
|
+
long documents chunked into the vector space, canonical time-bound format,
|
|
308
|
+
identifier-recall fixes, auto-widening MCP search scope, and an eval harness
|
|
309
|
+
(MRR / recall@k).
|
|
310
|
+
- Test suite pinned model-free (~2 min → ~8 s), integrity tests renamed by
|
|
311
|
+
behavior, coverage measured on every CI sweep, librarian MCP covered.
|
|
312
|
+
- `GET /api/archive-link` resolves a candidate list of ids, first real one
|
|
313
|
+
wins.
|
|
314
|
+
|
|
315
|
+
## 0.0.0 — initial release
|
|
316
|
+
|
|
317
|
+
- Serverless local archive over `~/.thread/archive`: append-only JSONL truth
|
|
318
|
+
plus a rebuildable SQLite index.
|
|
319
|
+
- Multi-provider importers: Claude Code, Cursor, OpenCode, ChatGPT/Anthropic
|
|
320
|
+
exports, Grok, cloth, and friends.
|
|
321
|
+
- Watcher daemon (`archive watch`) tails harness stores and ingests
|
|
322
|
+
continuously.
|
|
323
|
+
- Retrieval MCP server: `thread_search` (FTS + optional semantic/rerank arms)
|
|
324
|
+
and `thread_read`.
|
|
325
|
+
- Librarian MCP: topics, citations, thread links, and a review queue for
|
|
326
|
+
knowledge curation.
|
|
327
|
+
- Read-only web viewer cohosted at `:8787` (`archive watch --web`).
|
|
328
|
+
- CLI: import/export, reindex, checkpoint, backup, verify.
|
|
@@ -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.
|