puenteo 0.4.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.
- puenteo-0.4.0/LICENSE +21 -0
- puenteo-0.4.0/PKG-INFO +132 -0
- puenteo-0.4.0/README.md +97 -0
- puenteo-0.4.0/puenteo/__init__.py +89 -0
- puenteo-0.4.0/puenteo/__main__.py +3 -0
- puenteo-0.4.0/puenteo/api.py +286 -0
- puenteo-0.4.0/puenteo/bootstrap.py +97 -0
- puenteo-0.4.0/puenteo/cli.py +368 -0
- puenteo-0.4.0/puenteo/exporters.py +676 -0
- puenteo-0.4.0/puenteo/extract.py +260 -0
- puenteo-0.4.0/puenteo/format.py +174 -0
- puenteo-0.4.0/puenteo/models.py +44 -0
- puenteo-0.4.0/puenteo/providers/__init__.py +105 -0
- puenteo-0.4.0/puenteo/providers/claude.py +231 -0
- puenteo-0.4.0/puenteo/providers/codex.py +223 -0
- puenteo-0.4.0/puenteo/providers/grok.py +247 -0
- puenteo-0.4.0/puenteo/providers/pi.py +184 -0
- puenteo-0.4.0/puenteo/py.typed +0 -0
- puenteo-0.4.0/puenteo/rich.py +790 -0
- puenteo-0.4.0/puenteo/search.py +174 -0
- puenteo-0.4.0/puenteo/util.py +157 -0
- puenteo-0.4.0/puenteo/version.py +2 -0
- puenteo-0.4.0/puenteo.egg-info/PKG-INFO +132 -0
- puenteo-0.4.0/puenteo.egg-info/SOURCES.txt +30 -0
- puenteo-0.4.0/puenteo.egg-info/dependency_links.txt +1 -0
- puenteo-0.4.0/puenteo.egg-info/entry_points.txt +3 -0
- puenteo-0.4.0/puenteo.egg-info/requires.txt +5 -0
- puenteo-0.4.0/puenteo.egg-info/top_level.txt +1 -0
- puenteo-0.4.0/pyproject.toml +65 -0
- puenteo-0.4.0/setup.cfg +4 -0
- puenteo-0.4.0/setup.py +3 -0
- puenteo-0.4.0/tests/test_smoke.py +103 -0
puenteo-0.4.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 mano7onam
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
puenteo-0.4.0/PKG-INFO
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: puenteo
|
|
3
|
+
Version: 0.4.0
|
|
4
|
+
Summary: Puenteo — the bridge between coding agents. List, search, and export Claude/Codex/Grok/Pi sessions to md/html/pdf/json/zip (Python library + CLI).
|
|
5
|
+
Author-email: mano7onam <mano7onamm@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/mano7onam/puenteo
|
|
8
|
+
Project-URL: Repository, https://github.com/mano7onam/puenteo
|
|
9
|
+
Project-URL: Issues, https://github.com/mano7onam/puenteo/issues
|
|
10
|
+
Project-URL: Changelog, https://github.com/mano7onam/puenteo/releases
|
|
11
|
+
Keywords: agents,bridge,puente,claude-code,codex,grok,cli,library,export,markdown,pdf,session,developer-tools
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Operating System :: MacOS
|
|
17
|
+
Classifier: Operating System :: POSIX
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
24
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
25
|
+
Classifier: Topic :: Utilities
|
|
26
|
+
Classifier: Typing :: Typed
|
|
27
|
+
Requires-Python: >=3.9
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
License-File: LICENSE
|
|
30
|
+
Provides-Extra: dev
|
|
31
|
+
Requires-Dist: pytest>=7; extra == "dev"
|
|
32
|
+
Requires-Dist: build; extra == "dev"
|
|
33
|
+
Requires-Dist: twine; extra == "dev"
|
|
34
|
+
Dynamic: license-file
|
|
35
|
+
|
|
36
|
+
# puenteo
|
|
37
|
+
|
|
38
|
+
**The bridge between coding agents.**
|
|
39
|
+
|
|
40
|
+
Python **library + CLI** to discover, search, and export local sessions from Claude Code, Codex, Grok, and Pi — to Markdown, HTML, PDF, JSON, ZIP, CSV, XML, YAML.
|
|
41
|
+
|
|
42
|
+
*Puenteo* ← Spanish *puente* (bridge) + *puentear* (to bridge / jump across).
|
|
43
|
+
|
|
44
|
+
Zero runtime dependencies · Python ≥ 3.9
|
|
45
|
+
|
|
46
|
+
[](https://pypi.org/project/puenteo/)
|
|
47
|
+
[](LICENSE)
|
|
48
|
+
|
|
49
|
+
## Install
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
pip install puenteo
|
|
53
|
+
# or
|
|
54
|
+
uv add puenteo
|
|
55
|
+
# or
|
|
56
|
+
pipx install puenteo
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
From source:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
git clone https://github.com/mano7onam/puenteo.git
|
|
63
|
+
cd puenteo
|
|
64
|
+
python3 -m venv .venv && .venv/bin/pip install -e .
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Library
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
import puenteo
|
|
71
|
+
|
|
72
|
+
print(puenteo.status())
|
|
73
|
+
|
|
74
|
+
for s in puenteo.list_sessions(limit=10):
|
|
75
|
+
print(s.provider, s.session_id[:8], s.title)
|
|
76
|
+
|
|
77
|
+
t = puenteo.load("019f7a24", include_tools=True)
|
|
78
|
+
hits = puenteo.search("gatekeeper dmg")
|
|
79
|
+
msgs = puenteo.pull("019f7a24", query="export", mode="query")
|
|
80
|
+
|
|
81
|
+
puenteo.export_session("019f7a24", fmt="md", output="chat.md")
|
|
82
|
+
puenteo.export_session("019f7a24", fmt="pdf", output="chat.pdf")
|
|
83
|
+
puenteo.export_session("019f7a24", fmt="all", output="./exports/")
|
|
84
|
+
|
|
85
|
+
data, media_type, filename = puenteo.export_bytes("019f7a24", fmt="html")
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## CLI
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
puenteo status
|
|
92
|
+
puenteo list -n 20 --json
|
|
93
|
+
puenteo list --provider claude,grok --cwd ~/dev/myapp
|
|
94
|
+
puenteo show <id> --last 40
|
|
95
|
+
puenteo search "topic" --json
|
|
96
|
+
puenteo pull <id> --query "topic" --mode query --max-chars 8000
|
|
97
|
+
puenteo export <id> -f md -o chat.md
|
|
98
|
+
puenteo export <id> -f pdf -o chat.pdf
|
|
99
|
+
puenteo export <id> -f html|json|zip|csv|xml|yaml -o …
|
|
100
|
+
puenteo export <id> -f all -o ./out/
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Short alias after install: `pto` (same as `puenteo`).
|
|
104
|
+
|
|
105
|
+
`<id>` = full uuid, **prefix**, path, or unique title substring.
|
|
106
|
+
|
|
107
|
+
## Providers
|
|
108
|
+
|
|
109
|
+
| Provider | Store |
|
|
110
|
+
|----------|--------|
|
|
111
|
+
| Claude Code | `~/.claude/projects/**/*.jsonl` |
|
|
112
|
+
| Codex | `~/.codex/sessions/**/rollout-*.jsonl` |
|
|
113
|
+
| Grok | `~/.grok/sessions/**/chat_history.jsonl` |
|
|
114
|
+
| Pi | `~/.pi/agent/sessions/**/*.jsonl` |
|
|
115
|
+
|
|
116
|
+
## Export formats
|
|
117
|
+
|
|
118
|
+
`md` · `txt` · `html` · `pdf` · `json` · `zip` · `csv` · `xml` · `yaml`
|
|
119
|
+
|
|
120
|
+
## Agent skill
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
./scripts/install_skills.sh
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Used by
|
|
127
|
+
|
|
128
|
+
[Terminal Dashboard](https://github.com/mano7onam/terminal-dashboard) imports **puenteo** for chat export (shared parsers, no duplication).
|
|
129
|
+
|
|
130
|
+
## License
|
|
131
|
+
|
|
132
|
+
MIT · [mano7onam/puenteo](https://github.com/mano7onam/puenteo)
|
puenteo-0.4.0/README.md
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# puenteo
|
|
2
|
+
|
|
3
|
+
**The bridge between coding agents.**
|
|
4
|
+
|
|
5
|
+
Python **library + CLI** to discover, search, and export local sessions from Claude Code, Codex, Grok, and Pi — to Markdown, HTML, PDF, JSON, ZIP, CSV, XML, YAML.
|
|
6
|
+
|
|
7
|
+
*Puenteo* ← Spanish *puente* (bridge) + *puentear* (to bridge / jump across).
|
|
8
|
+
|
|
9
|
+
Zero runtime dependencies · Python ≥ 3.9
|
|
10
|
+
|
|
11
|
+
[](https://pypi.org/project/puenteo/)
|
|
12
|
+
[](LICENSE)
|
|
13
|
+
|
|
14
|
+
## Install
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pip install puenteo
|
|
18
|
+
# or
|
|
19
|
+
uv add puenteo
|
|
20
|
+
# or
|
|
21
|
+
pipx install puenteo
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
From source:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
git clone https://github.com/mano7onam/puenteo.git
|
|
28
|
+
cd puenteo
|
|
29
|
+
python3 -m venv .venv && .venv/bin/pip install -e .
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Library
|
|
33
|
+
|
|
34
|
+
```python
|
|
35
|
+
import puenteo
|
|
36
|
+
|
|
37
|
+
print(puenteo.status())
|
|
38
|
+
|
|
39
|
+
for s in puenteo.list_sessions(limit=10):
|
|
40
|
+
print(s.provider, s.session_id[:8], s.title)
|
|
41
|
+
|
|
42
|
+
t = puenteo.load("019f7a24", include_tools=True)
|
|
43
|
+
hits = puenteo.search("gatekeeper dmg")
|
|
44
|
+
msgs = puenteo.pull("019f7a24", query="export", mode="query")
|
|
45
|
+
|
|
46
|
+
puenteo.export_session("019f7a24", fmt="md", output="chat.md")
|
|
47
|
+
puenteo.export_session("019f7a24", fmt="pdf", output="chat.pdf")
|
|
48
|
+
puenteo.export_session("019f7a24", fmt="all", output="./exports/")
|
|
49
|
+
|
|
50
|
+
data, media_type, filename = puenteo.export_bytes("019f7a24", fmt="html")
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## CLI
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
puenteo status
|
|
57
|
+
puenteo list -n 20 --json
|
|
58
|
+
puenteo list --provider claude,grok --cwd ~/dev/myapp
|
|
59
|
+
puenteo show <id> --last 40
|
|
60
|
+
puenteo search "topic" --json
|
|
61
|
+
puenteo pull <id> --query "topic" --mode query --max-chars 8000
|
|
62
|
+
puenteo export <id> -f md -o chat.md
|
|
63
|
+
puenteo export <id> -f pdf -o chat.pdf
|
|
64
|
+
puenteo export <id> -f html|json|zip|csv|xml|yaml -o …
|
|
65
|
+
puenteo export <id> -f all -o ./out/
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Short alias after install: `pto` (same as `puenteo`).
|
|
69
|
+
|
|
70
|
+
`<id>` = full uuid, **prefix**, path, or unique title substring.
|
|
71
|
+
|
|
72
|
+
## Providers
|
|
73
|
+
|
|
74
|
+
| Provider | Store |
|
|
75
|
+
|----------|--------|
|
|
76
|
+
| Claude Code | `~/.claude/projects/**/*.jsonl` |
|
|
77
|
+
| Codex | `~/.codex/sessions/**/rollout-*.jsonl` |
|
|
78
|
+
| Grok | `~/.grok/sessions/**/chat_history.jsonl` |
|
|
79
|
+
| Pi | `~/.pi/agent/sessions/**/*.jsonl` |
|
|
80
|
+
|
|
81
|
+
## Export formats
|
|
82
|
+
|
|
83
|
+
`md` · `txt` · `html` · `pdf` · `json` · `zip` · `csv` · `xml` · `yaml`
|
|
84
|
+
|
|
85
|
+
## Agent skill
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
./scripts/install_skills.sh
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Used by
|
|
92
|
+
|
|
93
|
+
[Terminal Dashboard](https://github.com/mano7onam/terminal-dashboard) imports **puenteo** for chat export (shared parsers, no duplication).
|
|
94
|
+
|
|
95
|
+
## License
|
|
96
|
+
|
|
97
|
+
MIT · [mano7onam/puenteo](https://github.com/mano7onam/puenteo)
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Puenteo — the bridge between coding agents.
|
|
3
|
+
|
|
4
|
+
Install::
|
|
5
|
+
|
|
6
|
+
pip install puenteo
|
|
7
|
+
# CLI:
|
|
8
|
+
puenteo list
|
|
9
|
+
puenteo export <session_id> -f md -o chat.md
|
|
10
|
+
|
|
11
|
+
Library::
|
|
12
|
+
|
|
13
|
+
import puenteo
|
|
14
|
+
|
|
15
|
+
print(puenteo.status())
|
|
16
|
+
for s in puenteo.list_sessions(limit=10):
|
|
17
|
+
print(s.provider, s.session_id[:8], s.title)
|
|
18
|
+
|
|
19
|
+
puenteo.export_session("019f7a24", fmt="pdf", output="chat.pdf")
|
|
20
|
+
hits = puenteo.search("export markdown")
|
|
21
|
+
msgs = puenteo.pull("019f7a24", query="dmg", mode="query")
|
|
22
|
+
|
|
23
|
+
Providers: Claude Code, Codex, Grok, Pi.
|
|
24
|
+
Formats: md, txt, html, pdf, json, zip, csv, xml, yaml.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
from .api import ( # noqa: F401
|
|
28
|
+
APP_NAME,
|
|
29
|
+
SUPPORTED_FORMATS,
|
|
30
|
+
Attachment,
|
|
31
|
+
Hit,
|
|
32
|
+
Message,
|
|
33
|
+
PROVIDER_NAMES,
|
|
34
|
+
RichMessage,
|
|
35
|
+
RichTranscript,
|
|
36
|
+
Session,
|
|
37
|
+
Transcript,
|
|
38
|
+
clipboard_text,
|
|
39
|
+
export_bytes,
|
|
40
|
+
export_session,
|
|
41
|
+
find_best_agent_transcript,
|
|
42
|
+
get_session,
|
|
43
|
+
list_sessions,
|
|
44
|
+
list_sources_for_cwd,
|
|
45
|
+
load,
|
|
46
|
+
load_rich_transcript,
|
|
47
|
+
load_transcript,
|
|
48
|
+
pull,
|
|
49
|
+
render,
|
|
50
|
+
resolve_session,
|
|
51
|
+
search,
|
|
52
|
+
search_all,
|
|
53
|
+
search_transcript,
|
|
54
|
+
smart_pull,
|
|
55
|
+
status,
|
|
56
|
+
)
|
|
57
|
+
from .version import __version__
|
|
58
|
+
|
|
59
|
+
__all__ = [
|
|
60
|
+
"APP_NAME",
|
|
61
|
+
"SUPPORTED_FORMATS",
|
|
62
|
+
"Attachment",
|
|
63
|
+
"Hit",
|
|
64
|
+
"Message",
|
|
65
|
+
"PROVIDER_NAMES",
|
|
66
|
+
"RichMessage",
|
|
67
|
+
"RichTranscript",
|
|
68
|
+
"Session",
|
|
69
|
+
"Transcript",
|
|
70
|
+
"__version__",
|
|
71
|
+
"clipboard_text",
|
|
72
|
+
"export_bytes",
|
|
73
|
+
"export_session",
|
|
74
|
+
"find_best_agent_transcript",
|
|
75
|
+
"get_session",
|
|
76
|
+
"list_sessions",
|
|
77
|
+
"list_sources_for_cwd",
|
|
78
|
+
"load",
|
|
79
|
+
"load_rich_transcript",
|
|
80
|
+
"load_transcript",
|
|
81
|
+
"pull",
|
|
82
|
+
"render",
|
|
83
|
+
"resolve_session",
|
|
84
|
+
"search",
|
|
85
|
+
"search_all",
|
|
86
|
+
"search_transcript",
|
|
87
|
+
"smart_pull",
|
|
88
|
+
"status",
|
|
89
|
+
]
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Public library API for Puenteo.
|
|
3
|
+
|
|
4
|
+
Prefer importing from the package root::
|
|
5
|
+
|
|
6
|
+
import puenteo
|
|
7
|
+
|
|
8
|
+
sessions = puenteo.list_sessions(limit=20)
|
|
9
|
+
path = puenteo.export_session(sessions[0].session_id, fmt="md", output="chat.md")
|
|
10
|
+
hits = puenteo.search("gatekeeper")
|
|
11
|
+
pack = puenteo.pull(sessions[0].session_id, query="dmg", mode="query")
|
|
12
|
+
|
|
13
|
+
CLI is the same package: ``puenteo`` / ``pto`` / ``python -m puenteo``.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
import os
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
from typing import Any, Dict, List, Optional, Sequence, Union
|
|
21
|
+
|
|
22
|
+
from .exporters import SUPPORTED_FORMATS, clipboard_text, render
|
|
23
|
+
from .extract import smart_pull
|
|
24
|
+
from .models import Message, Session, Transcript
|
|
25
|
+
from .providers import PROVIDER_NAMES, list_sessions, load_transcript, resolve_session
|
|
26
|
+
from .rich import (
|
|
27
|
+
find_best_agent_transcript,
|
|
28
|
+
list_sources_for_cwd,
|
|
29
|
+
load_transcript as load_rich_transcript,
|
|
30
|
+
)
|
|
31
|
+
from .search import Hit, search_all, search_transcript
|
|
32
|
+
from .version import APP_NAME, __version__
|
|
33
|
+
|
|
34
|
+
# Re-export rich models for export consumers (Terminal Dashboard, etc.)
|
|
35
|
+
from .rich import Attachment, Message as RichMessage, Transcript as RichTranscript
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def status() -> Dict[str, Any]:
|
|
39
|
+
"""Discover which agent stores exist and how many sessions each has."""
|
|
40
|
+
from pathlib import Path as P
|
|
41
|
+
|
|
42
|
+
homes = {
|
|
43
|
+
"claude_code": P.home() / ".claude" / "projects",
|
|
44
|
+
"codex": P.home() / ".codex" / "sessions",
|
|
45
|
+
"grok": P.home() / ".grok" / "sessions",
|
|
46
|
+
"pi": P.home() / ".pi" / "agent" / "sessions",
|
|
47
|
+
}
|
|
48
|
+
providers: Dict[str, Any] = {}
|
|
49
|
+
for name, path in homes.items():
|
|
50
|
+
exists = path.is_dir()
|
|
51
|
+
count = 0
|
|
52
|
+
if exists:
|
|
53
|
+
try:
|
|
54
|
+
count = len(list_sessions(providers=[name], limit=500))
|
|
55
|
+
except Exception:
|
|
56
|
+
count = 0
|
|
57
|
+
providers[name] = {
|
|
58
|
+
"path": str(path),
|
|
59
|
+
"exists": exists,
|
|
60
|
+
"sessions": count,
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
"name": APP_NAME,
|
|
64
|
+
"version": __version__,
|
|
65
|
+
"role": "library+cli",
|
|
66
|
+
"providers": providers,
|
|
67
|
+
"export_formats": list(SUPPORTED_FORMATS),
|
|
68
|
+
"provider_names": list(PROVIDER_NAMES),
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def get_session(
|
|
73
|
+
ref: str,
|
|
74
|
+
*,
|
|
75
|
+
providers: Optional[Sequence[str]] = None,
|
|
76
|
+
cwd: Optional[str] = None,
|
|
77
|
+
) -> Optional[Session]:
|
|
78
|
+
"""Resolve a session by id prefix, path, or title substring."""
|
|
79
|
+
prov = list(providers) if providers else None
|
|
80
|
+
return resolve_session(ref, providers=prov, cwd=cwd)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def load(
|
|
84
|
+
ref: Union[str, Session],
|
|
85
|
+
*,
|
|
86
|
+
rich: bool = True,
|
|
87
|
+
include_tools: bool = False,
|
|
88
|
+
include_thinking: bool = False,
|
|
89
|
+
providers: Optional[Sequence[str]] = None,
|
|
90
|
+
cwd: Optional[str] = None,
|
|
91
|
+
) -> Union[Transcript, RichTranscript]:
|
|
92
|
+
"""
|
|
93
|
+
Load a session transcript.
|
|
94
|
+
|
|
95
|
+
- ``rich=True`` (default): full export model (tools, attachments) via ``rich`` loaders
|
|
96
|
+
- ``rich=False``: lightweight messages for search / pull
|
|
97
|
+
"""
|
|
98
|
+
sess = ref if isinstance(ref, Session) else get_session(ref, providers=providers, cwd=cwd)
|
|
99
|
+
if not sess:
|
|
100
|
+
raise LookupError(f"Session not found: {ref!r}")
|
|
101
|
+
if rich:
|
|
102
|
+
return load_rich_transcript(
|
|
103
|
+
sess.provider,
|
|
104
|
+
sess.path,
|
|
105
|
+
include_tools=include_tools,
|
|
106
|
+
include_thinking=include_thinking,
|
|
107
|
+
)
|
|
108
|
+
return load_transcript(sess, include_tools=include_tools)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def search(
|
|
112
|
+
query: str,
|
|
113
|
+
*,
|
|
114
|
+
session: Optional[str] = None,
|
|
115
|
+
providers: Optional[Sequence[str]] = None,
|
|
116
|
+
cwd: Optional[str] = None,
|
|
117
|
+
limit: int = 20,
|
|
118
|
+
session_limit: int = 40,
|
|
119
|
+
) -> List[Hit]:
|
|
120
|
+
"""Search message text across sessions (or one session)."""
|
|
121
|
+
prov = list(providers) if providers else None
|
|
122
|
+
if session:
|
|
123
|
+
sess = get_session(session, providers=prov, cwd=cwd)
|
|
124
|
+
if not sess:
|
|
125
|
+
return []
|
|
126
|
+
tr = load_transcript(sess)
|
|
127
|
+
return search_transcript(tr, query, limit=limit)
|
|
128
|
+
return search_all(
|
|
129
|
+
query,
|
|
130
|
+
providers=prov,
|
|
131
|
+
cwd=cwd,
|
|
132
|
+
session_limit=session_limit,
|
|
133
|
+
hit_limit=limit,
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def pull(
|
|
138
|
+
ref: Union[str, Session],
|
|
139
|
+
*,
|
|
140
|
+
query: Optional[str] = None,
|
|
141
|
+
mode: str = "auto",
|
|
142
|
+
last: int = 0,
|
|
143
|
+
max_chars: int = 12000,
|
|
144
|
+
max_messages: int = 30,
|
|
145
|
+
include_tools: bool = False,
|
|
146
|
+
providers: Optional[Sequence[str]] = None,
|
|
147
|
+
cwd: Optional[str] = None,
|
|
148
|
+
) -> List[Message]:
|
|
149
|
+
"""Build a compact message pack for another agent (same as ``puenteo pull``)."""
|
|
150
|
+
sess = ref if isinstance(ref, Session) else get_session(ref, providers=providers, cwd=cwd)
|
|
151
|
+
if not sess:
|
|
152
|
+
raise LookupError(f"Session not found: {ref!r}")
|
|
153
|
+
tr = load_transcript(sess, include_tools=include_tools)
|
|
154
|
+
return smart_pull(
|
|
155
|
+
tr,
|
|
156
|
+
query=query,
|
|
157
|
+
mode=mode,
|
|
158
|
+
last=last,
|
|
159
|
+
max_chars=max_chars,
|
|
160
|
+
max_messages=max_messages,
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def export_session(
|
|
165
|
+
ref: Union[str, Session],
|
|
166
|
+
*,
|
|
167
|
+
fmt: str = "md",
|
|
168
|
+
output: Optional[Union[str, Path]] = None,
|
|
169
|
+
include_tools: bool = False,
|
|
170
|
+
include_thinking: bool = False,
|
|
171
|
+
providers: Optional[Sequence[str]] = None,
|
|
172
|
+
cwd: Optional[str] = None,
|
|
173
|
+
) -> Path:
|
|
174
|
+
"""
|
|
175
|
+
Export a full transcript to a file.
|
|
176
|
+
|
|
177
|
+
``fmt``: md | txt | html | pdf | json | zip | csv | xml | yaml | all
|
|
178
|
+
|
|
179
|
+
Returns the primary written path (or directory when ``fmt=all``).
|
|
180
|
+
"""
|
|
181
|
+
sess = ref if isinstance(ref, Session) else get_session(ref, providers=providers, cwd=cwd)
|
|
182
|
+
if not sess:
|
|
183
|
+
raise LookupError(f"Session not found: {ref!r}")
|
|
184
|
+
|
|
185
|
+
rich_tr = load_rich_transcript(
|
|
186
|
+
sess.provider,
|
|
187
|
+
sess.path,
|
|
188
|
+
include_tools=include_tools,
|
|
189
|
+
include_thinking=include_thinking,
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
fmt_arg = (fmt or "md").lower().strip()
|
|
193
|
+
formats = list(SUPPORTED_FORMATS) if fmt_arg == "all" else [fmt_arg]
|
|
194
|
+
out = Path(os.path.expanduser(str(output))).resolve() if output else None
|
|
195
|
+
|
|
196
|
+
written: List[Path] = []
|
|
197
|
+
for f in formats:
|
|
198
|
+
data, _media, filename = render(
|
|
199
|
+
rich_tr,
|
|
200
|
+
f,
|
|
201
|
+
include_tools=include_tools,
|
|
202
|
+
include_thinking=include_thinking,
|
|
203
|
+
)
|
|
204
|
+
if out is None:
|
|
205
|
+
path = Path.cwd() / filename
|
|
206
|
+
elif out.is_dir() or fmt_arg == "all" or (out.suffix == "" and len(formats) > 1):
|
|
207
|
+
out.mkdir(parents=True, exist_ok=True)
|
|
208
|
+
path = out / filename if out.is_dir() or out.suffix == "" else out
|
|
209
|
+
if out.suffix == "" and not out.is_dir():
|
|
210
|
+
# treat as directory path to create
|
|
211
|
+
out.mkdir(parents=True, exist_ok=True)
|
|
212
|
+
path = out / filename
|
|
213
|
+
else:
|
|
214
|
+
path = out
|
|
215
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
216
|
+
|
|
217
|
+
path.write_bytes(data)
|
|
218
|
+
written.append(path)
|
|
219
|
+
|
|
220
|
+
if not written:
|
|
221
|
+
raise RuntimeError("Nothing exported")
|
|
222
|
+
return written[0] if len(written) == 1 else (out if out and out.is_dir() else written[0].parent)
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def export_bytes(
|
|
226
|
+
ref: Union[str, Session],
|
|
227
|
+
*,
|
|
228
|
+
fmt: str = "md",
|
|
229
|
+
include_tools: bool = False,
|
|
230
|
+
include_thinking: bool = False,
|
|
231
|
+
providers: Optional[Sequence[str]] = None,
|
|
232
|
+
cwd: Optional[str] = None,
|
|
233
|
+
) -> tuple:
|
|
234
|
+
"""
|
|
235
|
+
Export without writing a file.
|
|
236
|
+
|
|
237
|
+
Returns ``(data: bytes, media_type: str, filename: str)``.
|
|
238
|
+
"""
|
|
239
|
+
sess = ref if isinstance(ref, Session) else get_session(ref, providers=providers, cwd=cwd)
|
|
240
|
+
if not sess:
|
|
241
|
+
raise LookupError(f"Session not found: {ref!r}")
|
|
242
|
+
rich_tr = load_rich_transcript(
|
|
243
|
+
sess.provider,
|
|
244
|
+
sess.path,
|
|
245
|
+
include_tools=include_tools,
|
|
246
|
+
include_thinking=include_thinking,
|
|
247
|
+
)
|
|
248
|
+
return render(
|
|
249
|
+
rich_tr,
|
|
250
|
+
fmt,
|
|
251
|
+
include_tools=include_tools,
|
|
252
|
+
include_thinking=include_thinking,
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
__all__ = [
|
|
257
|
+
"APP_NAME",
|
|
258
|
+
"SUPPORTED_FORMATS",
|
|
259
|
+
"Attachment",
|
|
260
|
+
"Hit",
|
|
261
|
+
"Message",
|
|
262
|
+
"PROVIDER_NAMES",
|
|
263
|
+
"RichMessage",
|
|
264
|
+
"RichTranscript",
|
|
265
|
+
"Session",
|
|
266
|
+
"Transcript",
|
|
267
|
+
"__version__",
|
|
268
|
+
"clipboard_text",
|
|
269
|
+
"export_bytes",
|
|
270
|
+
"export_session",
|
|
271
|
+
"find_best_agent_transcript",
|
|
272
|
+
"get_session",
|
|
273
|
+
"list_sessions",
|
|
274
|
+
"list_sources_for_cwd",
|
|
275
|
+
"load",
|
|
276
|
+
"load_rich_transcript",
|
|
277
|
+
"load_transcript",
|
|
278
|
+
"pull",
|
|
279
|
+
"render",
|
|
280
|
+
"resolve_session",
|
|
281
|
+
"search",
|
|
282
|
+
"search_all",
|
|
283
|
+
"search_transcript",
|
|
284
|
+
"smart_pull",
|
|
285
|
+
"status",
|
|
286
|
+
]
|