opencode-db 0.7.0__tar.gz → 0.7.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.
Files changed (41) hide show
  1. {opencode_db-0.7.0/opencode_db.egg-info → opencode_db-0.7.2}/PKG-INFO +5 -2
  2. {opencode_db-0.7.0 → opencode_db-0.7.2}/README.md +87 -14
  3. {opencode_db-0.7.0 → opencode_db-0.7.2}/README_PYPI.md +4 -1
  4. {opencode_db-0.7.0 → opencode_db-0.7.2}/cli.py +9 -3
  5. {opencode_db-0.7.0 → opencode_db-0.7.2/opencode_db.egg-info}/PKG-INFO +5 -2
  6. {opencode_db-0.7.0 → opencode_db-0.7.2}/opencode_db.egg-info/SOURCES.txt +2 -0
  7. {opencode_db-0.7.0 → opencode_db-0.7.2}/opencode_db.egg-info/top_level.txt +1 -0
  8. {opencode_db-0.7.0 → opencode_db-0.7.2}/pyproject.toml +2 -2
  9. opencode_db-0.7.2/runtime.py +55 -0
  10. opencode_db-0.7.2/tests/test_runtime.py +21 -0
  11. {opencode_db-0.7.0 → opencode_db-0.7.2}/utils.py +1 -1
  12. {opencode_db-0.7.0 → opencode_db-0.7.2}/LICENSE +0 -0
  13. {opencode_db-0.7.0 → opencode_db-0.7.2}/cmd_costs.py +0 -0
  14. {opencode_db-0.7.0 → opencode_db-0.7.2}/cmd_delete.py +0 -0
  15. {opencode_db-0.7.0 → opencode_db-0.7.2}/cmd_export.py +0 -0
  16. {opencode_db-0.7.0 → opencode_db-0.7.2}/cmd_help.py +0 -0
  17. {opencode_db-0.7.0 → opencode_db-0.7.2}/cmd_info.py +0 -0
  18. {opencode_db-0.7.0 → opencode_db-0.7.2}/cmd_list.py +0 -0
  19. {opencode_db-0.7.0 → opencode_db-0.7.2}/cmd_projects.py +0 -0
  20. {opencode_db-0.7.0 → opencode_db-0.7.2}/cmd_prune.py +0 -0
  21. {opencode_db-0.7.0 → opencode_db-0.7.2}/cmd_search.py +0 -0
  22. {opencode_db-0.7.0 → opencode_db-0.7.2}/cmd_stats.py +0 -0
  23. {opencode_db-0.7.0 → opencode_db-0.7.2}/cmd_todos.py +0 -0
  24. {opencode_db-0.7.0 → opencode_db-0.7.2}/cmd_tree.py +0 -0
  25. {opencode_db-0.7.0 → opencode_db-0.7.2}/cmd_vacuum.py +0 -0
  26. {opencode_db-0.7.0 → opencode_db-0.7.2}/cmd_view.py +0 -0
  27. {opencode_db-0.7.0 → opencode_db-0.7.2}/commands/__init__.py +0 -0
  28. {opencode_db-0.7.0 → opencode_db-0.7.2}/config.py +0 -0
  29. {opencode_db-0.7.0 → opencode_db-0.7.2}/db.py +0 -0
  30. {opencode_db-0.7.0 → opencode_db-0.7.2}/formatters.py +0 -0
  31. {opencode_db-0.7.0 → opencode_db-0.7.2}/i18n.py +0 -0
  32. {opencode_db-0.7.0 → opencode_db-0.7.2}/markdown_to_ansi.py +0 -0
  33. {opencode_db-0.7.0 → opencode_db-0.7.2}/opencode_db.egg-info/dependency_links.txt +0 -0
  34. {opencode_db-0.7.0 → opencode_db-0.7.2}/opencode_db.egg-info/entry_points.txt +0 -0
  35. {opencode_db-0.7.0 → opencode_db-0.7.2}/opencode_db.egg-info/requires.txt +0 -0
  36. {opencode_db-0.7.0 → opencode_db-0.7.2}/setup.cfg +0 -0
  37. {opencode_db-0.7.0 → opencode_db-0.7.2}/tests/test_commands.py +0 -0
  38. {opencode_db-0.7.0 → opencode_db-0.7.2}/tests/test_db.py +0 -0
  39. {opencode_db-0.7.0 → opencode_db-0.7.2}/tests/test_formatters.py +0 -0
  40. {opencode_db-0.7.0 → opencode_db-0.7.2}/tests/test_i18n.py +0 -0
  41. {opencode_db-0.7.0 → opencode_db-0.7.2}/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opencode-db
3
- Version: 0.7.0
3
+ Version: 0.7.2
4
4
  Summary: OpenCode database CLI manager — browse, export, analyze, clean up sessions
5
5
  Project-URL: Homepage, https://github.com/VasilevNStas/opencode-db
6
6
  Project-URL: Source, https://github.com/VasilevNStas/opencode-db
@@ -23,6 +23,9 @@ Dynamic: license-file
23
23
 
24
24
  ```bash
25
25
  pip install opencode-db
26
+
27
+ # recommended if your system python3 is older than 3.12:
28
+ uv tool install opencode-db
26
29
  ```
27
30
 
28
31
  ## Quick start
@@ -54,6 +57,6 @@ pip install opencode-db # zero external dependencies
54
57
 
55
58
  ## Requirements
56
59
 
57
- - Python 3.12+
60
+ - Python 3.12+ — the CLI checks the interpreter at startup and exits with a clear message instead of an `ImportError` on older versions
58
61
  - [OpenCode](https://opencode.ai) (must have been run at least once)
59
62
  - macOS / Linux
@@ -22,9 +22,10 @@ opencode-db costs --total # total token costs
22
22
 
23
23
  ### Requirements
24
24
 
25
- - Python 3.12+
25
+ - Python 3.12+ — `opencode-db` refuses to start on older interpreters with a clear message (no cryptic `ImportError`)
26
26
  - OpenCode (must have been run at least once — the database is created automatically)
27
27
  - macOS / Linux
28
+ - [`uv`](https://docs.astral.sh/uv/) — optional, but recommended for installing and running on systems whose default `python3` is older than 3.12
28
29
 
29
30
  ### Database location
30
31
 
@@ -51,13 +52,26 @@ opencode-db --db-path /path/to/opencode.db stats
51
52
 
52
53
  The `--db-path` flag takes precedence over the environment variable.
53
54
 
54
- ### One-command install (recommended)
55
+ ### Recommended: uv
56
+
57
+ If your system `python3` is older than 3.12 (for example, macOS ships 3.9), use `uv` — it installs the tool into an isolated environment with a supported interpreter:
58
+
59
+ ```bash
60
+ uv tool install opencode-db
61
+ # with enhanced Markdown rendering:
62
+ uv tool install "opencode-db[rich]"
63
+
64
+ # one-off run without installing:
65
+ uvx opencode-db stats
66
+ ```
67
+
68
+ ### One-command install
55
69
 
56
70
  ```bash
57
71
  curl -fsSL https://raw.githubusercontent.com/VasilevNStas/opencode-db/master/install.sh | sh
58
72
  ```
59
73
 
60
- Downloads everything to `~/.local/share/opencode-db/` and creates `~/.local/bin/opencode-db`.
74
+ Downloads everything to `~/.local/share/opencode-db/` and creates `~/.local/bin/opencode-db`. The installer looks for Python 3.12+ (including interpreters managed by `uv` or `pyenv`) and writes the discovered path into the launcher shebang.
61
75
 
62
76
  ### pip / pipx install
63
77
 
@@ -67,7 +81,7 @@ pipx install opencode-db
67
81
  pip install opencode-db
68
82
  ```
69
83
 
70
- [Zero external dependencies](https://treyhunner.com/2015/12/python-imports-and-path-manipulation/) — pure Python standard library only.
84
+ [Zero external dependencies](https://treyhunner.com/2015/12/python-imports-and-path-manipulation/) — pure Python standard library only (`rich` is optional).
71
85
 
72
86
  ### Manual install
73
87
 
@@ -82,7 +96,17 @@ git clone https://github.com/VasilevNStas/opencode-db.git ~/.local/share/opencod
82
96
  ```bash
83
97
  cat > ~/.local/bin/opencode-db << 'SCRIPT'
84
98
  #!/usr/bin/env python3
85
- import sys, os
99
+ import os
100
+ import sys
101
+
102
+ if sys.version_info < (3, 12):
103
+ print(
104
+ "opencode-db requires Python 3.12+; current: %s (%s)"
105
+ % (".".join(map(str, sys.version_info[:3])), sys.executable),
106
+ file=sys.stderr,
107
+ )
108
+ raise SystemExit(1)
109
+
86
110
  PKG_DIR = os.path.expanduser("~/.local/share/opencode-db")
87
111
  if PKG_DIR not in sys.path:
88
112
  sys.path.insert(0, PKG_DIR)
@@ -488,14 +512,16 @@ Example output:
488
512
  ~/.local/share/opencode-db/ ← all source code
489
513
  │
490
514
  ├── __init__.py ← executable entry point
491
- ├── __main__.py ← python -m opencode_db
515
+ ├── __main__.py ← python3 . (directory entry point)
492
516
  ├── cli.py ← argparse + command dispatcher
493
517
  │
494
518
  ├── config.py ← constants and paths
519
+ ├── runtime.py ← Python 3.12+ version guard
495
520
  ├── db.py ← SQLite queries
496
521
  ├── utils.py ← date/token formatting, validation
497
522
  ├── formatters.py ← tables, JSON, Markdown, snapshots
498
- ├── i18n.py ← localization (EN/RU, 238 keys)
523
+ ├── i18n.py ← localization (EN/RU, 280 keys)
524
+ ├── markdown_to_ansi.py ← Markdown → ANSI renderer for `view`
499
525
  │
500
526
  ├── commands/
501
527
  │ └── __init__.py ← command registry
@@ -512,6 +538,7 @@ Example output:
512
538
  ├── cmd_stats.py ← opencode-db stats
513
539
  ├── cmd_todos.py ← opencode-db todos
514
540
  ├── cmd_vacuum.py ← opencode-db vacuum
541
+ ├── cmd_view.py ← opencode-db view
515
542
  └── cmd_help.py ← opencode-db help
516
543
 
517
544
  README.md ← this file (English)
@@ -522,10 +549,11 @@ opencode-db-commands.json ← OpenCode TUI custom commands confi
522
549
  ### How it works
523
550
 
524
551
  1. The launcher script at `~/.local/bin/opencode-db` (a shebang Python script) adds `~/.local/share/opencode-db/` to `sys.path` and calls `cli.main()`.
525
- 2. `cli.py` builds an `argparse` parser with subparsers from every command module and dispatches the call.
526
- 3. Each command is a separate `cmd_*.py` module exporting two functions: `register(subparsers)` and `run(args, db)`.
527
- 4. `db.py` opens a connection to OpenCode's SQLite database (`~/.local/share/opencode/opencode.db`).
528
- 5. Destructive operations (`delete`, `prune`) always require confirmation (or `--force`).
552
+ 2. `runtime.require_python()` checks the interpreter before importing `cli`/`db`; on Python < 3.12 it prints a clear message with remediation steps instead of failing with `ImportError`.
553
+ 3. `cli.py` builds an `argparse` parser with subparsers from every command module and dispatches the call.
554
+ 4. Each command is a separate `cmd_*.py` module exporting two functions: `register(subparsers)` and `run(args, db)`.
555
+ 5. `db.py` opens a connection to OpenCode's SQLite database (`~/.local/share/opencode/opencode.db`).
556
+ 6. Destructive operations (`delete`, `prune`) always require confirmation (or `--force`).
529
557
 
530
558
  ### Database schema (key tables)
531
559
 
@@ -617,7 +645,7 @@ opencode-db --lang en help # English help text
617
645
  opencode-db --lang en stats # English statistics
618
646
  ```
619
647
 
620
- The `--lang` flag applies to any command. All 238 UI strings are translated. Data content (session titles, project names, etc.) remains in its original language.
648
+ The `--lang` flag applies to any command. All 280 UI strings are translated. Data content (session titles, project names, etc.) remains in its original language.
621
649
 
622
650
  The language can also be set via environment variable `OPENCODE_DB_LANG=en`.
623
651
 
@@ -659,10 +687,54 @@ Use a longer prefix or the full session ID (use `list --json` to find it).
659
687
 
660
688
  If the database is being used by another process (e.g., OpenCode is running), VACUUM may fail. Close OpenCode and try again.
661
689
 
690
+ ### `ImportError: cannot import name 'UTC' from 'datetime'`
691
+
692
+ This means `opencode-db` is running on Python older than 3.12 (for example, the system Python 3.9). Check:
693
+
694
+ ```bash
695
+ python3 --version
696
+ ```
697
+
698
+ Fix with `uv` (recommended):
699
+
700
+ ```bash
701
+ uv python install 3.13
702
+ uv tool install opencode-db
703
+ opencode-db stats
704
+ ```
705
+
706
+ Or run the repository checkout with an explicit interpreter:
707
+
708
+ ```bash
709
+ uvx --from . opencode-db stats
710
+ # alternative for a persistent dev environment:
711
+ uv run --python 3.13 opencode-db stats
712
+ ```
713
+
714
+ After changing the interpreter, rerun `install.sh` to regenerate the `~/.local/bin/opencode-db` launcher.
715
+
662
716
  ---
663
717
 
664
718
  ## Development
665
719
 
720
+ ### Local development
721
+
722
+ Requires Python 3.12+ and `pytest`/`ruff`:
723
+
724
+ ```bash
725
+ git clone https://github.com/VasilevNStas/opencode-db.git
726
+ cd opencode-db
727
+
728
+ uv venv --python 3.13
729
+ source .venv/bin/activate
730
+ uv pip install -e ".[rich]"
731
+ uv pip install pytest ruff
732
+
733
+ make check # check-python + ruff + 191 tests
734
+ ```
735
+
736
+ `make check` fails fast with a clear message if the active interpreter is older than 3.12.
737
+
666
738
  ### Adding a new command
667
739
 
668
740
  1. Create `cmd_xxx.py`:
@@ -692,10 +764,11 @@ The command will appear in `--help` automatically.
692
764
  python3 ~/.local/share/opencode-db list
693
765
  ```
694
766
 
695
- Or as a module:
767
+ Or from the repository root (Python 3.12+):
696
768
 
697
769
  ```bash
698
- python3 -m opencode_db list
770
+ python3 . list
771
+ uvx --from . opencode-db list
699
772
  ```
700
773
 
701
774
  ---
@@ -7,6 +7,9 @@
7
7
 
8
8
  ```bash
9
9
  pip install opencode-db
10
+
11
+ # recommended if your system python3 is older than 3.12:
12
+ uv tool install opencode-db
10
13
  ```
11
14
 
12
15
  ## Quick start
@@ -38,6 +41,6 @@ pip install opencode-db # zero external dependencies
38
41
 
39
42
  ## Requirements
40
43
 
41
- - Python 3.12+
44
+ - Python 3.12+ — the CLI checks the interpreter at startup and exits with a clear message instead of an `ImportError` on older versions
42
45
  - [OpenCode](https://opencode.ai) (must have been run at least once)
43
46
  - macOS / Linux
@@ -7,14 +7,20 @@
7
7
  - Единообразный интерфейс
8
8
  """
9
9
 
10
+ from __future__ import annotations
11
+
10
12
  import argparse
11
13
  import os
12
14
  import sys
13
15
  from typing import Any, Literal
14
16
 
15
- import commands
16
- from db import get_db
17
- from i18n import _, set_lang
17
+ from runtime import require_python
18
+
19
+ require_python()
20
+
21
+ import commands # noqa: E402
22
+ from db import get_db # noqa: E402
23
+ from i18n import _, set_lang # noqa: E402
18
24
 
19
25
 
20
26
  def build_parser() -> argparse.ArgumentParser:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opencode-db
3
- Version: 0.7.0
3
+ Version: 0.7.2
4
4
  Summary: OpenCode database CLI manager — browse, export, analyze, clean up sessions
5
5
  Project-URL: Homepage, https://github.com/VasilevNStas/opencode-db
6
6
  Project-URL: Source, https://github.com/VasilevNStas/opencode-db
@@ -23,6 +23,9 @@ Dynamic: license-file
23
23
 
24
24
  ```bash
25
25
  pip install opencode-db
26
+
27
+ # recommended if your system python3 is older than 3.12:
28
+ uv tool install opencode-db
26
29
  ```
27
30
 
28
31
  ## Quick start
@@ -54,6 +57,6 @@ pip install opencode-db # zero external dependencies
54
57
 
55
58
  ## Requirements
56
59
 
57
- - Python 3.12+
60
+ - Python 3.12+ — the CLI checks the interpreter at startup and exits with a clear message instead of an `ImportError` on older versions
58
61
  - [OpenCode](https://opencode.ai) (must have been run at least once)
59
62
  - macOS / Linux
@@ -22,6 +22,7 @@ formatters.py
22
22
  i18n.py
23
23
  markdown_to_ansi.py
24
24
  pyproject.toml
25
+ runtime.py
25
26
  utils.py
26
27
  commands/__init__.py
27
28
  opencode_db.egg-info/PKG-INFO
@@ -34,4 +35,5 @@ tests/test_commands.py
34
35
  tests/test_db.py
35
36
  tests/test_formatters.py
36
37
  tests/test_i18n.py
38
+ tests/test_runtime.py
37
39
  tests/test_utils.py
@@ -19,4 +19,5 @@ db
19
19
  formatters
20
20
  i18n
21
21
  markdown_to_ansi
22
+ runtime
22
23
  utils
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "opencode-db"
7
- version = "0.7.0"
7
+ version = "0.7.2"
8
8
  description = "OpenCode database CLI manager — browse, export, analyze, clean up sessions"
9
9
  readme = "README_PYPI.md"
10
10
  requires-python = ">=3.12"
@@ -23,7 +23,7 @@ opencode-db = "cli:main"
23
23
 
24
24
  [tool.setuptools]
25
25
  py-modules = [
26
- "cli", "config", "db", "formatters", "i18n", "utils",
26
+ "cli", "config", "db", "formatters", "i18n", "runtime", "utils",
27
27
  "cmd_costs", "cmd_delete", "cmd_export", "cmd_help",
28
28
  "cmd_info", "cmd_list", "cmd_projects", "cmd_prune",
29
29
  "cmd_search", "cmd_stats", "cmd_todos", "cmd_tree", "cmd_vacuum",
@@ -0,0 +1,55 @@
1
+ """Проверка минимальной версии Python.
2
+
3
+ Модуль намеренно написан без синтаксиса новее Python 3.8, чтобы его можно
4
+ было импортировать до проверки версии и показать понятную ошибку вместо
5
+ ImportError/SyntaxError.
6
+ """
7
+
8
+ import sys
9
+
10
+ MIN_PYTHON = (3, 12)
11
+ REQUIRED_VERSION = "3.12"
12
+
13
+
14
+ def format_version_error(version_info=None, executable=None) -> str:
15
+ """Возвращает текст ошибки для неподдерживаемой версии Python."""
16
+ info = version_info or sys.version_info
17
+ exe = executable or sys.executable
18
+ current = f"{info[0]}.{info[1]}.{info[2]}"
19
+
20
+ return (
21
+ f"opencode-db requires Python {REQUIRED_VERSION}+.\n"
22
+ f"opencode-db требует Python {REQUIRED_VERSION}+.\n"
23
+ "\n"
24
+ f"Current interpreter: Python {current} ({exe})\n"
25
+ f"Текущий интерпретатор: Python {current} ({exe})\n"
26
+ "\n"
27
+ "How to fix / Как исправить:\n"
28
+ " uv python install 3.13\n"
29
+ " uv venv --python 3.13\n"
30
+ " source .venv/bin/activate\n"
31
+ " pip install -e .\n"
32
+ "\n"
33
+ "Or run with uv / Или запуск через uv:\n"
34
+ " uv run --python 3.13 opencode-db --help\n"
35
+ " uv tool install --editable . && opencode-db --help\n"
36
+ "\n"
37
+ "After changing the interpreter, rerun install.sh to regenerate\n"
38
+ "the ~/.local/bin/opencode-db launcher."
39
+ )
40
+
41
+
42
+ def check_python_version(version_info=None):
43
+ """Возвращает None, если версия подходит, иначе текст ошибки."""
44
+ info = version_info or sys.version_info
45
+ if tuple(info[:2]) >= MIN_PYTHON:
46
+ return None
47
+ return format_version_error(info)
48
+
49
+
50
+ def require_python() -> None:
51
+ """Завершает процесс с понятной ошибкой, если Python слишком старый."""
52
+ message = check_python_version()
53
+ if message:
54
+ print(message, file=sys.stderr)
55
+ raise SystemExit(1)
@@ -0,0 +1,21 @@
1
+ from runtime import MIN_PYTHON, check_python_version, format_version_error
2
+
3
+
4
+ class TestRuntime:
5
+ def test_supported_versions_pass(self) -> None:
6
+ assert check_python_version((3, 12, 0)) is None
7
+ assert check_python_version((3, 13, 5)) is None
8
+ assert check_python_version((4, 0, 0)) is None
9
+
10
+ def test_old_version_returns_error(self) -> None:
11
+ message = check_python_version((3, 9, 6))
12
+ assert message is not None
13
+ assert "3.12+" in message
14
+ assert "3.9.6" in message
15
+
16
+ def test_error_contains_remediation(self) -> None:
17
+ message = format_version_error((3, 9, 6), "/usr/bin/python3")
18
+ assert MIN_PYTHON == (3, 12)
19
+ assert "/usr/bin/python3" in message
20
+ assert "uv python install" in message
21
+ assert "uv run" in message
@@ -50,7 +50,7 @@ def parse_date(date_str: str) -> datetime | None:
50
50
  return None
51
51
 
52
52
 
53
- def parse_time_spec(spec) -> None | datetime:
53
+ def parse_time_spec(spec) -> datetime | None:
54
54
  """Парсит спецификацию времени ('30d', '6m', '1y') в timedelta."""
55
55
  if not spec or not isinstance(spec, str):
56
56
  return None
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