opencode-db 0.7.0__tar.gz → 0.7.3__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 (46) hide show
  1. {opencode_db-0.7.0/opencode_db.egg-info → opencode_db-0.7.3}/PKG-INFO +6 -3
  2. {opencode_db-0.7.0 → opencode_db-0.7.3}/README.md +129 -51
  3. {opencode_db-0.7.0 → opencode_db-0.7.3/docs}/README_PYPI.md +5 -2
  4. opencode_db-0.7.3/opencode_db/__init__.py +5 -0
  5. opencode_db-0.7.3/opencode_db/__main__.py +6 -0
  6. {opencode_db-0.7.0 → opencode_db-0.7.3/opencode_db}/cli.py +9 -3
  7. {opencode_db-0.7.0 → opencode_db-0.7.3/opencode_db}/commands/__init__.py +18 -16
  8. {opencode_db-0.7.0 → opencode_db-0.7.3/opencode_db/commands}/cmd_costs.py +7 -7
  9. {opencode_db-0.7.0 → opencode_db-0.7.3/opencode_db/commands}/cmd_delete.py +3 -3
  10. {opencode_db-0.7.0 → opencode_db-0.7.3/opencode_db/commands}/cmd_export.py +4 -4
  11. {opencode_db-0.7.0 → opencode_db-0.7.3/opencode_db/commands}/cmd_help.py +2 -2
  12. {opencode_db-0.7.0 → opencode_db-0.7.3/opencode_db/commands}/cmd_info.py +4 -4
  13. {opencode_db-0.7.0 → opencode_db-0.7.3/opencode_db/commands}/cmd_list.py +5 -5
  14. {opencode_db-0.7.0 → opencode_db-0.7.3/opencode_db/commands}/cmd_projects.py +4 -4
  15. {opencode_db-0.7.0 → opencode_db-0.7.3/opencode_db/commands}/cmd_prune.py +3 -3
  16. {opencode_db-0.7.0 → opencode_db-0.7.3/opencode_db/commands}/cmd_search.py +4 -4
  17. {opencode_db-0.7.0 → opencode_db-0.7.3/opencode_db/commands}/cmd_stats.py +4 -4
  18. {opencode_db-0.7.0 → opencode_db-0.7.3/opencode_db/commands}/cmd_todos.py +4 -4
  19. {opencode_db-0.7.0 → opencode_db-0.7.3/opencode_db/commands}/cmd_tree.py +3 -3
  20. {opencode_db-0.7.0 → opencode_db-0.7.3/opencode_db/commands}/cmd_vacuum.py +3 -3
  21. {opencode_db-0.7.0 → opencode_db-0.7.3/opencode_db/commands}/cmd_view.py +4 -4
  22. {opencode_db-0.7.0 → opencode_db-0.7.3/opencode_db}/db.py +2 -2
  23. {opencode_db-0.7.0 → opencode_db-0.7.3/opencode_db}/formatters.py +2 -2
  24. {opencode_db-0.7.0 → opencode_db-0.7.3/opencode_db}/i18n.py +1 -1
  25. opencode_db-0.7.3/opencode_db/runtime.py +55 -0
  26. {opencode_db-0.7.0 → opencode_db-0.7.3/opencode_db}/utils.py +2 -2
  27. {opencode_db-0.7.0 → opencode_db-0.7.3/opencode_db.egg-info}/PKG-INFO +6 -3
  28. opencode_db-0.7.3/opencode_db.egg-info/SOURCES.txt +41 -0
  29. opencode_db-0.7.3/opencode_db.egg-info/entry_points.txt +2 -0
  30. opencode_db-0.7.3/opencode_db.egg-info/top_level.txt +1 -0
  31. {opencode_db-0.7.0 → opencode_db-0.7.3}/pyproject.toml +6 -14
  32. {opencode_db-0.7.0 → opencode_db-0.7.3}/tests/test_commands.py +81 -81
  33. {opencode_db-0.7.0 → opencode_db-0.7.3}/tests/test_db.py +1 -1
  34. {opencode_db-0.7.0 → opencode_db-0.7.3}/tests/test_formatters.py +1 -1
  35. {opencode_db-0.7.0 → opencode_db-0.7.3}/tests/test_i18n.py +2 -2
  36. opencode_db-0.7.3/tests/test_runtime.py +21 -0
  37. {opencode_db-0.7.0 → opencode_db-0.7.3}/tests/test_utils.py +1 -1
  38. opencode_db-0.7.0/opencode_db.egg-info/SOURCES.txt +0 -37
  39. opencode_db-0.7.0/opencode_db.egg-info/entry_points.txt +0 -2
  40. opencode_db-0.7.0/opencode_db.egg-info/top_level.txt +0 -22
  41. {opencode_db-0.7.0 → opencode_db-0.7.3}/LICENSE +0 -0
  42. {opencode_db-0.7.0 → opencode_db-0.7.3/opencode_db}/config.py +0 -0
  43. {opencode_db-0.7.0 → opencode_db-0.7.3/opencode_db}/markdown_to_ansi.py +0 -0
  44. {opencode_db-0.7.0 → opencode_db-0.7.3}/opencode_db.egg-info/dependency_links.txt +0 -0
  45. {opencode_db-0.7.0 → opencode_db-0.7.3}/opencode_db.egg-info/requires.txt +0 -0
  46. {opencode_db-0.7.0 → opencode_db-0.7.3}/setup.cfg +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.3
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
@@ -17,12 +17,15 @@ Dynamic: license-file
17
17
  # opencode-db
18
18
 
19
19
  [![Python](https://img.shields.io/badge/python-3.12%2B-blue)](https://www.python.org/downloads/)
20
- [![License](https://img.shields.io/badge/license-MIT-green)](LICENSE)
20
+ [![License](https://img.shields.io/badge/license-MIT-green)](https://github.com/VasilevNStas/opencode-db/blob/master/LICENSE)
21
21
 
22
22
  **CLI for OpenCode's local database.** OpenCode saves every agent session, conversation, token usage, and cost in a local SQLite file. This tool lets you inspect, export, analyze, and clean up that data.
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
@@ -8,6 +8,8 @@
8
8
 
9
9
  **OpenCode stores everything in a local SQLite database.** Every agent session, conversation, token usage, and cost is saved automatically. `opencode-db` is the CLI tool to work with that database — list sessions, export conversations to Markdown, track token costs, prune old data, and more.
10
10
 
11
+ [Русская версия](docs/README.ru.md)
12
+
11
13
  ```
12
14
  opencode-db help # full reference with examples
13
15
  opencode-db list # list recent sessions
@@ -22,9 +24,10 @@ opencode-db costs --total # total token costs
22
24
 
23
25
  ### Requirements
24
26
 
25
- - Python 3.12+
27
+ - Python 3.12+ — `opencode-db` refuses to start on older interpreters with a clear message (no cryptic `ImportError`)
26
28
  - OpenCode (must have been run at least once — the database is created automatically)
27
29
  - macOS / Linux
30
+ - [`uv`](https://docs.astral.sh/uv/) — optional, but recommended for installing and running on systems whose default `python3` is older than 3.12
28
31
 
29
32
  ### Database location
30
33
 
@@ -51,13 +54,26 @@ opencode-db --db-path /path/to/opencode.db stats
51
54
 
52
55
  The `--db-path` flag takes precedence over the environment variable.
53
56
 
54
- ### One-command install (recommended)
57
+ ### Recommended: uv
58
+
59
+ 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:
60
+
61
+ ```bash
62
+ uv tool install opencode-db
63
+ # with enhanced Markdown rendering:
64
+ uv tool install "opencode-db[rich]"
65
+
66
+ # one-off run without installing:
67
+ uvx opencode-db stats
68
+ ```
69
+
70
+ ### One-command install
55
71
 
56
72
  ```bash
57
73
  curl -fsSL https://raw.githubusercontent.com/VasilevNStas/opencode-db/master/install.sh | sh
58
74
  ```
59
75
 
60
- Downloads everything to `~/.local/share/opencode-db/` and creates `~/.local/bin/opencode-db`.
76
+ 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
77
 
62
78
  ### pip / pipx install
63
79
 
@@ -67,7 +83,7 @@ pipx install opencode-db
67
83
  pip install opencode-db
68
84
  ```
69
85
 
70
- [Zero external dependencies](https://treyhunner.com/2015/12/python-imports-and-path-manipulation/) — pure Python standard library only.
86
+ [Zero external dependencies](https://treyhunner.com/2015/12/python-imports-and-path-manipulation/) — pure Python standard library only (`rich` is optional).
71
87
 
72
88
  ### Manual install
73
89
 
@@ -82,12 +98,22 @@ git clone https://github.com/VasilevNStas/opencode-db.git ~/.local/share/opencod
82
98
  ```bash
83
99
  cat > ~/.local/bin/opencode-db << 'SCRIPT'
84
100
  #!/usr/bin/env python3
85
- import sys, os
101
+ import os
102
+ import sys
103
+
104
+ if sys.version_info < (3, 12):
105
+ print(
106
+ "opencode-db requires Python 3.12+; current: %s (%s)"
107
+ % (".".join(map(str, sys.version_info[:3])), sys.executable),
108
+ file=sys.stderr,
109
+ )
110
+ raise SystemExit(1)
111
+
86
112
  PKG_DIR = os.path.expanduser("~/.local/share/opencode-db")
87
113
  if PKG_DIR not in sys.path:
88
114
  sys.path.insert(0, PKG_DIR)
89
- import cli
90
- sys.exit(cli.main())
115
+ from opencode_db.cli import main
116
+ sys.exit(main())
91
117
  SCRIPT
92
118
  chmod +x ~/.local/bin/opencode-db
93
119
  ```
@@ -483,49 +509,56 @@ Example output:
483
509
  ## Project architecture
484
510
 
485
511
  ```
486
- ~/.local/bin/opencode-db ← entry point (in $PATH)
512
+ opencode-db/
513
+ ├── opencode_db/ ← Python package (installed as opencode_db)
514
+ │ ├── __init__.py ← package init + Python version guard
515
+ │ ├── __main__.py ← python3 -m opencode_db
516
+ │ ├── cli.py ← argparse + command dispatcher
517
+ │ ├── config.py ← constants and paths
518
+ │ ├── db.py ← SQLite queries
519
+ │ ├── formatters.py ← tables, JSON, Markdown, snapshots
520
+ │ ├── i18n.py ← localization (EN/RU, 280 keys)
521
+ │ ├── markdown_to_ansi.py ← Markdown → ANSI renderer for `view`
522
+ │ ├── runtime.py ← Python 3.12+ version guard
523
+ │ ├── utils.py ← date/token formatting, validation
524
+ │ └── commands/
525
+ │ ├── __init__.py ← command registry
526
+ │ ├── cmd_list.py ← opencode-db list
527
+ │ ├── cmd_info.py ← opencode-db info
528
+ │ ├── cmd_export.py ← opencode-db export
529
+ │ ├── cmd_delete.py ← opencode-db delete
530
+ │ ├── cmd_costs.py ← opencode-db costs
531
+ │ ├── cmd_prune.py ← opencode-db prune
532
+ │ ├── cmd_search.py ← opencode-db search
533
+ │ ├── cmd_tree.py ← opencode-db tree
534
+ │ ├── cmd_projects.py ← opencode-db projects
535
+ │ ├── cmd_stats.py ← opencode-db stats
536
+ │ ├── cmd_todos.py ← opencode-db todos
537
+ │ ├── cmd_vacuum.py ← opencode-db vacuum
538
+ │ ├── cmd_view.py ← opencode-db view
539
+ │ └── cmd_help.py ← opencode-db help
487
540
  │
488
- ~/.local/share/opencode-db/ ← all source code
489
- │
490
- ├── __init__.py ← executable entry point
491
- ├── __main__.py ← python -m opencode_db
492
- ├── cli.py ← argparse + command dispatcher
493
- │
494
- ├── config.py ← constants and paths
495
- ├── db.py ← SQLite queries
496
- ├── utils.py ← date/token formatting, validation
497
- ├── formatters.py ← tables, JSON, Markdown, snapshots
498
- ├── i18n.py ← localization (EN/RU, 238 keys)
499
- │
500
- ├── commands/
501
- │ └── __init__.py ← command registry
502
- │
503
- ├── cmd_list.py ← opencode-db list
504
- ├── cmd_info.py ← opencode-db info
505
- ├── cmd_export.py ← opencode-db export
506
- ├── cmd_delete.py ← opencode-db delete
507
- ├── cmd_costs.py ← opencode-db costs
508
- ├── cmd_prune.py ← opencode-db prune
509
- ├── cmd_search.py ← opencode-db search
510
- ├── cmd_tree.py ← opencode-db tree
511
- ├── cmd_projects.py ← opencode-db projects
512
- ├── cmd_stats.py ← opencode-db stats
513
- ├── cmd_todos.py ← opencode-db todos
514
- ├── cmd_vacuum.py ← opencode-db vacuum
515
- └── cmd_help.py ← opencode-db help
516
-
517
- README.md ← this file (English)
518
- README.ru.md ← documentation in Russian
519
- opencode-db-commands.json ← OpenCode TUI custom commands config
541
+ ├── docs/
542
+ │ ├── README.ru.md ← documentation in Russian
543
+ │ └── README_PYPI.md ← PyPI page
544
+ ├── contrib/
545
+ │ └── opencode-db-commands.json ← OpenCode TUI custom commands config
546
+ ├── tests/
547
+ ├── README.md ← this file (English)
548
+ ├── LICENSE
549
+ ├── Makefile
550
+ ├── pyproject.toml
551
+ └── install.sh
520
552
  ```
521
553
 
522
554
  ### How it works
523
555
 
524
- 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`).
556
+ 1. The console script `opencode-db` (or `python3 -m opencode_db`) imports `opencode_db.cli` and calls `main()`.
557
+ 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`.
558
+ 3. `cli.py` builds an `argparse` parser with subparsers from every command module and dispatches the call.
559
+ 4. Each command is a separate `opencode_db/commands/cmd_*.py` module exporting two functions: `register(subparsers)` and `run(args, db)`.
560
+ 5. `db.py` opens a connection to OpenCode's SQLite database (`~/.local/share/opencode/opencode.db`).
561
+ 6. Destructive operations (`delete`, `prune`) always require confirmation (or `--force`).
529
562
 
530
563
  ### Database schema (key tables)
531
564
 
@@ -558,7 +591,7 @@ This runs the command directly and shows the output — **no tokens are consumed
558
591
 
559
592
  ### Custom `/db` command (uses AI, consumes tokens)
560
593
 
561
- Add the commands from `opencode-db-commands.json` to your project's `opencode.json`:
594
+ Add the commands from `contrib/opencode-db-commands.json` to your project's `opencode.json`:
562
595
 
563
596
  ```json
564
597
  {
@@ -586,7 +619,7 @@ Then in the TUI:
586
619
 
587
620
  A ready-to-use config file is provided at:
588
621
  ```
589
- ~/.local/share/opencode-db/opencode-db-commands.json
622
+ ~/.local/share/opencode-db/contrib/opencode-db-commands.json
590
623
  ```
591
624
 
592
625
  ---
@@ -617,7 +650,7 @@ opencode-db --lang en help # English help text
617
650
  opencode-db --lang en stats # English statistics
618
651
  ```
619
652
 
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.
653
+ 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
654
 
622
655
  The language can also be set via environment variable `OPENCODE_DB_LANG=en`.
623
656
 
@@ -659,13 +692,57 @@ Use a longer prefix or the full session ID (use `list --json` to find it).
659
692
 
660
693
  If the database is being used by another process (e.g., OpenCode is running), VACUUM may fail. Close OpenCode and try again.
661
694
 
695
+ ### `ImportError: cannot import name 'UTC' from 'datetime'`
696
+
697
+ This means `opencode-db` is running on Python older than 3.12 (for example, the system Python 3.9). Check:
698
+
699
+ ```bash
700
+ python3 --version
701
+ ```
702
+
703
+ Fix with `uv` (recommended):
704
+
705
+ ```bash
706
+ uv python install 3.13
707
+ uv tool install opencode-db
708
+ opencode-db stats
709
+ ```
710
+
711
+ Or run the repository checkout with an explicit interpreter:
712
+
713
+ ```bash
714
+ uvx --from . opencode-db stats
715
+ # alternative for a persistent dev environment:
716
+ uv run --python 3.13 opencode-db stats
717
+ ```
718
+
719
+ After changing the interpreter, rerun `install.sh` to regenerate the `~/.local/bin/opencode-db` launcher.
720
+
662
721
  ---
663
722
 
664
723
  ## Development
665
724
 
725
+ ### Local development
726
+
727
+ Requires Python 3.12+ and `pytest`/`ruff`:
728
+
729
+ ```bash
730
+ git clone https://github.com/VasilevNStas/opencode-db.git
731
+ cd opencode-db
732
+
733
+ uv venv --python 3.13
734
+ source .venv/bin/activate
735
+ uv pip install -e ".[rich]"
736
+ uv pip install pytest ruff==0.17.1
737
+
738
+ make check # check-python + ruff + 191 tests
739
+ ```
740
+
741
+ `make check` fails fast with a clear message if the active interpreter is older than 3.12.
742
+
666
743
  ### Adding a new command
667
744
 
668
- 1. Create `cmd_xxx.py`:
745
+ 1. Create `opencode_db/commands/cmd_xxx.py`:
669
746
 
670
747
  ```python
671
748
  def register(subparsers):
@@ -677,7 +754,7 @@ def run(args, db):
677
754
  return 0
678
755
  ```
679
756
 
680
- 2. Register it in `commands/__init__.py`:
757
+ 2. Register it in `opencode_db/commands/__init__.py`:
681
758
 
682
759
  ```python
683
760
  import cmd_xxx
@@ -692,10 +769,11 @@ The command will appear in `--help` automatically.
692
769
  python3 ~/.local/share/opencode-db list
693
770
  ```
694
771
 
695
- Or as a module:
772
+ Or from the repository root (Python 3.12+):
696
773
 
697
774
  ```bash
698
775
  python3 -m opencode_db list
776
+ uvx --from . opencode-db list
699
777
  ```
700
778
 
701
779
  ---
@@ -1,12 +1,15 @@
1
1
  # opencode-db
2
2
 
3
3
  [![Python](https://img.shields.io/badge/python-3.12%2B-blue)](https://www.python.org/downloads/)
4
- [![License](https://img.shields.io/badge/license-MIT-green)](LICENSE)
4
+ [![License](https://img.shields.io/badge/license-MIT-green)](https://github.com/VasilevNStas/opencode-db/blob/master/LICENSE)
5
5
 
6
6
  **CLI for OpenCode's local database.** OpenCode saves every agent session, conversation, token usage, and cost in a local SQLite file. This tool lets you inspect, export, analyze, and clean up that data.
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
@@ -0,0 +1,5 @@
1
+ """opencode-db: CLI for OpenCode's local SQLite database."""
2
+
3
+ from .runtime import require_python
4
+
5
+ require_python()
@@ -0,0 +1,6 @@
1
+ """Entry point for `python3 -m opencode_db`."""
2
+
3
+ from .cli import main
4
+
5
+ if __name__ == "__main__":
6
+ raise SystemExit(main())
@@ -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
+ from . 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:
@@ -5,25 +5,27 @@
5
5
  - run(args, db) — выполняет команду
6
6
 
7
7
  Добавление новой команды:
8
- 1. Создать cmd_xxx.py
9
- 2. Добавить import cmd_xxx
8
+ 1. Создать opencode_db/commands/cmd_xxx.py
9
+ 2. Добавить `from . import cmd_xxx`
10
10
  3. Добавить "xxx": cmd_xxx в COMMANDS
11
11
  """
12
12
 
13
- import cmd_costs
14
- import cmd_delete
15
- import cmd_export
16
- import cmd_help
17
- import cmd_info
18
- import cmd_list
19
- import cmd_projects
20
- import cmd_prune
21
- import cmd_search
22
- import cmd_stats
23
- import cmd_todos
24
- import cmd_tree
25
- import cmd_vacuum
26
- import cmd_view
13
+ from . import (
14
+ cmd_costs,
15
+ cmd_delete,
16
+ cmd_export,
17
+ cmd_help,
18
+ cmd_info,
19
+ cmd_list,
20
+ cmd_projects,
21
+ cmd_prune,
22
+ cmd_search,
23
+ cmd_stats,
24
+ cmd_todos,
25
+ cmd_tree,
26
+ cmd_vacuum,
27
+ cmd_view,
28
+ )
27
29
 
28
30
  # Словарь {имя_команды: модуль}
29
31
  # Модуль должен иметь register(subparsers) и run(args, db)
@@ -5,9 +5,9 @@
5
5
 
6
6
  import argparse
7
7
 
8
- from db import SessionError, get_session_info, get_session_title, parse_model
9
- from i18n import _
10
- from utils import build_help_epilog, format_cost, format_tokens
8
+ from ..db import SessionError, get_session_info, get_session_title, parse_model
9
+ from ..i18n import _
10
+ from ..utils import build_help_epilog, format_cost, format_tokens
11
11
 
12
12
  _COSTS_EXAMPLES = [
13
13
  ("", "help.costs.e0"),
@@ -57,7 +57,7 @@ def _show_session(db, session_id, as_json) -> int:
57
57
  cost = info["cost"] or 0
58
58
 
59
59
  if as_json:
60
- from formatters import print_json
60
+ from ..formatters import print_json
61
61
 
62
62
  print_json(
63
63
  {
@@ -115,7 +115,7 @@ def _show_total(db, project_id, as_json) -> int:
115
115
  total_tr = row["tr"] or 0
116
116
 
117
117
  if as_json:
118
- from formatters import print_json
118
+ from ..formatters import print_json
119
119
 
120
120
  print_json(
121
121
  {
@@ -165,7 +165,7 @@ def _show_list(db, project_id, limit, as_json) -> int:
165
165
  ).fetchall()
166
166
 
167
167
  if as_json:
168
- from formatters import print_json
168
+ from ..formatters import print_json
169
169
 
170
170
  data = []
171
171
  for r in rows:
@@ -183,7 +183,7 @@ def _show_list(db, project_id, limit, as_json) -> int:
183
183
  print_json(data)
184
184
  return 0
185
185
 
186
- from formatters import print_table_simple
186
+ from ..formatters import print_table_simple
187
187
 
188
188
  table = []
189
189
  for r in rows:
@@ -2,7 +2,7 @@
2
2
 
3
3
  import argparse
4
4
 
5
- from db import (
5
+ from ..db import (
6
6
  SessionError,
7
7
  get_message_count,
8
8
  get_part_count,
@@ -11,8 +11,8 @@ from db import (
11
11
  get_session_title,
12
12
  parse_model,
13
13
  )
14
- from i18n import _
15
- from utils import build_help_epilog, confirm, format_cost, format_ts, parse_date, parse_time_spec
14
+ from ..i18n import _
15
+ from ..utils import build_help_epilog, confirm, format_cost, format_ts, parse_date, parse_time_spec
16
16
 
17
17
  _DELETE_EXAMPLES = [
18
18
  ("<session_id>", "help.delete.e0"),
@@ -9,7 +9,7 @@
9
9
  import argparse
10
10
  import os
11
11
 
12
- from db import (
12
+ from ..db import (
13
13
  SessionError,
14
14
  get_latest_session,
15
15
  get_messages,
@@ -18,9 +18,9 @@ from db import (
18
18
  get_session_title,
19
19
  parse_model,
20
20
  )
21
- from formatters import collect_snapshot, format_part_to_md, update_log
22
- from i18n import _
23
- from utils import build_help_epilog, format_cost, format_ts, format_ts_short
21
+ from ..formatters import collect_snapshot, format_part_to_md, update_log
22
+ from ..i18n import _
23
+ from ..utils import build_help_epilog, format_cost, format_ts, format_ts_short
24
24
 
25
25
  _EXPORT_EXAMPLES = [
26
26
  ("<session_id>", "help.export.e0"),
@@ -3,8 +3,8 @@
3
3
  import argparse
4
4
  from typing import Literal
5
5
 
6
- from i18n import _
7
- from utils import build_help_epilog
6
+ from ..i18n import _
7
+ from ..utils import build_help_epilog
8
8
 
9
9
  _HELP_EXAMPLES = [
10
10
  ("", "help.help.e0"),
@@ -2,7 +2,7 @@
2
2
 
3
3
  import argparse
4
4
 
5
- from db import (
5
+ from ..db import (
6
6
  SessionError,
7
7
  get_children_sessions,
8
8
  get_message_count,
@@ -14,8 +14,8 @@ from db import (
14
14
  get_session_todos,
15
15
  parse_model,
16
16
  )
17
- from i18n import _
18
- from utils import build_help_epilog, format_cost, format_tokens, format_ts
17
+ from ..i18n import _
18
+ from ..utils import build_help_epilog, format_cost, format_tokens, format_ts
19
19
 
20
20
  _INFO_EXAMPLES = [
21
21
  ("<session_id>", "help.info.e0"),
@@ -104,7 +104,7 @@ def run(args, db) -> int:
104
104
  if parent:
105
105
  data["parent"] = {"id": parent["id"], "title": parent["title"]}
106
106
 
107
- from formatters import print_json
107
+ from ..formatters import print_json
108
108
 
109
109
  print_json(data)
110
110
  return 0
@@ -3,11 +3,11 @@
3
3
  import argparse
4
4
  from typing import Literal
5
5
 
6
- import db as db_module
7
- from db import get_session_title, parse_model
8
- from formatters import print_json, print_table_simple
9
- from i18n import _
10
- from utils import build_help_epilog, format_ts
6
+ from .. import db as db_module
7
+ from ..db import get_session_title, parse_model
8
+ from ..formatters import print_json, print_table_simple
9
+ from ..i18n import _
10
+ from ..utils import build_help_epilog, format_ts
11
11
 
12
12
  _LIST_EXAMPLES = [
13
13
  ("", "help.list.e0"),
@@ -3,8 +3,8 @@
3
3
  import argparse
4
4
  from typing import Literal
5
5
 
6
- from i18n import _
7
- from utils import build_help_epilog, format_cost, format_tokens, format_ts
6
+ from ..i18n import _
7
+ from ..utils import build_help_epilog, format_cost, format_tokens, format_ts
8
8
 
9
9
  _PROJECTS_EXAMPLES = [
10
10
  ("", "help.projects.e0"),
@@ -37,7 +37,7 @@ def run(args, db) -> Literal[0]:
37
37
  """).fetchall()
38
38
 
39
39
  if args.json:
40
- from formatters import print_json
40
+ from ..formatters import print_json
41
41
 
42
42
  data = []
43
43
  for r in rows:
@@ -59,7 +59,7 @@ def run(args, db) -> Literal[0]:
59
59
  print_json(data)
60
60
  return 0
61
61
 
62
- from formatters import print_table_simple
62
+ from ..formatters import print_table_simple
63
63
 
64
64
  table = []
65
65
  for r in rows:
@@ -2,9 +2,9 @@
2
2
 
3
3
  import argparse
4
4
 
5
- from cmd_delete import run as delete_run
6
- from i18n import _
7
- from utils import build_help_epilog
5
+ from ..i18n import _
6
+ from ..utils import build_help_epilog
7
+ from .cmd_delete import run as delete_run
8
8
 
9
9
  _PRUNE_EXAMPLES = [
10
10
  ("--older-than 90d", "help.prune.e0"),
@@ -3,9 +3,9 @@
3
3
  import argparse
4
4
  import json
5
5
 
6
- from db import SessionError, resolve_session_id
7
- from i18n import _
8
- from utils import build_help_epilog, format_ts
6
+ from ..db import SessionError, resolve_session_id
7
+ from ..i18n import _
8
+ from ..utils import build_help_epilog, format_ts
9
9
 
10
10
  _SEARCH_EXAMPLES = [
11
11
  ('"text"', "help.search.e0"),
@@ -103,7 +103,7 @@ def run(args, db) -> int:
103
103
  break
104
104
 
105
105
  if args.json:
106
- from formatters import print_json
106
+ from ..formatters import print_json
107
107
 
108
108
  print_json(results)
109
109
  return 0
@@ -3,9 +3,9 @@
3
3
  import argparse
4
4
  from typing import Literal
5
5
 
6
- from db import parse_model
7
- from i18n import _
8
- from utils import build_help_epilog, format_cost, format_tokens, format_ts
6
+ from ..db import parse_model
7
+ from ..i18n import _
8
+ from ..utils import build_help_epilog, format_cost, format_tokens, format_ts
9
9
 
10
10
  _STATS_EXAMPLES = [
11
11
  ("", "help.stats.e0"),
@@ -64,7 +64,7 @@ def run(args, db) -> Literal[0]:
64
64
  """).fetchall()
65
65
 
66
66
  if args.json:
67
- from formatters import print_json
67
+ from ..formatters import print_json
68
68
 
69
69
  data = {
70
70
  "sessions": session_count,