folio-cli 0.3.0__tar.gz → 0.3.1__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.
- {folio_cli-0.3.0/src/folio_cli.egg-info → folio_cli-0.3.1}/PKG-INFO +7 -7
- {folio_cli-0.3.0 → folio_cli-0.3.1}/README.md +6 -4
- {folio_cli-0.3.0 → folio_cli-0.3.1}/pyproject.toml +9 -2
- {folio_cli-0.3.0 → folio_cli-0.3.1}/src/folio/__init__.py +1 -1
- {folio_cli-0.3.0 → folio_cli-0.3.1}/src/folio/cli.py +6 -2
- {folio_cli-0.3.0 → folio_cli-0.3.1}/src/folio/distribute.py +52 -4
- {folio_cli-0.3.0 → folio_cli-0.3.1}/src/folio/store.py +55 -4
- {folio_cli-0.3.0 → folio_cli-0.3.1/src/folio_cli.egg-info}/PKG-INFO +7 -7
- {folio_cli-0.3.0 → folio_cli-0.3.1}/src/folio_cli.egg-info/requires.txt +0 -2
- {folio_cli-0.3.0 → folio_cli-0.3.1}/tests/test_distribute.py +1 -1
- {folio_cli-0.3.0 → folio_cli-0.3.1}/LICENSE +0 -0
- {folio_cli-0.3.0 → folio_cli-0.3.1}/setup.cfg +0 -0
- {folio_cli-0.3.0 → folio_cli-0.3.1}/src/folio/__main__.py +0 -0
- {folio_cli-0.3.0 → folio_cli-0.3.1}/src/folio/assets/SKILL.md +0 -0
- {folio_cli-0.3.0 → folio_cli-0.3.1}/src/folio/assets/__init__.py +0 -0
- {folio_cli-0.3.0 → folio_cli-0.3.1}/src/folio/assets/config.yaml +0 -0
- {folio_cli-0.3.0 → folio_cli-0.3.1}/src/folio/chunk.py +0 -0
- {folio_cli-0.3.0 → folio_cli-0.3.1}/src/folio/config.py +0 -0
- {folio_cli-0.3.0 → folio_cli-0.3.1}/src/folio/ingest.py +0 -0
- {folio_cli-0.3.0 → folio_cli-0.3.1}/src/folio/install.py +0 -0
- {folio_cli-0.3.0 → folio_cli-0.3.1}/src/folio/retrieve.py +0 -0
- {folio_cli-0.3.0 → folio_cli-0.3.1}/src/folio/sync.py +0 -0
- {folio_cli-0.3.0 → folio_cli-0.3.1}/src/folio_cli.egg-info/SOURCES.txt +0 -0
- {folio_cli-0.3.0 → folio_cli-0.3.1}/src/folio_cli.egg-info/dependency_links.txt +0 -0
- {folio_cli-0.3.0 → folio_cli-0.3.1}/src/folio_cli.egg-info/entry_points.txt +0 -0
- {folio_cli-0.3.0 → folio_cli-0.3.1}/src/folio_cli.egg-info/top_level.txt +0 -0
- {folio_cli-0.3.0 → folio_cli-0.3.1}/tests/test_chunk.py +0 -0
- {folio_cli-0.3.0 → folio_cli-0.3.1}/tests/test_cli.py +0 -0
- {folio_cli-0.3.0 → folio_cli-0.3.1}/tests/test_config.py +0 -0
- {folio_cli-0.3.0 → folio_cli-0.3.1}/tests/test_ingest_retrieve.py +0 -0
- {folio_cli-0.3.0 → folio_cli-0.3.1}/tests/test_install.py +0 -0
- {folio_cli-0.3.0 → folio_cli-0.3.1}/tests/test_rrf_and_format.py +0 -0
- {folio_cli-0.3.0 → folio_cli-0.3.1}/tests/test_sync.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: folio-cli
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: Local hybrid RAG over curated AI / MLOps / infra curricula — graphify-style CLI for any assistant
|
|
5
5
|
Author: Iman Sharei
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -29,8 +29,6 @@ Requires-Dist: sentence-transformers<6,>=3.3.0; extra == "rerank"
|
|
|
29
29
|
Provides-Extra: dev
|
|
30
30
|
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
31
31
|
Requires-Dist: pytest-cov>=5.0; extra == "dev"
|
|
32
|
-
Requires-Dist: build>=1.2; extra == "dev"
|
|
33
|
-
Requires-Dist: twine>=5.0; extra == "dev"
|
|
34
32
|
Dynamic: license-file
|
|
35
33
|
|
|
36
34
|
# folio
|
|
@@ -64,8 +62,10 @@ From a checkout (editable / unreleased):
|
|
|
64
62
|
|
|
65
63
|
```bash
|
|
66
64
|
cd ~/Desktop/folio
|
|
65
|
+
uv sync # creates .venv + uv.lock-backed env
|
|
66
|
+
uv run folio status
|
|
67
|
+
# or install the CLI globally from this tree:
|
|
67
68
|
uv tool install --editable .
|
|
68
|
-
# or: uv sync && uv run folio status
|
|
69
69
|
```
|
|
70
70
|
|
|
71
71
|
Git install without waiting for PyPI:
|
|
@@ -138,7 +138,7 @@ folio uninstall --project [--purge]
|
|
|
138
138
|
## Tests
|
|
139
139
|
|
|
140
140
|
```bash
|
|
141
|
-
uv sync
|
|
141
|
+
uv sync
|
|
142
142
|
uv run pytest -q # all
|
|
143
143
|
uv run pytest -q -m "not integration" # fast (no Chroma embed)
|
|
144
144
|
uv run pytest -q -m integration # sync + ingest + retrieve + pack
|
|
@@ -159,8 +159,8 @@ One-time setup (API token **or** Trusted Publishing):
|
|
|
159
159
|
After Trusted Publishing is configured, a version tag is enough:
|
|
160
160
|
|
|
161
161
|
```bash
|
|
162
|
-
git tag -a v0.3.
|
|
163
|
-
git push origin v0.3.
|
|
162
|
+
git tag -a v0.3.1 -m v0.3.1
|
|
163
|
+
git push origin v0.3.1
|
|
164
164
|
```
|
|
165
165
|
|
|
166
166
|
Manual local publish (token in env):
|
|
@@ -29,8 +29,10 @@ From a checkout (editable / unreleased):
|
|
|
29
29
|
|
|
30
30
|
```bash
|
|
31
31
|
cd ~/Desktop/folio
|
|
32
|
+
uv sync # creates .venv + uv.lock-backed env
|
|
33
|
+
uv run folio status
|
|
34
|
+
# or install the CLI globally from this tree:
|
|
32
35
|
uv tool install --editable .
|
|
33
|
-
# or: uv sync && uv run folio status
|
|
34
36
|
```
|
|
35
37
|
|
|
36
38
|
Git install without waiting for PyPI:
|
|
@@ -103,7 +105,7 @@ folio uninstall --project [--purge]
|
|
|
103
105
|
## Tests
|
|
104
106
|
|
|
105
107
|
```bash
|
|
106
|
-
uv sync
|
|
108
|
+
uv sync
|
|
107
109
|
uv run pytest -q # all
|
|
108
110
|
uv run pytest -q -m "not integration" # fast (no Chroma embed)
|
|
109
111
|
uv run pytest -q -m integration # sync + ingest + retrieve + pack
|
|
@@ -124,8 +126,8 @@ One-time setup (API token **or** Trusted Publishing):
|
|
|
124
126
|
After Trusted Publishing is configured, a version tag is enough:
|
|
125
127
|
|
|
126
128
|
```bash
|
|
127
|
-
git tag -a v0.3.
|
|
128
|
-
git push origin v0.3.
|
|
129
|
+
git tag -a v0.3.1 -m v0.3.1
|
|
130
|
+
git push origin v0.3.1
|
|
129
131
|
```
|
|
130
132
|
|
|
131
133
|
Manual local publish (token in env):
|
|
@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
|
|
|
6
6
|
# PyPI distribution name (plain "folio" is taken by an unrelated static-site tool).
|
|
7
7
|
# Import package + CLI command remain `folio`.
|
|
8
8
|
name = "folio-cli"
|
|
9
|
-
version = "0.3.
|
|
9
|
+
version = "0.3.1"
|
|
10
10
|
description = "Local hybrid RAG over curated AI / MLOps / infra curricula — graphify-style CLI for any assistant"
|
|
11
11
|
readme = "README.md"
|
|
12
12
|
license = "Apache-2.0"
|
|
@@ -30,9 +30,12 @@ dependencies = [
|
|
|
30
30
|
"numpy>=1.26.0,<3",
|
|
31
31
|
]
|
|
32
32
|
|
|
33
|
+
[dependency-groups]
|
|
34
|
+
dev = ["pytest>=8.0", "pytest-cov>=5.0"]
|
|
35
|
+
|
|
33
36
|
[project.optional-dependencies]
|
|
34
37
|
rerank = ["sentence-transformers>=3.3.0,<6"]
|
|
35
|
-
dev = ["pytest>=8.0", "pytest-cov>=5.0"
|
|
38
|
+
dev = ["pytest>=8.0", "pytest-cov>=5.0"]
|
|
36
39
|
|
|
37
40
|
[project.urls]
|
|
38
41
|
Homepage = "https://github.com/Iman-Sharei/folio"
|
|
@@ -49,6 +52,10 @@ where = ["src"]
|
|
|
49
52
|
[tool.setuptools.package-data]
|
|
50
53
|
folio = ["assets/*"]
|
|
51
54
|
|
|
55
|
+
[tool.uv]
|
|
56
|
+
package = true
|
|
57
|
+
default-groups = ["dev"]
|
|
58
|
+
|
|
52
59
|
[tool.pytest.ini_options]
|
|
53
60
|
testpaths = ["tests"]
|
|
54
61
|
markers = [
|
|
@@ -17,10 +17,14 @@ from .sync import sync_sources
|
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
def _cli_version() -> str:
|
|
20
|
+
# PyPI distribution is folio-cli; import package remains folio.
|
|
20
21
|
try:
|
|
21
|
-
return pkg_version("folio")
|
|
22
|
+
return pkg_version("folio-cli")
|
|
22
23
|
except PackageNotFoundError:
|
|
23
|
-
|
|
24
|
+
try:
|
|
25
|
+
return pkg_version("folio")
|
|
26
|
+
except PackageNotFoundError:
|
|
27
|
+
return __version__
|
|
24
28
|
|
|
25
29
|
|
|
26
30
|
def _cfg(args: argparse.Namespace) -> dict:
|
|
@@ -16,6 +16,7 @@ from .sync import sync_sources
|
|
|
16
16
|
|
|
17
17
|
# Files/dirs included in a portable index pack (query-ready without sources).
|
|
18
18
|
_PACK_MEMBERS = ("chroma", "bm25", "manifest.json", "config.yaml")
|
|
19
|
+
_PACK_TOP = frozenset(_PACK_MEMBERS)
|
|
19
20
|
|
|
20
21
|
|
|
21
22
|
def _release_url(cfg: dict[str, Any]) -> str:
|
|
@@ -23,6 +24,41 @@ def _release_url(cfg: dict[str, Any]) -> str:
|
|
|
23
24
|
return (release.get("index_url") or "").strip()
|
|
24
25
|
|
|
25
26
|
|
|
27
|
+
def _require_https_url(url: str) -> str:
|
|
28
|
+
"""Bootstrap downloads must be https (blocks file:// and SSRF-ish schemes)."""
|
|
29
|
+
from urllib.parse import urlparse
|
|
30
|
+
|
|
31
|
+
parsed = urlparse(url)
|
|
32
|
+
if parsed.scheme != "https" or not parsed.netloc:
|
|
33
|
+
raise RuntimeError(
|
|
34
|
+
f"Refusing non-https index URL (scheme={parsed.scheme!r}). "
|
|
35
|
+
"Use https://… or pass a local --archive path."
|
|
36
|
+
)
|
|
37
|
+
return url
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _safe_tar_members(tar: tarfile.TarFile) -> list[tarfile.TarInfo]:
|
|
41
|
+
"""Allowlist pack members; reject path traversal, absolute paths, and links."""
|
|
42
|
+
safe: list[tarfile.TarInfo] = []
|
|
43
|
+
for member in tar.getmembers():
|
|
44
|
+
name = member.name
|
|
45
|
+
if name.startswith("./"):
|
|
46
|
+
name = name[2:]
|
|
47
|
+
parts = Path(name).parts
|
|
48
|
+
if not parts or parts[0] not in _PACK_TOP:
|
|
49
|
+
continue
|
|
50
|
+
if Path(name).is_absolute() or ".." in parts:
|
|
51
|
+
raise RuntimeError(f"Unsafe tar member path: {member.name!r}")
|
|
52
|
+
if member.issym() or member.islnk():
|
|
53
|
+
raise RuntimeError(f"Tar symlinks/hardlinks are not allowed: {member.name!r}")
|
|
54
|
+
# Re-bind normalized relative name for extract.
|
|
55
|
+
member.name = name
|
|
56
|
+
safe.append(member)
|
|
57
|
+
if not safe:
|
|
58
|
+
raise RuntimeError("Invalid index pack: no allowed members found")
|
|
59
|
+
return safe
|
|
60
|
+
|
|
61
|
+
|
|
26
62
|
def pack_index(cfg: dict[str, Any], *, dest: Path | None = None) -> Path:
|
|
27
63
|
"""Create a tarball of the shared index for GitHub Release upload."""
|
|
28
64
|
out = Path(cfg["paths"]["out_dir"])
|
|
@@ -51,8 +87,12 @@ def pack_index(cfg: dict[str, Any], *, dest: Path | None = None) -> Path:
|
|
|
51
87
|
def _extract_pack(archive: Path, dest: Path) -> None:
|
|
52
88
|
dest.mkdir(parents=True, exist_ok=True)
|
|
53
89
|
with tarfile.open(archive, "r:gz") as tar:
|
|
54
|
-
|
|
55
|
-
|
|
90
|
+
members = _safe_tar_members(tar)
|
|
91
|
+
# Prefer PEP 706 data filter when available (3.12+).
|
|
92
|
+
extract_kw: dict[str, Any] = {"path": dest, "members": members}
|
|
93
|
+
if hasattr(tarfile, "data_filter"):
|
|
94
|
+
extract_kw["filter"] = "data"
|
|
95
|
+
tar.extractall(**extract_kw)
|
|
56
96
|
|
|
57
97
|
|
|
58
98
|
def bootstrap_index(
|
|
@@ -87,6 +127,8 @@ def bootstrap_index(
|
|
|
87
127
|
"pass --url, or run `folio build` / `folio update --from-source`."
|
|
88
128
|
)
|
|
89
129
|
|
|
130
|
+
resolved = _require_https_url(resolved)
|
|
131
|
+
|
|
90
132
|
with tempfile.TemporaryDirectory(prefix="folio-bootstrap-") as tmp:
|
|
91
133
|
tmp_path = Path(tmp) / "folio-index.tar.gz"
|
|
92
134
|
print(f"[bootstrap] downloading {resolved}")
|
|
@@ -115,10 +157,16 @@ def _extract_into_out(archive: Path, out: Path) -> None:
|
|
|
115
157
|
shutil.rmtree(dest)
|
|
116
158
|
else:
|
|
117
159
|
dest.unlink()
|
|
160
|
+
if src.is_symlink():
|
|
161
|
+
raise RuntimeError(f"Refusing symlink pack member: {src}")
|
|
118
162
|
if src.is_dir():
|
|
119
|
-
|
|
163
|
+
# symlinks=True copies link nodes as links (does not follow into secrets).
|
|
164
|
+
shutil.copytree(src, dest, symlinks=True, ignore_dangling_symlinks=False)
|
|
165
|
+
for p in dest.rglob("*"):
|
|
166
|
+
if p.is_symlink():
|
|
167
|
+
raise RuntimeError(f"Refusing symlink inside pack member {name}: {p}")
|
|
120
168
|
else:
|
|
121
|
-
shutil.copy2(src, dest)
|
|
169
|
+
shutil.copy2(src, dest, follow_symlinks=False)
|
|
122
170
|
|
|
123
171
|
|
|
124
172
|
def update_index(
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import json
|
|
3
4
|
import os
|
|
4
5
|
import pickle
|
|
5
6
|
import shutil
|
|
@@ -13,6 +14,27 @@ from rank_bm25 import BM25Okapi
|
|
|
13
14
|
|
|
14
15
|
from .chunk import Chunk
|
|
15
16
|
|
|
17
|
+
# Legacy pickle allowlist (BM25Okapi is pure-Python; block __reduce__ gadgets).
|
|
18
|
+
_PICKLE_ALLOWED = {
|
|
19
|
+
("builtins", "dict"),
|
|
20
|
+
("builtins", "list"),
|
|
21
|
+
("builtins", "tuple"),
|
|
22
|
+
("builtins", "str"),
|
|
23
|
+
("builtins", "int"),
|
|
24
|
+
("builtins", "float"),
|
|
25
|
+
("builtins", "bool"),
|
|
26
|
+
("builtins", "set"),
|
|
27
|
+
("builtins", "frozenset"),
|
|
28
|
+
("rank_bm25", "BM25Okapi"),
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class _RestrictedBm25Unpickler(pickle.Unpickler):
|
|
33
|
+
def find_class(self, module: str, name: str) -> Any:
|
|
34
|
+
if (module, name) not in _PICKLE_ALLOWED:
|
|
35
|
+
raise pickle.UnpicklingError(f"Refusing to unpickle {module}.{name}")
|
|
36
|
+
return super().find_class(module, name)
|
|
37
|
+
|
|
16
38
|
|
|
17
39
|
def _ensure_local_chroma_cache(model_cache_dir: Path | None = None) -> Path:
|
|
18
40
|
"""Keep ONNX model cache under the folio index home (sandbox-friendly).
|
|
@@ -103,18 +125,47 @@ def build_bm25(chunks: list[Chunk]) -> tuple[BM25Okapi, list[str], list[Chunk]]:
|
|
|
103
125
|
return BM25Okapi(tokenized), [c.chunk_id for c in chunks], chunks
|
|
104
126
|
|
|
105
127
|
|
|
128
|
+
def _bm25_json_path(path: Path) -> Path:
|
|
129
|
+
"""Prefer index.json alongside (or instead of) legacy index.pkl."""
|
|
130
|
+
if path.suffix == ".json":
|
|
131
|
+
return path
|
|
132
|
+
return path.with_suffix(".json")
|
|
133
|
+
|
|
134
|
+
|
|
106
135
|
def save_bm25(path: Path, bm25: BM25Okapi, ids: list[str], chunks: list[Chunk]) -> None:
|
|
136
|
+
"""Persist BM25 corpus as JSON and rebuild the index on load (no pickle)."""
|
|
137
|
+
del bm25 # rebuilt from texts on load
|
|
107
138
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
139
|
+
json_path = _bm25_json_path(path)
|
|
108
140
|
payload = {
|
|
109
|
-
"bm25": bm25,
|
|
110
141
|
"ids": ids,
|
|
111
142
|
"texts": [c.text for c in chunks],
|
|
112
143
|
"metadatas": [c.to_metadata() for c in chunks],
|
|
113
144
|
}
|
|
114
|
-
|
|
115
|
-
|
|
145
|
+
json_path.write_text(json.dumps(payload, ensure_ascii=False), encoding="utf-8")
|
|
146
|
+
# Remove legacy pickle so packs don't ship an RCE surface.
|
|
147
|
+
if path.suffix == ".pkl" and path.exists():
|
|
148
|
+
path.unlink()
|
|
116
149
|
|
|
117
150
|
|
|
118
151
|
def load_bm25(path: Path) -> dict[str, Any]:
|
|
152
|
+
json_path = _bm25_json_path(path)
|
|
153
|
+
|
|
154
|
+
if json_path.exists():
|
|
155
|
+
data = json.loads(json_path.read_text(encoding="utf-8"))
|
|
156
|
+
texts: list[str] = data["texts"]
|
|
157
|
+
ids: list[str] = data["ids"]
|
|
158
|
+
metas: list[dict] = data["metadatas"]
|
|
159
|
+
tokenized = [t.lower().split() for t in texts]
|
|
160
|
+
bm25 = BM25Okapi(tokenized) if tokenized else BM25Okapi([["_"]])
|
|
161
|
+
return {"bm25": bm25, "ids": ids, "texts": texts, "metadatas": metas}
|
|
162
|
+
|
|
163
|
+
if not path.exists():
|
|
164
|
+
raise FileNotFoundError(path)
|
|
165
|
+
|
|
166
|
+
# Legacy pickle path: restricted unpickler only (blocks RCE gadgets).
|
|
119
167
|
with path.open("rb") as f:
|
|
120
|
-
|
|
168
|
+
payload = _RestrictedBm25Unpickler(f).load()
|
|
169
|
+
if not isinstance(payload, dict) or "bm25" not in payload:
|
|
170
|
+
raise RuntimeError(f"Invalid legacy BM25 pickle at {path}")
|
|
171
|
+
return payload
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: folio-cli
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: Local hybrid RAG over curated AI / MLOps / infra curricula — graphify-style CLI for any assistant
|
|
5
5
|
Author: Iman Sharei
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -29,8 +29,6 @@ Requires-Dist: sentence-transformers<6,>=3.3.0; extra == "rerank"
|
|
|
29
29
|
Provides-Extra: dev
|
|
30
30
|
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
31
31
|
Requires-Dist: pytest-cov>=5.0; extra == "dev"
|
|
32
|
-
Requires-Dist: build>=1.2; extra == "dev"
|
|
33
|
-
Requires-Dist: twine>=5.0; extra == "dev"
|
|
34
32
|
Dynamic: license-file
|
|
35
33
|
|
|
36
34
|
# folio
|
|
@@ -64,8 +62,10 @@ From a checkout (editable / unreleased):
|
|
|
64
62
|
|
|
65
63
|
```bash
|
|
66
64
|
cd ~/Desktop/folio
|
|
65
|
+
uv sync # creates .venv + uv.lock-backed env
|
|
66
|
+
uv run folio status
|
|
67
|
+
# or install the CLI globally from this tree:
|
|
67
68
|
uv tool install --editable .
|
|
68
|
-
# or: uv sync && uv run folio status
|
|
69
69
|
```
|
|
70
70
|
|
|
71
71
|
Git install without waiting for PyPI:
|
|
@@ -138,7 +138,7 @@ folio uninstall --project [--purge]
|
|
|
138
138
|
## Tests
|
|
139
139
|
|
|
140
140
|
```bash
|
|
141
|
-
uv sync
|
|
141
|
+
uv sync
|
|
142
142
|
uv run pytest -q # all
|
|
143
143
|
uv run pytest -q -m "not integration" # fast (no Chroma embed)
|
|
144
144
|
uv run pytest -q -m integration # sync + ingest + retrieve + pack
|
|
@@ -159,8 +159,8 @@ One-time setup (API token **or** Trusted Publishing):
|
|
|
159
159
|
After Trusted Publishing is configured, a version tag is enough:
|
|
160
160
|
|
|
161
161
|
```bash
|
|
162
|
-
git tag -a v0.3.
|
|
163
|
-
git push origin v0.3.
|
|
162
|
+
git tag -a v0.3.1 -m v0.3.1
|
|
163
|
+
git push origin v0.3.1
|
|
164
164
|
```
|
|
165
165
|
|
|
166
166
|
Manual local publish (token in env):
|
|
@@ -44,7 +44,7 @@ def test_pack_and_bootstrap_roundtrip(
|
|
|
44
44
|
|
|
45
45
|
assert (other / "manifest.json").exists()
|
|
46
46
|
assert (other / "chroma").exists()
|
|
47
|
-
assert (other / "bm25" / "index.pkl").exists()
|
|
47
|
+
assert (other / "bm25" / "index.json").exists() or (other / "bm25" / "index.pkl").exists()
|
|
48
48
|
assert (other / "config.yaml").exists()
|
|
49
49
|
|
|
50
50
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|