sessionmemory 0.4.1__tar.gz → 0.5.0__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.
- {sessionmemory-0.4.1 → sessionmemory-0.5.0}/PKG-INFO +8 -6
- {sessionmemory-0.4.1 → sessionmemory-0.5.0}/README.md +7 -5
- {sessionmemory-0.4.1 → sessionmemory-0.5.0}/pyproject.toml +1 -1
- {sessionmemory-0.4.1 → sessionmemory-0.5.0}/pyproject.toml.orig +1 -1
- {sessionmemory-0.4.1 → sessionmemory-0.5.0}/src/sessionmemory/cli.py +1 -1
- sessionmemory-0.5.0/src/sessionmemory/commands/reindex.py +67 -0
- {sessionmemory-0.4.1 → sessionmemory-0.5.0}/src/sessionmemory/lib/doctor.py +5 -14
- {sessionmemory-0.4.1 → sessionmemory-0.5.0}/src/sessionmemory/lib/inject.py +21 -12
- {sessionmemory-0.4.1 → sessionmemory-0.5.0}/src/sessionmemory/lib/paths.py +10 -0
- sessionmemory-0.4.1/src/sessionmemory/commands/reindex.py +0 -46
- {sessionmemory-0.4.1 → sessionmemory-0.5.0}/src/sessionmemory/__init__.py +0 -0
- {sessionmemory-0.4.1 → sessionmemory-0.5.0}/src/sessionmemory/commands/__init__.py +0 -0
- {sessionmemory-0.4.1 → sessionmemory-0.5.0}/src/sessionmemory/commands/_common.py +0 -0
- {sessionmemory-0.4.1 → sessionmemory-0.5.0}/src/sessionmemory/commands/delete.py +0 -0
- {sessionmemory-0.4.1 → sessionmemory-0.5.0}/src/sessionmemory/commands/doctor.py +0 -0
- {sessionmemory-0.4.1 → sessionmemory-0.5.0}/src/sessionmemory/commands/export.py +0 -0
- {sessionmemory-0.4.1 → sessionmemory-0.5.0}/src/sessionmemory/commands/init.py +0 -0
- {sessionmemory-0.4.1 → sessionmemory-0.5.0}/src/sessionmemory/commands/inject.py +0 -0
- {sessionmemory-0.4.1 → sessionmemory-0.5.0}/src/sessionmemory/commands/log.py +0 -0
- {sessionmemory-0.4.1 → sessionmemory-0.5.0}/src/sessionmemory/commands/new.py +0 -0
- {sessionmemory-0.4.1 → sessionmemory-0.5.0}/src/sessionmemory/commands/project.py +0 -0
- {sessionmemory-0.4.1 → sessionmemory-0.5.0}/src/sessionmemory/commands/search.py +0 -0
- {sessionmemory-0.4.1 → sessionmemory-0.5.0}/src/sessionmemory/lib/__init__.py +0 -0
- {sessionmemory-0.4.1 → sessionmemory-0.5.0}/src/sessionmemory/lib/atomic.py +0 -0
- {sessionmemory-0.4.1 → sessionmemory-0.5.0}/src/sessionmemory/lib/backlog.py +0 -0
- {sessionmemory-0.4.1 → sessionmemory-0.5.0}/src/sessionmemory/lib/bootstrap.py +0 -0
- {sessionmemory-0.4.1 → sessionmemory-0.5.0}/src/sessionmemory/lib/config.py +0 -0
- {sessionmemory-0.4.1 → sessionmemory-0.5.0}/src/sessionmemory/lib/embed.py +0 -0
- {sessionmemory-0.4.1 → sessionmemory-0.5.0}/src/sessionmemory/lib/export.py +0 -0
- {sessionmemory-0.4.1 → sessionmemory-0.5.0}/src/sessionmemory/lib/field.py +0 -0
- {sessionmemory-0.4.1 → sessionmemory-0.5.0}/src/sessionmemory/lib/fieldindex.py +0 -0
- {sessionmemory-0.4.1 → sessionmemory-0.5.0}/src/sessionmemory/lib/frontmatter.py +0 -0
- {sessionmemory-0.4.1 → sessionmemory-0.5.0}/src/sessionmemory/lib/gitinfo.py +0 -0
- {sessionmemory-0.4.1 → sessionmemory-0.5.0}/src/sessionmemory/lib/ids.py +0 -0
- {sessionmemory-0.4.1 → sessionmemory-0.5.0}/src/sessionmemory/lib/log.py +0 -0
- {sessionmemory-0.4.1 → sessionmemory-0.5.0}/src/sessionmemory/lib/registry.py +0 -0
- {sessionmemory-0.4.1 → sessionmemory-0.5.0}/src/sessionmemory/lib/resolve.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: sessionmemory
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: Durable memory for coding agents, one folder of searchable pages per project.
|
|
5
5
|
Author: Nathaniel Landau
|
|
6
6
|
Author-email: Nathaniel Landau <github@natelandau.com>
|
|
@@ -205,7 +205,7 @@ project holding four learnings, one spec, one plan, and two open backlog items:
|
|
|
205
205
|
Durable memory for this project lives in a vault of markdown pages. Nothing below is
|
|
206
206
|
loaded for you: the titles are what the vault holds, and each is one `sessionmemory search`
|
|
207
207
|
away. The project's folder has `learnings/` and `logs/`, searched by meaning, beside
|
|
208
|
-
`specs
|
|
208
|
+
`specs/` and `backlog.md`, which are ordinary files you Read and Edit.
|
|
209
209
|
`sessionmemory project --json` prints every path.
|
|
210
210
|
|
|
211
211
|
- Before assuming nothing was written down, search: `sessionmemory search "<words>"`
|
|
@@ -220,8 +220,11 @@ away. The project's folder has `learnings/` and `logs/`, searched by meaning, be
|
|
|
220
220
|
which creates the file or heading when missing. Delete a finished line, and one
|
|
221
221
|
that will never be done, directly; never tick or annotate it. Git history is the
|
|
222
222
|
record of what was finished.
|
|
223
|
-
- Specs
|
|
224
|
-
and
|
|
223
|
+
- Specs: `specs/` holds one design record per feature, named `<date>-<topic>.md`
|
|
224
|
+
and kept after the work ships. Before designing or changing a feature, list the
|
|
225
|
+
directory and read any spec whose name matches, so a decision already made is not
|
|
226
|
+
made again. `sessionmemory new spec --title "..." --cwd .` creates one and prints its
|
|
227
|
+
path. Edit it directly after that.
|
|
225
228
|
- Learnings are captured at session end, not by you mid-session. When the user asks
|
|
226
229
|
to keep one now: `sessionmemory new learning --title "..." --summary "..." --cwd .`
|
|
227
230
|
creates the page and prints the path to write prose into. Title and summary state
|
|
@@ -237,8 +240,7 @@ away. The project's folder has `learnings/` and `logs/`, searched by meaning, be
|
|
|
237
240
|
## Open work
|
|
238
241
|
|
|
239
242
|
2 open backlog items
|
|
240
|
-
spec
|
|
241
|
-
plan: Move PDF rendering to a worker queue
|
|
243
|
+
1 spec in specs/
|
|
242
244
|
```
|
|
243
245
|
|
|
244
246
|
A page body never enters that block, so its cost grows with the number of pages and not
|
|
@@ -190,7 +190,7 @@ project holding four learnings, one spec, one plan, and two open backlog items:
|
|
|
190
190
|
Durable memory for this project lives in a vault of markdown pages. Nothing below is
|
|
191
191
|
loaded for you: the titles are what the vault holds, and each is one `sessionmemory search`
|
|
192
192
|
away. The project's folder has `learnings/` and `logs/`, searched by meaning, beside
|
|
193
|
-
`specs
|
|
193
|
+
`specs/` and `backlog.md`, which are ordinary files you Read and Edit.
|
|
194
194
|
`sessionmemory project --json` prints every path.
|
|
195
195
|
|
|
196
196
|
- Before assuming nothing was written down, search: `sessionmemory search "<words>"`
|
|
@@ -205,8 +205,11 @@ away. The project's folder has `learnings/` and `logs/`, searched by meaning, be
|
|
|
205
205
|
which creates the file or heading when missing. Delete a finished line, and one
|
|
206
206
|
that will never be done, directly; never tick or annotate it. Git history is the
|
|
207
207
|
record of what was finished.
|
|
208
|
-
- Specs
|
|
209
|
-
and
|
|
208
|
+
- Specs: `specs/` holds one design record per feature, named `<date>-<topic>.md`
|
|
209
|
+
and kept after the work ships. Before designing or changing a feature, list the
|
|
210
|
+
directory and read any spec whose name matches, so a decision already made is not
|
|
211
|
+
made again. `sessionmemory new spec --title "..." --cwd .` creates one and prints its
|
|
212
|
+
path. Edit it directly after that.
|
|
210
213
|
- Learnings are captured at session end, not by you mid-session. When the user asks
|
|
211
214
|
to keep one now: `sessionmemory new learning --title "..." --summary "..." --cwd .`
|
|
212
215
|
creates the page and prints the path to write prose into. Title and summary state
|
|
@@ -222,8 +225,7 @@ away. The project's folder has `learnings/` and `logs/`, searched by meaning, be
|
|
|
222
225
|
## Open work
|
|
223
226
|
|
|
224
227
|
2 open backlog items
|
|
225
|
-
spec
|
|
226
|
-
plan: Move PDF rendering to a worker queue
|
|
228
|
+
1 spec in specs/
|
|
227
229
|
```
|
|
228
230
|
|
|
229
231
|
A page body never enters that block, so its cost grows with the number of pages and not
|
|
@@ -11,7 +11,7 @@ description = "Durable memory for coding agents, one folder of searchable pages
|
|
|
11
11
|
name = "sessionmemory"
|
|
12
12
|
readme = "README.md"
|
|
13
13
|
requires-python = ">=3.13,<3.15"
|
|
14
|
-
version = "0.
|
|
14
|
+
version = "0.5.0"
|
|
15
15
|
|
|
16
16
|
[[project.authors]]
|
|
17
17
|
name = "Nathaniel Landau"
|
|
@@ -65,7 +65,7 @@ app.command("log", help="Record this session's work in one upserted page.")(
|
|
|
65
65
|
app.command("project", help="Report this directory's project, or register it.")(
|
|
66
66
|
project.project_command
|
|
67
67
|
)
|
|
68
|
-
app.command("reindex", help="Rebuild this project's search indexes.")(
|
|
68
|
+
app.command("reindex", help="Rebuild this project's search indexes, or every project's.")(
|
|
69
69
|
reindex_commands.reindex_command
|
|
70
70
|
)
|
|
71
71
|
app.command("search", help="Search this project's learnings by meaning, or its logs with --logs.")(
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""The `reindex` command: rebuild a project's field indexes from its pages."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import asdict
|
|
6
|
+
from pathlib import Path # noqa: TC003
|
|
7
|
+
|
|
8
|
+
import typer
|
|
9
|
+
from nclutils import pp
|
|
10
|
+
|
|
11
|
+
from sessionmemory.commands._common import (
|
|
12
|
+
build_embedder,
|
|
13
|
+
emit_json,
|
|
14
|
+
fail,
|
|
15
|
+
require_project,
|
|
16
|
+
require_vault,
|
|
17
|
+
)
|
|
18
|
+
from sessionmemory.lib import fieldindex, paths
|
|
19
|
+
|
|
20
|
+
CWD = typer.Option(None, "--cwd", help="Directory to resolve the project from.")
|
|
21
|
+
ALL = typer.Option(False, "--all", help="Reindex every project in the vault.") # noqa: FBT003
|
|
22
|
+
JSON = typer.Option(False, "--json", help="Emit JSON instead of prose.") # noqa: FBT003
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def reindex_command(
|
|
26
|
+
cwd: Path | None = CWD, *, all_projects: bool = ALL, as_json: bool = JSON
|
|
27
|
+
) -> None:
|
|
28
|
+
"""Bring this project's learnings and logs indexes up to date, or every project's.
|
|
29
|
+
|
|
30
|
+
Raises:
|
|
31
|
+
Exit: When `--all` is combined with `--cwd`.
|
|
32
|
+
"""
|
|
33
|
+
vault = require_vault()
|
|
34
|
+
if all_projects:
|
|
35
|
+
if cwd is not None:
|
|
36
|
+
fail("--all and --cwd are mutually exclusive", ["pass one or the other"])
|
|
37
|
+
fields = [
|
|
38
|
+
(directory.parent.name, directory.name, directory)
|
|
39
|
+
for directory in paths.iter_field_dirs(vault)
|
|
40
|
+
]
|
|
41
|
+
else:
|
|
42
|
+
slug = require_project(vault, cwd)
|
|
43
|
+
fields = [
|
|
44
|
+
(slug, paths.LEARNINGS_DIR, paths.learnings_dir(vault, slug)),
|
|
45
|
+
(slug, paths.LOGS_DIR, paths.logs_dir(vault, slug)),
|
|
46
|
+
]
|
|
47
|
+
embedder = build_embedder()
|
|
48
|
+
|
|
49
|
+
if as_json:
|
|
50
|
+
payload: dict[str, dict] = {}
|
|
51
|
+
for slug, name, directory in fields:
|
|
52
|
+
counts = asdict(fieldindex.refresh(directory, embedder))
|
|
53
|
+
if all_projects:
|
|
54
|
+
payload.setdefault(slug, {})[name] = counts
|
|
55
|
+
else:
|
|
56
|
+
payload[name] = counts
|
|
57
|
+
emit_json(payload)
|
|
58
|
+
return
|
|
59
|
+
|
|
60
|
+
with pp.step("reindexing") as step:
|
|
61
|
+
for slug, name, directory in fields:
|
|
62
|
+
result = fieldindex.refresh(directory, embedder)
|
|
63
|
+
label = f"{slug}/{name}" if all_projects else name
|
|
64
|
+
step.sub(
|
|
65
|
+
f"{label}: {result.added} added, {result.updated} updated, "
|
|
66
|
+
f"{result.removed} removed, {result.unchanged} unchanged"
|
|
67
|
+
)
|
|
@@ -36,20 +36,11 @@ class Finding:
|
|
|
36
36
|
message: str
|
|
37
37
|
|
|
38
38
|
|
|
39
|
-
def _fields(vault: Path) -> list[Path]:
|
|
40
|
-
return [
|
|
41
|
-
paths.project_dir(vault, slug) / name
|
|
42
|
-
for slug in paths.iter_project_slugs(vault)
|
|
43
|
-
for name in paths.FIELD_DIRS
|
|
44
|
-
if (paths.project_dir(vault, slug) / name).is_dir()
|
|
45
|
-
]
|
|
46
|
-
|
|
47
|
-
|
|
48
39
|
def nonconformant_names(vault: Path, _embedder: Embedder) -> list[Finding]:
|
|
49
40
|
"""Report a markdown file in a field whose name breaks the spec's filename rule."""
|
|
50
41
|
return [
|
|
51
42
|
Finding("filename", str(path), "not lowercase ascii letters, digits, and hyphens")
|
|
52
|
-
for directory in
|
|
43
|
+
for directory in paths.iter_field_dirs(vault)
|
|
53
44
|
for path in sorted(directory.glob("*.md"))
|
|
54
45
|
if path.is_file() and not field.is_debris(path.name) and not field.is_page_name(path.name)
|
|
55
46
|
]
|
|
@@ -63,7 +54,7 @@ def oversized_pages(vault: Path, _embedder: Embedder) -> list[Finding]:
|
|
|
63
54
|
str(path),
|
|
64
55
|
f"{path.stat().st_size} bytes; split it, the limit is {field.PAGE_LIMIT}",
|
|
65
56
|
)
|
|
66
|
-
for directory in
|
|
57
|
+
for directory in paths.iter_field_dirs(vault)
|
|
67
58
|
for path in field.iter_pages(directory)
|
|
68
59
|
if path.stat().st_size > field.PAGE_LIMIT
|
|
69
60
|
]
|
|
@@ -82,7 +73,7 @@ def malformed_frontmatter(vault: Path, _embedder: Embedder) -> list[Finding]:
|
|
|
82
73
|
when it has no block at all.
|
|
83
74
|
"""
|
|
84
75
|
findings = []
|
|
85
|
-
for directory in
|
|
76
|
+
for directory in paths.iter_field_dirs(vault):
|
|
86
77
|
for path in field.iter_pages(directory):
|
|
87
78
|
raw = path.read_bytes()
|
|
88
79
|
try:
|
|
@@ -114,7 +105,7 @@ def unquoted_datetimes(vault: Path, _embedder: Embedder) -> list[Finding]:
|
|
|
114
105
|
block that cannot be parsed at all is left to the frontmatter check.
|
|
115
106
|
"""
|
|
116
107
|
findings = []
|
|
117
|
-
for directory in
|
|
108
|
+
for directory in paths.iter_field_dirs(vault):
|
|
118
109
|
for path in field.iter_pages(directory):
|
|
119
110
|
try:
|
|
120
111
|
keys = unquoted_datetime_keys(path.read_text(encoding="utf-8"))
|
|
@@ -191,7 +182,7 @@ def _is_stale(directory: Path, embedder: Embedder) -> str | None:
|
|
|
191
182
|
def stale_indexes(vault: Path, embedder: Embedder) -> list[Finding]:
|
|
192
183
|
"""Report a field whose index file is unreadable or behind its pages."""
|
|
193
184
|
findings = []
|
|
194
|
-
for directory in
|
|
185
|
+
for directory in paths.iter_field_dirs(vault):
|
|
195
186
|
message = _is_stale(directory, embedder)
|
|
196
187
|
if message:
|
|
197
188
|
findings.append(Finding("index", str(directory), message))
|
|
@@ -25,8 +25,7 @@ class Injection:
|
|
|
25
25
|
project: str
|
|
26
26
|
titles: tuple[str, ...]
|
|
27
27
|
open_backlog: int
|
|
28
|
-
specs:
|
|
29
|
-
plans: tuple[str, ...]
|
|
28
|
+
specs: int
|
|
30
29
|
|
|
31
30
|
|
|
32
31
|
def _sort_key(title: str) -> str:
|
|
@@ -45,14 +44,22 @@ def _open_backlog(path: Path) -> int:
|
|
|
45
44
|
return sum(1 for line in path.read_text(encoding="utf-8").splitlines() if backlog.is_item(line))
|
|
46
45
|
|
|
47
46
|
|
|
47
|
+
def _spec_count(directory: Path) -> int:
|
|
48
|
+
return sum(1 for _ in field.iter_pages(directory))
|
|
49
|
+
|
|
50
|
+
|
|
48
51
|
def build(vault: Path, slug: str) -> Injection:
|
|
49
|
-
"""Read the project's pages and files; the index is never consulted here.
|
|
52
|
+
"""Read the project's pages and files; the index is never consulted here.
|
|
53
|
+
|
|
54
|
+
Specs are counted rather than listed. A spec outlives the work it describes, so a
|
|
55
|
+
list of them is a changelog rather than open work, and it grows without bound. The
|
|
56
|
+
count says whether listing `specs/` is worth a call, which is all a session needs.
|
|
57
|
+
"""
|
|
50
58
|
return Injection(
|
|
51
59
|
project=slug,
|
|
52
60
|
titles=_titles(paths.learnings_dir(vault, slug)),
|
|
53
61
|
open_backlog=_open_backlog(paths.backlog_path(vault, slug)),
|
|
54
|
-
specs=
|
|
55
|
-
plans=_titles(paths.plans_dir(vault, slug)),
|
|
62
|
+
specs=_spec_count(paths.specs_dir(vault, slug)),
|
|
56
63
|
)
|
|
57
64
|
|
|
58
65
|
|
|
@@ -61,7 +68,7 @@ GUIDANCE = """## Using this vault
|
|
|
61
68
|
Durable memory for this project lives in a vault of markdown pages. Nothing below is
|
|
62
69
|
loaded for you: the titles are what the vault holds, and each is one `{command} search`
|
|
63
70
|
away. The project's folder has `learnings/` and `logs/`, searched by meaning, beside
|
|
64
|
-
`specs
|
|
71
|
+
`specs/` and `backlog.md`, which are ordinary files you Read and Edit.
|
|
65
72
|
`{command} project --json` prints every path.
|
|
66
73
|
|
|
67
74
|
- Before assuming nothing was written down, search: `{command} search "<words>"`
|
|
@@ -76,8 +83,11 @@ away. The project's folder has `learnings/` and `logs/`, searched by meaning, be
|
|
|
76
83
|
which creates the file or heading when missing. Delete a finished line, and one
|
|
77
84
|
that will never be done, directly; never tick or annotate it. Git history is the
|
|
78
85
|
record of what was finished.
|
|
79
|
-
- Specs
|
|
80
|
-
and
|
|
86
|
+
- Specs: `specs/` holds one design record per feature, named `<date>-<topic>.md`
|
|
87
|
+
and kept after the work ships. Before designing or changing a feature, list the
|
|
88
|
+
directory and read any spec whose name matches, so a decision already made is not
|
|
89
|
+
made again. `{command} new spec --title "..." --cwd .` creates one and prints its
|
|
90
|
+
path. Edit it directly after that.
|
|
81
91
|
- Learnings are captured at session end, not by you mid-session. When the user asks
|
|
82
92
|
to keep one now: `{command} new learning --title "..." --summary "..." --cwd .`
|
|
83
93
|
creates the page and prints the path to write prose into. Title and summary state
|
|
@@ -93,8 +103,8 @@ def render(injection: Injection, *, command: str = "sessionmemory") -> str:
|
|
|
93
103
|
lines.extend(["", "## Open work", ""])
|
|
94
104
|
item = "item" if injection.open_backlog == 1 else "items"
|
|
95
105
|
lines.append(f" {injection.open_backlog} open backlog {item}")
|
|
96
|
-
|
|
97
|
-
lines.
|
|
106
|
+
spec = "spec" if injection.specs == 1 else "specs"
|
|
107
|
+
lines.append(f" {injection.specs} {spec} in specs/")
|
|
98
108
|
return "\n".join(lines)
|
|
99
109
|
|
|
100
110
|
|
|
@@ -105,6 +115,5 @@ def payload(injection: Injection, *, command: str) -> dict[str, object]:
|
|
|
105
115
|
"project": injection.project,
|
|
106
116
|
"titles": list(injection.titles),
|
|
107
117
|
"open_backlog": injection.open_backlog,
|
|
108
|
-
"specs":
|
|
109
|
-
"plans": list(injection.plans),
|
|
118
|
+
"specs": injection.specs,
|
|
110
119
|
}
|
|
@@ -75,3 +75,13 @@ def iter_project_slugs(vault: Path) -> list[str]:
|
|
|
75
75
|
if not root.is_dir():
|
|
76
76
|
return []
|
|
77
77
|
return sorted(entry.name for entry in root.iterdir() if entry.is_dir())
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def iter_field_dirs(vault: Path) -> list[Path]:
|
|
81
|
+
"""Return every existing field directory in the vault, sorted by project then field."""
|
|
82
|
+
return [
|
|
83
|
+
project_dir(vault, slug) / name
|
|
84
|
+
for slug in iter_project_slugs(vault)
|
|
85
|
+
for name in FIELD_DIRS
|
|
86
|
+
if (project_dir(vault, slug) / name).is_dir()
|
|
87
|
+
]
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
"""The `reindex` command: rebuild a project's field indexes from its pages."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
from dataclasses import asdict
|
|
6
|
-
from pathlib import Path # noqa: TC003
|
|
7
|
-
|
|
8
|
-
import typer
|
|
9
|
-
from nclutils import pp
|
|
10
|
-
|
|
11
|
-
from sessionmemory.commands._common import (
|
|
12
|
-
build_embedder,
|
|
13
|
-
emit_json,
|
|
14
|
-
require_project,
|
|
15
|
-
require_vault,
|
|
16
|
-
)
|
|
17
|
-
from sessionmemory.lib import fieldindex, paths
|
|
18
|
-
|
|
19
|
-
CWD = typer.Option(None, "--cwd", help="Directory to resolve the project from.")
|
|
20
|
-
JSON = typer.Option(False, "--json", help="Emit JSON instead of prose.") # noqa: FBT003
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
def reindex_command(cwd: Path | None = CWD, *, as_json: bool = JSON) -> None:
|
|
24
|
-
"""Bring this project's learnings and logs indexes up to date."""
|
|
25
|
-
vault = require_vault()
|
|
26
|
-
slug = require_project(vault, cwd)
|
|
27
|
-
embedder = build_embedder()
|
|
28
|
-
fields = {
|
|
29
|
-
"learnings": paths.learnings_dir(vault, slug),
|
|
30
|
-
"logs": paths.logs_dir(vault, slug),
|
|
31
|
-
}
|
|
32
|
-
if as_json:
|
|
33
|
-
emit_json(
|
|
34
|
-
{
|
|
35
|
-
name: asdict(fieldindex.refresh(directory, embedder))
|
|
36
|
-
for name, directory in fields.items()
|
|
37
|
-
}
|
|
38
|
-
)
|
|
39
|
-
return
|
|
40
|
-
with pp.step("reindexing") as step:
|
|
41
|
-
for name, directory in fields.items():
|
|
42
|
-
result = fieldindex.refresh(directory, embedder)
|
|
43
|
-
step.sub(
|
|
44
|
-
f"{name}: {result.added} added, {result.updated} updated, "
|
|
45
|
-
f"{result.removed} removed, {result.unchanged} unchanged"
|
|
46
|
-
)
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|