@alexzeitler/session-md 0.5.0
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.
- package/LICENSE +21 -0
- package/README.md +187 -0
- package/package.json +20 -0
- package/session-md +49 -0
- package/src/app.ts +603 -0
- package/src/components/ConversationList.ts +243 -0
- package/src/components/MessageView.ts +241 -0
- package/src/components/SearchResultsView.ts +146 -0
- package/src/components/SourcePicker.ts +87 -0
- package/src/components/StatusBar.ts +70 -0
- package/src/components/TargetPicker.ts +174 -0
- package/src/config.ts +85 -0
- package/src/file-ops.ts +23 -0
- package/src/import/claude-code-to-md.ts +184 -0
- package/src/import/claude-export-to-md.ts +122 -0
- package/src/import/loader.ts +86 -0
- package/src/import/memorizer-to-md.ts +117 -0
- package/src/import/opencode-to-md.ts +176 -0
- package/src/import/parse-worker.ts +28 -0
- package/src/import/types.ts +56 -0
- package/src/index.ts +282 -0
- package/src/mcp/http.ts +264 -0
- package/src/mcp/server.ts +330 -0
- package/src/search/index.ts +235 -0
- package/src/search/plaintext.ts +47 -0
- package/src/theme.ts +111 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Alexander Zeitler
|
|
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.
|
package/README.md
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# session-md
|
|
2
|
+
|
|
3
|
+
A terminal UI for browsing and managing AI chat sessions from multiple sources - Claude Code, Claude.ai exports, OpenCode, and Memorizer.
|
|
4
|
+
|
|
5
|
+
Built with [Bun](https://bun.sh), [OpenTUI](https://github.com/anomalyco/opentui), and TypeScript.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- Browse sessions from 4 sources in a single TUI
|
|
10
|
+
- Filter sessions by source and text search
|
|
11
|
+
- **Full-text content search** (`g`) with SQLite FTS5 index
|
|
12
|
+
- Multi-select sessions and copy as Markdown to target folders
|
|
13
|
+
- Markdown preview with syntax highlighting
|
|
14
|
+
- Configurable targets for organizing exported sessions
|
|
15
|
+
- Incremental search index - only new/changed sessions are re-indexed on startup
|
|
16
|
+
|
|
17
|
+
## Supported Sources
|
|
18
|
+
|
|
19
|
+
| Source | Format | Location |
|
|
20
|
+
|--------|--------|----------|
|
|
21
|
+
| [**Claude Code**](https://docs.anthropic.com/en/docs/claude-code) | JSONL | `~/.claude/projects/**/*.jsonl` |
|
|
22
|
+
| [**Claude.ai**](https://claude.ai) Export | ZIP / `conversations.json` | Configurable path |
|
|
23
|
+
| [**OpenCode**](https://github.com/anomalyco/opencode) | JSON shards | `~/.local/share/opencode/storage/` |
|
|
24
|
+
| [**Memorizer**](https://github.com/petabridge/memorizer) | REST API | Configurable URL |
|
|
25
|
+
|
|
26
|
+
## Install
|
|
27
|
+
|
|
28
|
+
### Global (recommended)
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
bun install -g @alexzeitler/session-md
|
|
32
|
+
session-md
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### From source
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
git clone https://github.com/AlexZeitler/session-md.git
|
|
39
|
+
cd session-md
|
|
40
|
+
bun install
|
|
41
|
+
bun src/index.ts
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Update
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
session-md update
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Version
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
session-md --version
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Configuration
|
|
57
|
+
|
|
58
|
+
Config file: `~/.config/session-md/config.toml`
|
|
59
|
+
|
|
60
|
+
A default config is created on first run.
|
|
61
|
+
|
|
62
|
+
```toml
|
|
63
|
+
default_target = "~/notes/claude-chats"
|
|
64
|
+
|
|
65
|
+
[targets]
|
|
66
|
+
vault = "~/notes/claude-chats"
|
|
67
|
+
work = "~/work/claude-sessions"
|
|
68
|
+
archive = "~/archive/claude"
|
|
69
|
+
|
|
70
|
+
[sources]
|
|
71
|
+
claude_code = "~/.claude/projects"
|
|
72
|
+
opencode = "~/.local/share/opencode/storage"
|
|
73
|
+
# claude_export = "~/Downloads/conversations.zip"
|
|
74
|
+
# memorizer_url = "http://localhost:5001"
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Keyboard Shortcuts
|
|
78
|
+
|
|
79
|
+
### Navigation
|
|
80
|
+
|
|
81
|
+
| Key | Action |
|
|
82
|
+
|-----|--------|
|
|
83
|
+
| `Tab` | Cycle focus: Sources → Sessions → Detail |
|
|
84
|
+
| `Shift+Tab` | Cycle focus backward |
|
|
85
|
+
| `j` / `k` | Navigate list / scroll detail |
|
|
86
|
+
| `gg` | Jump to top (list or detail) |
|
|
87
|
+
| `G` | Jump to bottom (list or detail) |
|
|
88
|
+
| `Ctrl+d` / `Ctrl+u` | Page down / up in detail |
|
|
89
|
+
| `Esc` | Back to sessions from detail |
|
|
90
|
+
|
|
91
|
+
### Sessions
|
|
92
|
+
|
|
93
|
+
| Key | Action |
|
|
94
|
+
|-----|--------|
|
|
95
|
+
| `Space` | Toggle selection |
|
|
96
|
+
| `/` | Open text filter |
|
|
97
|
+
| `g` | Full-text content search (grep) |
|
|
98
|
+
| `c` | Copy selected sessions to target |
|
|
99
|
+
| `q` | Quit |
|
|
100
|
+
|
|
101
|
+
### Filter (`/`)
|
|
102
|
+
|
|
103
|
+
| Key | Action |
|
|
104
|
+
|-----|--------|
|
|
105
|
+
| Type | Filter sessions by title/project |
|
|
106
|
+
| `Enter` | Move to filtered results (filter stays active) |
|
|
107
|
+
| `/` | Return to filter input |
|
|
108
|
+
| `Esc` | Close filter |
|
|
109
|
+
|
|
110
|
+
### Content Search (`g`)
|
|
111
|
+
|
|
112
|
+
| Key | Action |
|
|
113
|
+
|-----|--------|
|
|
114
|
+
| Type | Search within session content (FTS5) |
|
|
115
|
+
| `Enter` | Move to results / open selected result |
|
|
116
|
+
| `/` | Return to search input |
|
|
117
|
+
| `Esc` | Close search |
|
|
118
|
+
|
|
119
|
+
Content search uses a SQLite FTS5 index stored at `~/.config/session-md/search-index.sqlite`. The index is built incrementally on startup - only new or changed sessions are indexed.
|
|
120
|
+
|
|
121
|
+
To rebuild the index from scratch:
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
session-md reindex
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## MCP Server
|
|
128
|
+
|
|
129
|
+
session-md can run as an [MCP](https://modelcontextprotocol.io/) server, exposing session search and retrieval to AI assistants like Claude Code.
|
|
130
|
+
|
|
131
|
+
### Stdio Transport
|
|
132
|
+
|
|
133
|
+
For direct integration with Claude Code:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
session-md mcp
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Add to your Claude Code MCP config:
|
|
140
|
+
|
|
141
|
+
```json
|
|
142
|
+
{
|
|
143
|
+
"mcpServers": {
|
|
144
|
+
"session-md": {
|
|
145
|
+
"command": "session-md",
|
|
146
|
+
"args": ["mcp"]
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### HTTP Transport
|
|
153
|
+
|
|
154
|
+
Foreground:
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
session-md mcp --http # default port 8282
|
|
158
|
+
session-md mcp --http --port 9000 # custom port
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Daemon (background):
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
session-md mcp --http --daemon
|
|
165
|
+
session-md mcp stop
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Daemon logs: `~/.cache/session-md/mcp.log`
|
|
169
|
+
|
|
170
|
+
Health check: `GET http://localhost:8282/health`
|
|
171
|
+
|
|
172
|
+
### MCP Tools
|
|
173
|
+
|
|
174
|
+
| Tool | Description |
|
|
175
|
+
|------|-------------|
|
|
176
|
+
| `search_sessions` | Full-text search across all indexed sessions |
|
|
177
|
+
| `list_sessions` | List sessions, optionally filtered by source |
|
|
178
|
+
| `get_session` | Retrieve full Markdown content of a session by ID |
|
|
179
|
+
| `import_sessions` | Re-scan all configured sources and update the index |
|
|
180
|
+
|
|
181
|
+
## Requirements
|
|
182
|
+
|
|
183
|
+
- [Bun](https://bun.sh) >= 1.0
|
|
184
|
+
|
|
185
|
+
## License
|
|
186
|
+
|
|
187
|
+
MIT
|
package/package.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@alexzeitler/session-md",
|
|
3
|
+
"version": "0.5.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"files": ["src", "session-md"],
|
|
6
|
+
"bin": {
|
|
7
|
+
"session-md": "./session-md"
|
|
8
|
+
},
|
|
9
|
+
"devDependencies": {
|
|
10
|
+
"@types/bun": "latest"
|
|
11
|
+
},
|
|
12
|
+
"peerDependencies": {
|
|
13
|
+
"typescript": "^5"
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@modelcontextprotocol/sdk": "^1.28.0",
|
|
17
|
+
"@opentui/core": "^0.1.79",
|
|
18
|
+
"smol-toml": "^1.3.1"
|
|
19
|
+
}
|
|
20
|
+
}
|
package/session-md
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# session-md - TUI for AI chat history management
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
find_bun() {
|
|
6
|
+
if command -v bun &>/dev/null; then
|
|
7
|
+
local ver=$(bun --version 2>/dev/null || echo "0")
|
|
8
|
+
if [[ "$ver" =~ ^1\. ]]; then
|
|
9
|
+
command -v bun
|
|
10
|
+
return 0
|
|
11
|
+
fi
|
|
12
|
+
fi
|
|
13
|
+
|
|
14
|
+
: "${HOME:=$(eval echo ~)}"
|
|
15
|
+
|
|
16
|
+
if [[ "${BASH_SOURCE[0]}" == */.bun/* ]]; then
|
|
17
|
+
local bun_home="${BASH_SOURCE[0]%%/.bun/*}/.bun"
|
|
18
|
+
if [[ -x "$bun_home/bin/bun" ]]; then
|
|
19
|
+
echo "$bun_home/bin/bun"
|
|
20
|
+
return 0
|
|
21
|
+
fi
|
|
22
|
+
fi
|
|
23
|
+
|
|
24
|
+
local candidates=(
|
|
25
|
+
"$HOME/.local/share/mise/installs/bun/latest/bin/bun"
|
|
26
|
+
"$HOME/.local/share/mise/shims/bun"
|
|
27
|
+
"$HOME/.asdf/shims/bun"
|
|
28
|
+
"/opt/homebrew/bin/bun"
|
|
29
|
+
"/usr/local/bin/bun"
|
|
30
|
+
"$HOME/.bun/bin/bun"
|
|
31
|
+
)
|
|
32
|
+
for c in "${candidates[@]}"; do
|
|
33
|
+
[[ -x "$c" ]] && { echo "$c"; return 0; }
|
|
34
|
+
done
|
|
35
|
+
|
|
36
|
+
return 1
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
BUN=$(find_bun) || { echo "Error: bun not found. Install from https://bun.sh" >&2; exit 1; }
|
|
40
|
+
|
|
41
|
+
SOURCE="${BASH_SOURCE[0]}"
|
|
42
|
+
while [[ -L "$SOURCE" ]]; do
|
|
43
|
+
DIR="$(cd -P "$(dirname "$SOURCE")" && pwd)"
|
|
44
|
+
SOURCE="$(readlink "$SOURCE")"
|
|
45
|
+
[[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE"
|
|
46
|
+
done
|
|
47
|
+
SCRIPT_DIR="$(cd -P "$(dirname "$SOURCE")" && pwd)"
|
|
48
|
+
|
|
49
|
+
exec "$BUN" "$SCRIPT_DIR/src/index.ts" "$@"
|