chronicle-dev 0.1.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.
@@ -0,0 +1,6 @@
1
+ node_modules/
2
+ dist/
3
+ *.tsbuildinfo
4
+ .env
5
+ .lore/.extraction-cache.json
6
+ .lore/capture.log
@@ -0,0 +1,62 @@
1
+ Metadata-Version: 2.4
2
+ Name: chronicle-dev
3
+ Version: 0.1.0
4
+ Summary: AI-native development memory — markdown RAG for every AI coding tool
5
+ Project-URL: Homepage, https://github.com/ypollak2/chronicle
6
+ Project-URL: Repository, https://github.com/ypollak2/chronicle
7
+ Project-URL: Issues, https://github.com/ypollak2/chronicle/issues
8
+ License: MIT
9
+ Keywords: ai,claude,codex,cursor,developer-tools,llm,rag
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Environment :: Console
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
16
+ Requires-Python: >=3.9
17
+ Provides-Extra: dev
18
+ Requires-Dist: pytest>=7.0; extra == 'dev'
19
+ Description-Content-Type: text/markdown
20
+
21
+ # chronicle-dev (Python)
22
+
23
+ > AI-native development memory — markdown RAG for every AI coding tool
24
+
25
+ This is the Python wrapper for [Chronicle](https://github.com/ypollak2/chronicle).
26
+ It delegates all work to the Node.js CLI (`chronicle-dev` on npm).
27
+
28
+ ## Requirements
29
+
30
+ - Python ≥ 3.9
31
+ - Node.js ≥ 20 ([install](https://nodejs.org))
32
+
33
+ ## Install
34
+
35
+ ```bash
36
+ pip install chronicle-dev
37
+ ```
38
+
39
+ ## Usage
40
+
41
+ Identical to the npm version:
42
+
43
+ ```bash
44
+ chronicle init # scan last 6 months of git history
45
+ chronicle inject | claude # pipe context into Claude
46
+ chronicle inject | codex # or Codex, Gemini CLI, Aider...
47
+ chronicle hooks install # passive capture on every commit
48
+ chronicle deepen --depth=1year # scan further back
49
+ ```
50
+
51
+ ## How it works
52
+
53
+ `pip install chronicle-dev` installs a `chronicle` entry point that:
54
+ 1. Checks Node ≥ 20 is available
55
+ 2. Delegates to `chronicle` (if globally installed) or `npx chronicle-dev`
56
+
57
+ The Node package is the source of truth. This wrapper exists so Python developers
58
+ can install Chronicle without switching to npm.
59
+
60
+ ## Full docs
61
+
62
+ See [github.com/ypollak2/chronicle](https://github.com/ypollak2/chronicle)
@@ -0,0 +1,42 @@
1
+ # chronicle-dev (Python)
2
+
3
+ > AI-native development memory — markdown RAG for every AI coding tool
4
+
5
+ This is the Python wrapper for [Chronicle](https://github.com/ypollak2/chronicle).
6
+ It delegates all work to the Node.js CLI (`chronicle-dev` on npm).
7
+
8
+ ## Requirements
9
+
10
+ - Python ≥ 3.9
11
+ - Node.js ≥ 20 ([install](https://nodejs.org))
12
+
13
+ ## Install
14
+
15
+ ```bash
16
+ pip install chronicle-dev
17
+ ```
18
+
19
+ ## Usage
20
+
21
+ Identical to the npm version:
22
+
23
+ ```bash
24
+ chronicle init # scan last 6 months of git history
25
+ chronicle inject | claude # pipe context into Claude
26
+ chronicle inject | codex # or Codex, Gemini CLI, Aider...
27
+ chronicle hooks install # passive capture on every commit
28
+ chronicle deepen --depth=1year # scan further back
29
+ ```
30
+
31
+ ## How it works
32
+
33
+ `pip install chronicle-dev` installs a `chronicle` entry point that:
34
+ 1. Checks Node ≥ 20 is available
35
+ 2. Delegates to `chronicle` (if globally installed) or `npx chronicle-dev`
36
+
37
+ The Node package is the source of truth. This wrapper exists so Python developers
38
+ can install Chronicle without switching to npm.
39
+
40
+ ## Full docs
41
+
42
+ See [github.com/ypollak2/chronicle](https://github.com/ypollak2/chronicle)
@@ -0,0 +1,12 @@
1
+ """
2
+ Chronicle — AI-native development memory.
3
+
4
+ This package is a thin wrapper around the Node.js chronicle-dev CLI.
5
+ For the full API, use the CLI directly or via subprocess.
6
+
7
+ Example:
8
+ import subprocess
9
+ result = subprocess.run(["chronicle", "inject"], capture_output=True, text=True)
10
+ context = result.stdout
11
+ """
12
+ __version__ = "0.1.0"
@@ -0,0 +1,64 @@
1
+ """
2
+ Subprocess wrapper — delegates all work to the Node binary (chronicle-dev).
3
+ Requires Node ≥ 20 on PATH. The Node package is the source of truth.
4
+ """
5
+ import shutil
6
+ import subprocess
7
+ import sys
8
+
9
+
10
+ def _node_available() -> bool:
11
+ node = shutil.which("node")
12
+ if not node:
13
+ return False
14
+ try:
15
+ out = subprocess.check_output(["node", "--version"], text=True).strip()
16
+ major = int(out.lstrip("v").split(".")[0])
17
+ return major >= 20
18
+ except Exception:
19
+ return False
20
+
21
+
22
+ def _chronicle_binary() -> list[str]:
23
+ """Return the command list that invokes the Node chronicle CLI.
24
+
25
+ Never calls 'chronicle' directly — that would call this Python wrapper
26
+ recursively. Always delegates to the Node package via npm/npx.
27
+ """
28
+ # If the user has `npm install -g chronicle-dev`, the Node binary lands
29
+ # at a path like /usr/local/bin/chronicle — but so does this Python script.
30
+ # We disambiguate by checking for the npm global bin explicitly.
31
+ npm = shutil.which("npm")
32
+ if npm:
33
+ try:
34
+ prefix = subprocess.check_output(
35
+ [npm, "root", "-g"], text=True, stderr=subprocess.DEVNULL
36
+ ).strip()
37
+ # npm global bin is one level up from global node_modules
38
+ import os
39
+ global_bin = os.path.join(os.path.dirname(prefix), "bin", "chronicle")
40
+ # Only use it if it's a Node script (not this Python script)
41
+ if os.path.exists(global_bin):
42
+ with open(global_bin) as f:
43
+ first_line = f.readline()
44
+ if "node" in first_line and "python" not in first_line:
45
+ return [global_bin]
46
+ except Exception:
47
+ pass
48
+
49
+ # Fallback: npx installs on-demand from npm registry
50
+ return ["npx", "--yes", "chronicle-dev"]
51
+
52
+
53
+ def main() -> None:
54
+ if not _node_available():
55
+ print(
56
+ "Chronicle requires Node.js ≥ 20.\n"
57
+ "Install it from https://nodejs.org or via `brew install node`.",
58
+ file=sys.stderr,
59
+ )
60
+ sys.exit(1)
61
+
62
+ cmd = _chronicle_binary() + sys.argv[1:]
63
+ result = subprocess.run(cmd)
64
+ sys.exit(result.returncode)
@@ -0,0 +1,37 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "chronicle-dev"
7
+ version = "0.1.0"
8
+ description = "AI-native development memory — markdown RAG for every AI coding tool"
9
+ readme = "README.md"
10
+ license = { text = "MIT" }
11
+ requires-python = ">=3.9"
12
+ keywords = ["ai", "llm", "rag", "developer-tools", "claude", "codex", "cursor"]
13
+ classifiers = [
14
+ "Development Status :: 3 - Alpha",
15
+ "Environment :: Console",
16
+ "Intended Audience :: Developers",
17
+ "License :: OSI Approved :: MIT License",
18
+ "Programming Language :: Python :: 3",
19
+ "Topic :: Software Development :: Libraries :: Python Modules",
20
+ ]
21
+
22
+ # No runtime dependencies — Node does all the work
23
+ dependencies = []
24
+
25
+ [project.optional-dependencies]
26
+ dev = ["pytest>=7.0"]
27
+
28
+ [project.scripts]
29
+ chronicle = "chronicle._cli:main"
30
+
31
+ [project.urls]
32
+ Homepage = "https://github.com/ypollak2/chronicle"
33
+ Repository = "https://github.com/ypollak2/chronicle"
34
+ Issues = "https://github.com/ypollak2/chronicle/issues"
35
+
36
+ [tool.hatch.build.targets.wheel]
37
+ packages = ["chronicle"]
@@ -0,0 +1,58 @@
1
+ """Tests for the Chronicle Python wrapper."""
2
+ import subprocess
3
+ import sys
4
+ from unittest.mock import patch, MagicMock
5
+ import pytest
6
+
7
+
8
+ def test_node_available_when_node_on_path():
9
+ """Node must be detectable via shutil.which."""
10
+ import shutil
11
+ assert shutil.which("node") is not None, "Node not found — required for Chronicle"
12
+
13
+
14
+ def test_node_version_is_20_plus():
15
+ """Node version must be >= 20."""
16
+ result = subprocess.run(["node", "--version"], capture_output=True, text=True)
17
+ assert result.returncode == 0
18
+ version_str = result.stdout.strip().lstrip("v")
19
+ major = int(version_str.split(".")[0])
20
+ assert major >= 20, f"Node {version_str} < 20"
21
+
22
+
23
+ def test_main_exits_nonzero_without_node(monkeypatch):
24
+ """main() exits with code 1 when Node is not available."""
25
+ from chronicle._cli import _node_available
26
+ with patch("chronicle._cli._node_available", return_value=False):
27
+ with pytest.raises(SystemExit) as exc:
28
+ from chronicle._cli import main
29
+ main()
30
+ assert exc.value.code == 1
31
+
32
+
33
+ def test_chronicle_binary_prefers_node_global():
34
+ """_chronicle_binary returns a list starting with a string."""
35
+ from chronicle._cli import _chronicle_binary
36
+ cmd = _chronicle_binary()
37
+ assert isinstance(cmd, list)
38
+ assert len(cmd) >= 1
39
+ assert isinstance(cmd[0], str)
40
+
41
+
42
+ def test_chronicle_binary_fallback_is_npx():
43
+ """Falls back to npx when no global Node binary found."""
44
+ import shutil
45
+ with patch("shutil.which", return_value=None):
46
+ from importlib import reload
47
+ import chronicle._cli as cli_module
48
+ # Simulate npm not found → must fall back to npx
49
+ with patch("subprocess.check_output", side_effect=Exception("no npm")):
50
+ cmd = cli_module._chronicle_binary()
51
+ assert cmd[0] in ("npx", "chronicle"), f"Unexpected fallback: {cmd}"
52
+
53
+
54
+ def test_package_version_defined():
55
+ """Package version must be defined."""
56
+ import chronicle
57
+ assert hasattr(chronicle, "__version__")
58
+ assert chronicle.__version__ == "0.1.0"