ai-tabs 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.
- ai_tabs-0.1.0/LICENSE +21 -0
- ai_tabs-0.1.0/PKG-INFO +192 -0
- ai_tabs-0.1.0/README.md +167 -0
- ai_tabs-0.1.0/pyproject.toml +68 -0
- ai_tabs-0.1.0/pyproject.toml.orig +54 -0
- ai_tabs-0.1.0/src/ai_tabs/__init__.py +5 -0
- ai_tabs-0.1.0/src/ai_tabs/__main__.py +5 -0
- ai_tabs-0.1.0/src/ai_tabs/agents.py +189 -0
- ai_tabs-0.1.0/src/ai_tabs/assets/logo.png +0 -0
- ai_tabs-0.1.0/src/ai_tabs/cli.py +360 -0
- ai_tabs-0.1.0/src/ai_tabs/config.py +195 -0
- ai_tabs-0.1.0/src/ai_tabs/diff.py +37 -0
- ai_tabs-0.1.0/src/ai_tabs/display.py +94 -0
- ai_tabs-0.1.0/src/ai_tabs/iterm.py +106 -0
- ai_tabs-0.1.0/src/ai_tabs/logo.py +38 -0
- ai_tabs-0.1.0/src/ai_tabs/markdown.py +99 -0
- ai_tabs-0.1.0/src/ai_tabs/models.py +102 -0
- ai_tabs-0.1.0/src/ai_tabs/opener.py +294 -0
- ai_tabs-0.1.0/src/ai_tabs/palette.py +60 -0
- ai_tabs-0.1.0/src/ai_tabs/plan.py +100 -0
- ai_tabs-0.1.0/src/ai_tabs/screen.py +51 -0
- ai_tabs-0.1.0/src/ai_tabs/snapshot.py +71 -0
- ai_tabs-0.1.0/src/ai_tabs/store.py +189 -0
- ai_tabs-0.1.0/src/ai_tabs/system.py +24 -0
- ai_tabs-0.1.0/src/ai_tabs/tui.py +449 -0
ai_tabs-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Carlo Bertini
|
|
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.
|
ai_tabs-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ai-tabs
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Save and restore iTerm2 tabs with their omp and Claude Code sessions.
|
|
5
|
+
Keywords: iterm2,claude-code,omp,terminal,session-restore
|
|
6
|
+
Author: Carlo Bertini
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Classifier: Environment :: Console
|
|
10
|
+
Classifier: Environment :: MacOS X
|
|
11
|
+
Classifier: Operating System :: MacOS
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
14
|
+
Classifier: Topic :: Terminals
|
|
15
|
+
Requires-Dist: iterm2>=2.30
|
|
16
|
+
Requires-Dist: rich>=15.0
|
|
17
|
+
Requires-Dist: textual>=8.2
|
|
18
|
+
Requires-Dist: typer>=0.27
|
|
19
|
+
Requires-Dist: websockets
|
|
20
|
+
Requires-Python: >=3.15
|
|
21
|
+
Project-URL: Homepage, https://github.com/WaYdotNET/ai-tabs
|
|
22
|
+
Project-URL: Issues, https://github.com/WaYdotNET/ai-tabs/issues
|
|
23
|
+
Project-URL: Changelog, https://github.com/WaYdotNET/ai-tabs/blob/main/CHANGELOG.md
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
<p align="center"><img src="src/ai_tabs/assets/logo.png" alt="ai-tabs" width="360"></p>
|
|
27
|
+
|
|
28
|
+
# ai-tabs
|
|
29
|
+
|
|
30
|
+
`ai-tabs` saves your iTerm2 tabs, and the omp and Claude Code sessions in them. After a reboot or a crash, it opens the tabs again and resumes each agent session.
|
|
31
|
+
|
|
32
|
+
- It takes a snapshot every 5 minutes through the iTerm2 Python API. A snapshot holds the windows, the tab order, titles and colors, the split layout, the iTerm2 profile of each pane, and the agent session in each pane.
|
|
33
|
+
- It keeps the snapshots in a SQLite database for 30 days. It pins the last snapshot before a reboot, or before many tabs close at once. The history never deletes pinned snapshots.
|
|
34
|
+
- A terminal screen lets you pick a snapshot and the tabs to open again.
|
|
35
|
+
- It can also export the snapshots as Markdown files, for example into an Obsidian vault.
|
|
36
|
+
|
|
37
|
+
## Requirements
|
|
38
|
+
|
|
39
|
+
- macOS with [iTerm2](https://iterm2.com) 3.5 or later.
|
|
40
|
+
- The iTerm2 Python API: open **iTerm2 › Settings › General › Magic** and select **Enable Python API**.
|
|
41
|
+
- [uv](https://docs.astral.sh/uv/). uv installs Python 3.15 for `ai-tabs` when it is necessary.
|
|
42
|
+
- Optional: [iTerm2 shell integration](https://iterm2.com/documentation-shell-integration.html). With it, `ai-tabs` waits for the shell prompt before it types the resume command.
|
|
43
|
+
|
|
44
|
+
## Install
|
|
45
|
+
|
|
46
|
+
To run the tool without an install:
|
|
47
|
+
|
|
48
|
+
```sh
|
|
49
|
+
uvx ai-tabs
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
To install it, so that the launchd agent has a stable path:
|
|
53
|
+
|
|
54
|
+
```sh
|
|
55
|
+
uv tool install ai-tabs
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
To install the latest `main` branch from GitHub:
|
|
59
|
+
|
|
60
|
+
```sh
|
|
61
|
+
uv tool install git+https://github.com/WaYdotNET/ai-tabs
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Then start the snapshots. This command loads a launchd agent that runs `ai-tabs snapshot` at login and every `snapshot_interval` seconds (default 300):
|
|
65
|
+
|
|
66
|
+
```sh
|
|
67
|
+
ai-tabs install
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
To stop the snapshots, run `ai-tabs uninstall`. The database, the backups and the configuration stay.
|
|
71
|
+
|
|
72
|
+
## Use
|
|
73
|
+
|
|
74
|
+
Run `ai-tabs` without a command to open the restore screen. In iTerm2, the logo shows for a moment first (setting `splash`):
|
|
75
|
+
|
|
76
|
+
- The screen uses the colors of the logo, in a dark and a light theme. The `theme` setting chooses one, and `auto` (the default) follows the macOS appearance. Press `t` to switch: it saves the choice as `theme = "dark"` or `theme = "light"` in the configuration file. The top bar shows the small logo. Press `?` for the list of all the keys.
|
|
77
|
+
- The left panel shows the snapshots, newest first. 📌 marks a pinned snapshot. A gold line shows how many panes opened and closed.
|
|
78
|
+
- The right panel shows the tabs of the selected snapshot. A bar in the tab color comes first, then the tab title, the session title and the folder. A green `●` marks an agent session that still runs.
|
|
79
|
+
- After a reboot or a crash, the screen starts on the last snapshot from before it, until you restore it.
|
|
80
|
+
|
|
81
|
+
| Key | Action |
|
|
82
|
+
|---|---|
|
|
83
|
+
| `↑` `↓` | Move in the list |
|
|
84
|
+
| `tab` | Switch between the snapshots and the tabs |
|
|
85
|
+
| `space` | Select or clear a tab |
|
|
86
|
+
| `a` | Select all the visible tabs, or none |
|
|
87
|
+
| `/` | Search tabs, sessions and folders. `esc` leaves the search |
|
|
88
|
+
| `enter` | Restore the selected tabs. In iTerm2, it asks first: new windows, or new tabs in this window |
|
|
89
|
+
| `c` | Show the commands that restore runs |
|
|
90
|
+
| `h` | Show the changes that the snapshot records |
|
|
91
|
+
| `p` | Pin the snapshot, or remove its pin |
|
|
92
|
+
| `e` | Export the snapshot as Markdown to `export_dir` |
|
|
93
|
+
| `o` | Change the settings |
|
|
94
|
+
| `s` | Take a snapshot now |
|
|
95
|
+
| `t` | Switch between the dark and the light theme, and save it in the settings |
|
|
96
|
+
| `?` | Show all the keys |
|
|
97
|
+
| `q`, `esc` | Quit |
|
|
98
|
+
|
|
99
|
+
The restore opens new windows with the saved order, frame, titles, colors, splits and profiles. Each pane runs `omp --resume` or `claude --resume` in the agent folder, with the launch flags of the original session. A shell pane goes to its folder.
|
|
100
|
+
|
|
101
|
+
`ai-tabs` does not resume a session that still runs: two processes on the same session file corrupt it. For the same reason, when a snapshot holds one session in two panes, only the first pane resumes it.
|
|
102
|
+
|
|
103
|
+
### Commands
|
|
104
|
+
|
|
105
|
+
| Command | What it does |
|
|
106
|
+
|---|---|
|
|
107
|
+
| `ai-tabs` | Open the restore screen |
|
|
108
|
+
| `ai-tabs snapshot` | Take a snapshot now |
|
|
109
|
+
| `ai-tabs restore [--from ID] [--tab 1.3 …] [--all] [--here] [--dry-run]` | Restore tabs. Without `--tab` or `--all`, it opens the restore screen. `--here` opens the tabs in this window |
|
|
110
|
+
| `ai-tabs show [ID]` | Show the tabs and sessions of a snapshot |
|
|
111
|
+
| `ai-tabs history [--limit N]` | List the snapshots, newest first |
|
|
112
|
+
| `ai-tabs pin ID`, `ai-tabs unpin ID` | Pin a snapshot, or remove its pin |
|
|
113
|
+
| `ai-tabs export [ID …] [--to DIR]` | Write snapshots as Markdown files |
|
|
114
|
+
| `ai-tabs backup` | Write a backup of the database now |
|
|
115
|
+
| `ai-tabs config`, `config set KEY VALUE`, `config unset KEY` | Show or change the settings |
|
|
116
|
+
| `ai-tabs install`, `ai-tabs uninstall` | Load or remove the launchd agent |
|
|
117
|
+
|
|
118
|
+
A snapshot ID is `YYYY-MM-DD/HH-MM-SS`. `latest` is the newest snapshot. See [docs/cli.md](docs/cli.md) for all the options.
|
|
119
|
+
|
|
120
|
+
## Settings
|
|
121
|
+
|
|
122
|
+
A setting takes its value from, in order of priority:
|
|
123
|
+
|
|
124
|
+
1. the command option, for example `export --to`;
|
|
125
|
+
2. the environment variable `AI_TABS_DIR`, for `data_dir` only;
|
|
126
|
+
3. the configuration file `$XDG_CONFIG_HOME/ai-tabs/config.toml`, or `~/.config/ai-tabs/config.toml`;
|
|
127
|
+
4. the default.
|
|
128
|
+
|
|
129
|
+
| Setting | Default | Meaning |
|
|
130
|
+
|---|---|---|
|
|
131
|
+
| `data_dir` | `$XDG_DATA_HOME/ai-tabs`, or `~/.local/share/ai-tabs` | Folder of the database `ai-tabs.sqlite`. If `~/Library/Application Support/ai-tabs` exists, ai-tabs moves it to this folder at the first start |
|
|
132
|
+
| `export_dir` | `data_dir/export` | Folder of the Markdown exports |
|
|
133
|
+
| `export_latest` | `false` | Rewrite `export_dir/latest.md` after every new snapshot |
|
|
134
|
+
| `backup_dir` | `data_dir/backups` | Folder of the daily backups |
|
|
135
|
+
| `backup_keep` | `7` | How many daily backups stay |
|
|
136
|
+
| `history_days` | `30` | How many days the unpinned snapshots stay |
|
|
137
|
+
| `snapshot_interval` | `300` | Seconds between two snapshots. Run `ai-tabs install` after a change |
|
|
138
|
+
| `splash` | `true` | Show the logo for a moment when the restore screen opens, in iTerm2 |
|
|
139
|
+
| `theme` | `auto` | `auto`, `dark` or `light`. `auto` follows the macOS appearance |
|
|
140
|
+
|
|
141
|
+
The configuration file holds only the settings that you changed, with `config set`, the settings window (`o`) or the `t` key. The other settings take their defaults. `ai-tabs config` shows each value and where it comes from: `file`, `environment` or `default`. `ai-tabs config unset KEY` gives a setting its default again. A new `data_dir` takes effect at the next start.
|
|
142
|
+
|
|
143
|
+
For an Obsidian vault, put the Markdown exports in the vault and keep the database out of it. A sync tool or git can copy the database while it is open and corrupt the copy. The exports are text files:
|
|
144
|
+
|
|
145
|
+
```sh
|
|
146
|
+
ai-tabs config set export_dir ~/Notes/ai-tabs
|
|
147
|
+
ai-tabs config set export_latest true
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Data
|
|
151
|
+
|
|
152
|
+
- `ai-tabs snapshot` writes one backup a day with SQLite `VACUUM INTO`, which makes a consistent copy. To use a backup, stop the agent with `ai-tabs uninstall`, copy the backup over the database file, then run `ai-tabs install`.
|
|
153
|
+
- `ai-tabs export` writes one file per snapshot: `export_dir/YYYY-MM-DD/HH-MM-SS.md`. Each file has a front matter for Obsidian properties and Dataview, the changes, a table of the panes and the resume commands. Nothing reads the exports back: the database stays the only source.
|
|
154
|
+
- The launchd agent logs to `~/Library/Logs/ai-tabs.log`.
|
|
155
|
+
|
|
156
|
+
## How it finds the agent sessions
|
|
157
|
+
|
|
158
|
+
- **Claude Code**: `~/.claude/sessions/<pid>.json` gives the session ID and folder of each `claude` process.
|
|
159
|
+
- **omp**: `lsof` gives the session file that each `omp` process holds open. The first lines of the file give the session ID, folder and title.
|
|
160
|
+
- `ps` gives the terminal of each process, and its command line for the launch flags. `ps` drops the original quotes, so a flag value with spaces can split into more words.
|
|
161
|
+
|
|
162
|
+
## Limits
|
|
163
|
+
|
|
164
|
+
- Only iTerm2 on macOS.
|
|
165
|
+
- A reboot stops every process. `ai-tabs` opens the tabs again and resumes the sessions, but it does not bring back running processes.
|
|
166
|
+
- It resumes only omp and Claude Code sessions. Other panes go back to their folder.
|
|
167
|
+
|
|
168
|
+
## Development
|
|
169
|
+
|
|
170
|
+
```sh
|
|
171
|
+
uv sync
|
|
172
|
+
uv run pytest
|
|
173
|
+
uv run ruff check src tests
|
|
174
|
+
uv run typer ai_tabs.cli utils docs --name ai-tabs --title ai-tabs --output docs/cli.md
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Release
|
|
178
|
+
|
|
179
|
+
The `Release` workflow publishes to PyPI when a tag `vX.Y.Z` arrives on GitHub. It runs the tests, checks that the tag is the version in `pyproject.toml`, builds the wheel and the sdist, then uploads them with PyPI Trusted Publishing. No token is stored in GitHub.
|
|
180
|
+
|
|
181
|
+
Before a release, move the `[Unreleased]` entries of `CHANGELOG.md` to a new section for the version, with the date. Then:
|
|
182
|
+
|
|
183
|
+
```sh
|
|
184
|
+
uv version --bump minor # or patch, major
|
|
185
|
+
git commit -am "chore: release v$(uv version --short)"
|
|
186
|
+
git tag "v$(uv version --short)"
|
|
187
|
+
git push origin main --tags
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## License
|
|
191
|
+
|
|
192
|
+
MIT. See [LICENSE](LICENSE).
|
ai_tabs-0.1.0/README.md
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
<p align="center"><img src="src/ai_tabs/assets/logo.png" alt="ai-tabs" width="360"></p>
|
|
2
|
+
|
|
3
|
+
# ai-tabs
|
|
4
|
+
|
|
5
|
+
`ai-tabs` saves your iTerm2 tabs, and the omp and Claude Code sessions in them. After a reboot or a crash, it opens the tabs again and resumes each agent session.
|
|
6
|
+
|
|
7
|
+
- It takes a snapshot every 5 minutes through the iTerm2 Python API. A snapshot holds the windows, the tab order, titles and colors, the split layout, the iTerm2 profile of each pane, and the agent session in each pane.
|
|
8
|
+
- It keeps the snapshots in a SQLite database for 30 days. It pins the last snapshot before a reboot, or before many tabs close at once. The history never deletes pinned snapshots.
|
|
9
|
+
- A terminal screen lets you pick a snapshot and the tabs to open again.
|
|
10
|
+
- It can also export the snapshots as Markdown files, for example into an Obsidian vault.
|
|
11
|
+
|
|
12
|
+
## Requirements
|
|
13
|
+
|
|
14
|
+
- macOS with [iTerm2](https://iterm2.com) 3.5 or later.
|
|
15
|
+
- The iTerm2 Python API: open **iTerm2 › Settings › General › Magic** and select **Enable Python API**.
|
|
16
|
+
- [uv](https://docs.astral.sh/uv/). uv installs Python 3.15 for `ai-tabs` when it is necessary.
|
|
17
|
+
- Optional: [iTerm2 shell integration](https://iterm2.com/documentation-shell-integration.html). With it, `ai-tabs` waits for the shell prompt before it types the resume command.
|
|
18
|
+
|
|
19
|
+
## Install
|
|
20
|
+
|
|
21
|
+
To run the tool without an install:
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
uvx ai-tabs
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
To install it, so that the launchd agent has a stable path:
|
|
28
|
+
|
|
29
|
+
```sh
|
|
30
|
+
uv tool install ai-tabs
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
To install the latest `main` branch from GitHub:
|
|
34
|
+
|
|
35
|
+
```sh
|
|
36
|
+
uv tool install git+https://github.com/WaYdotNET/ai-tabs
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Then start the snapshots. This command loads a launchd agent that runs `ai-tabs snapshot` at login and every `snapshot_interval` seconds (default 300):
|
|
40
|
+
|
|
41
|
+
```sh
|
|
42
|
+
ai-tabs install
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
To stop the snapshots, run `ai-tabs uninstall`. The database, the backups and the configuration stay.
|
|
46
|
+
|
|
47
|
+
## Use
|
|
48
|
+
|
|
49
|
+
Run `ai-tabs` without a command to open the restore screen. In iTerm2, the logo shows for a moment first (setting `splash`):
|
|
50
|
+
|
|
51
|
+
- The screen uses the colors of the logo, in a dark and a light theme. The `theme` setting chooses one, and `auto` (the default) follows the macOS appearance. Press `t` to switch: it saves the choice as `theme = "dark"` or `theme = "light"` in the configuration file. The top bar shows the small logo. Press `?` for the list of all the keys.
|
|
52
|
+
- The left panel shows the snapshots, newest first. 📌 marks a pinned snapshot. A gold line shows how many panes opened and closed.
|
|
53
|
+
- The right panel shows the tabs of the selected snapshot. A bar in the tab color comes first, then the tab title, the session title and the folder. A green `●` marks an agent session that still runs.
|
|
54
|
+
- After a reboot or a crash, the screen starts on the last snapshot from before it, until you restore it.
|
|
55
|
+
|
|
56
|
+
| Key | Action |
|
|
57
|
+
|---|---|
|
|
58
|
+
| `↑` `↓` | Move in the list |
|
|
59
|
+
| `tab` | Switch between the snapshots and the tabs |
|
|
60
|
+
| `space` | Select or clear a tab |
|
|
61
|
+
| `a` | Select all the visible tabs, or none |
|
|
62
|
+
| `/` | Search tabs, sessions and folders. `esc` leaves the search |
|
|
63
|
+
| `enter` | Restore the selected tabs. In iTerm2, it asks first: new windows, or new tabs in this window |
|
|
64
|
+
| `c` | Show the commands that restore runs |
|
|
65
|
+
| `h` | Show the changes that the snapshot records |
|
|
66
|
+
| `p` | Pin the snapshot, or remove its pin |
|
|
67
|
+
| `e` | Export the snapshot as Markdown to `export_dir` |
|
|
68
|
+
| `o` | Change the settings |
|
|
69
|
+
| `s` | Take a snapshot now |
|
|
70
|
+
| `t` | Switch between the dark and the light theme, and save it in the settings |
|
|
71
|
+
| `?` | Show all the keys |
|
|
72
|
+
| `q`, `esc` | Quit |
|
|
73
|
+
|
|
74
|
+
The restore opens new windows with the saved order, frame, titles, colors, splits and profiles. Each pane runs `omp --resume` or `claude --resume` in the agent folder, with the launch flags of the original session. A shell pane goes to its folder.
|
|
75
|
+
|
|
76
|
+
`ai-tabs` does not resume a session that still runs: two processes on the same session file corrupt it. For the same reason, when a snapshot holds one session in two panes, only the first pane resumes it.
|
|
77
|
+
|
|
78
|
+
### Commands
|
|
79
|
+
|
|
80
|
+
| Command | What it does |
|
|
81
|
+
|---|---|
|
|
82
|
+
| `ai-tabs` | Open the restore screen |
|
|
83
|
+
| `ai-tabs snapshot` | Take a snapshot now |
|
|
84
|
+
| `ai-tabs restore [--from ID] [--tab 1.3 …] [--all] [--here] [--dry-run]` | Restore tabs. Without `--tab` or `--all`, it opens the restore screen. `--here` opens the tabs in this window |
|
|
85
|
+
| `ai-tabs show [ID]` | Show the tabs and sessions of a snapshot |
|
|
86
|
+
| `ai-tabs history [--limit N]` | List the snapshots, newest first |
|
|
87
|
+
| `ai-tabs pin ID`, `ai-tabs unpin ID` | Pin a snapshot, or remove its pin |
|
|
88
|
+
| `ai-tabs export [ID …] [--to DIR]` | Write snapshots as Markdown files |
|
|
89
|
+
| `ai-tabs backup` | Write a backup of the database now |
|
|
90
|
+
| `ai-tabs config`, `config set KEY VALUE`, `config unset KEY` | Show or change the settings |
|
|
91
|
+
| `ai-tabs install`, `ai-tabs uninstall` | Load or remove the launchd agent |
|
|
92
|
+
|
|
93
|
+
A snapshot ID is `YYYY-MM-DD/HH-MM-SS`. `latest` is the newest snapshot. See [docs/cli.md](docs/cli.md) for all the options.
|
|
94
|
+
|
|
95
|
+
## Settings
|
|
96
|
+
|
|
97
|
+
A setting takes its value from, in order of priority:
|
|
98
|
+
|
|
99
|
+
1. the command option, for example `export --to`;
|
|
100
|
+
2. the environment variable `AI_TABS_DIR`, for `data_dir` only;
|
|
101
|
+
3. the configuration file `$XDG_CONFIG_HOME/ai-tabs/config.toml`, or `~/.config/ai-tabs/config.toml`;
|
|
102
|
+
4. the default.
|
|
103
|
+
|
|
104
|
+
| Setting | Default | Meaning |
|
|
105
|
+
|---|---|---|
|
|
106
|
+
| `data_dir` | `$XDG_DATA_HOME/ai-tabs`, or `~/.local/share/ai-tabs` | Folder of the database `ai-tabs.sqlite`. If `~/Library/Application Support/ai-tabs` exists, ai-tabs moves it to this folder at the first start |
|
|
107
|
+
| `export_dir` | `data_dir/export` | Folder of the Markdown exports |
|
|
108
|
+
| `export_latest` | `false` | Rewrite `export_dir/latest.md` after every new snapshot |
|
|
109
|
+
| `backup_dir` | `data_dir/backups` | Folder of the daily backups |
|
|
110
|
+
| `backup_keep` | `7` | How many daily backups stay |
|
|
111
|
+
| `history_days` | `30` | How many days the unpinned snapshots stay |
|
|
112
|
+
| `snapshot_interval` | `300` | Seconds between two snapshots. Run `ai-tabs install` after a change |
|
|
113
|
+
| `splash` | `true` | Show the logo for a moment when the restore screen opens, in iTerm2 |
|
|
114
|
+
| `theme` | `auto` | `auto`, `dark` or `light`. `auto` follows the macOS appearance |
|
|
115
|
+
|
|
116
|
+
The configuration file holds only the settings that you changed, with `config set`, the settings window (`o`) or the `t` key. The other settings take their defaults. `ai-tabs config` shows each value and where it comes from: `file`, `environment` or `default`. `ai-tabs config unset KEY` gives a setting its default again. A new `data_dir` takes effect at the next start.
|
|
117
|
+
|
|
118
|
+
For an Obsidian vault, put the Markdown exports in the vault and keep the database out of it. A sync tool or git can copy the database while it is open and corrupt the copy. The exports are text files:
|
|
119
|
+
|
|
120
|
+
```sh
|
|
121
|
+
ai-tabs config set export_dir ~/Notes/ai-tabs
|
|
122
|
+
ai-tabs config set export_latest true
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Data
|
|
126
|
+
|
|
127
|
+
- `ai-tabs snapshot` writes one backup a day with SQLite `VACUUM INTO`, which makes a consistent copy. To use a backup, stop the agent with `ai-tabs uninstall`, copy the backup over the database file, then run `ai-tabs install`.
|
|
128
|
+
- `ai-tabs export` writes one file per snapshot: `export_dir/YYYY-MM-DD/HH-MM-SS.md`. Each file has a front matter for Obsidian properties and Dataview, the changes, a table of the panes and the resume commands. Nothing reads the exports back: the database stays the only source.
|
|
129
|
+
- The launchd agent logs to `~/Library/Logs/ai-tabs.log`.
|
|
130
|
+
|
|
131
|
+
## How it finds the agent sessions
|
|
132
|
+
|
|
133
|
+
- **Claude Code**: `~/.claude/sessions/<pid>.json` gives the session ID and folder of each `claude` process.
|
|
134
|
+
- **omp**: `lsof` gives the session file that each `omp` process holds open. The first lines of the file give the session ID, folder and title.
|
|
135
|
+
- `ps` gives the terminal of each process, and its command line for the launch flags. `ps` drops the original quotes, so a flag value with spaces can split into more words.
|
|
136
|
+
|
|
137
|
+
## Limits
|
|
138
|
+
|
|
139
|
+
- Only iTerm2 on macOS.
|
|
140
|
+
- A reboot stops every process. `ai-tabs` opens the tabs again and resumes the sessions, but it does not bring back running processes.
|
|
141
|
+
- It resumes only omp and Claude Code sessions. Other panes go back to their folder.
|
|
142
|
+
|
|
143
|
+
## Development
|
|
144
|
+
|
|
145
|
+
```sh
|
|
146
|
+
uv sync
|
|
147
|
+
uv run pytest
|
|
148
|
+
uv run ruff check src tests
|
|
149
|
+
uv run typer ai_tabs.cli utils docs --name ai-tabs --title ai-tabs --output docs/cli.md
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Release
|
|
153
|
+
|
|
154
|
+
The `Release` workflow publishes to PyPI when a tag `vX.Y.Z` arrives on GitHub. It runs the tests, checks that the tag is the version in `pyproject.toml`, builds the wheel and the sdist, then uploads them with PyPI Trusted Publishing. No token is stored in GitHub.
|
|
155
|
+
|
|
156
|
+
Before a release, move the `[Unreleased]` entries of `CHANGELOG.md` to a new section for the version, with the date. Then:
|
|
157
|
+
|
|
158
|
+
```sh
|
|
159
|
+
uv version --bump minor # or patch, major
|
|
160
|
+
git commit -am "chore: release v$(uv version --short)"
|
|
161
|
+
git tag "v$(uv version --short)"
|
|
162
|
+
git push origin main --tags
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## License
|
|
166
|
+
|
|
167
|
+
MIT. See [LICENSE](LICENSE).
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "ai-tabs"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Save and restore iTerm2 tabs with their omp and Claude Code sessions."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
license-files = ["LICENSE"]
|
|
8
|
+
requires-python = ">=3.15"
|
|
9
|
+
dependencies = [
|
|
10
|
+
"iterm2>=2.30",
|
|
11
|
+
"rich>=15.0",
|
|
12
|
+
"textual>=8.2",
|
|
13
|
+
"typer>=0.27",
|
|
14
|
+
"websockets",
|
|
15
|
+
]
|
|
16
|
+
keywords = [
|
|
17
|
+
"iterm2",
|
|
18
|
+
"claude-code",
|
|
19
|
+
"omp",
|
|
20
|
+
"terminal",
|
|
21
|
+
"session-restore",
|
|
22
|
+
]
|
|
23
|
+
classifiers = [
|
|
24
|
+
"Environment :: Console",
|
|
25
|
+
"Environment :: MacOS X",
|
|
26
|
+
"Operating System :: MacOS",
|
|
27
|
+
"Programming Language :: Python :: 3",
|
|
28
|
+
"Programming Language :: Python :: 3.15",
|
|
29
|
+
"Topic :: Terminals",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
[[project.authors]]
|
|
33
|
+
name = "Carlo Bertini"
|
|
34
|
+
|
|
35
|
+
[project.urls]
|
|
36
|
+
Homepage = "https://github.com/WaYdotNET/ai-tabs"
|
|
37
|
+
Issues = "https://github.com/WaYdotNET/ai-tabs/issues"
|
|
38
|
+
Changelog = "https://github.com/WaYdotNET/ai-tabs/blob/main/CHANGELOG.md"
|
|
39
|
+
|
|
40
|
+
[project.scripts]
|
|
41
|
+
ai-tabs = "ai_tabs.cli:run"
|
|
42
|
+
|
|
43
|
+
[dependency-groups]
|
|
44
|
+
dev = [
|
|
45
|
+
"pytest>=8",
|
|
46
|
+
"ruff>=0.14",
|
|
47
|
+
]
|
|
48
|
+
|
|
49
|
+
[build-system]
|
|
50
|
+
requires = ["uv_build>=0.9,<0.14"]
|
|
51
|
+
build-backend = "uv_build"
|
|
52
|
+
|
|
53
|
+
[tool.ruff]
|
|
54
|
+
line-length = 120
|
|
55
|
+
target-version = "py315"
|
|
56
|
+
|
|
57
|
+
[tool.ruff.lint]
|
|
58
|
+
select = [
|
|
59
|
+
"E",
|
|
60
|
+
"F",
|
|
61
|
+
"I",
|
|
62
|
+
"B",
|
|
63
|
+
"UP",
|
|
64
|
+
"SIM",
|
|
65
|
+
]
|
|
66
|
+
|
|
67
|
+
[tool.pytest.ini_options]
|
|
68
|
+
testpaths = ["tests"]
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "ai-tabs"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Save and restore iTerm2 tabs with their omp and Claude Code sessions."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
license-files = ["LICENSE"]
|
|
8
|
+
authors = [{ name = "Carlo Bertini" }]
|
|
9
|
+
requires-python = ">=3.15"
|
|
10
|
+
dependencies = [
|
|
11
|
+
"iterm2>=2.30",
|
|
12
|
+
"rich>=15.0",
|
|
13
|
+
"textual>=8.2",
|
|
14
|
+
"typer>=0.27",
|
|
15
|
+
# opener.py catches its ConnectionClosed. iterm2 already depends on it.
|
|
16
|
+
"websockets",
|
|
17
|
+
]
|
|
18
|
+
keywords = ["iterm2", "claude-code", "omp", "terminal", "session-restore"]
|
|
19
|
+
classifiers = [
|
|
20
|
+
"Environment :: Console",
|
|
21
|
+
"Environment :: MacOS X",
|
|
22
|
+
"Operating System :: MacOS",
|
|
23
|
+
"Programming Language :: Python :: 3",
|
|
24
|
+
"Programming Language :: Python :: 3.15",
|
|
25
|
+
"Topic :: Terminals",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
[project.urls]
|
|
29
|
+
Homepage = "https://github.com/WaYdotNET/ai-tabs"
|
|
30
|
+
Issues = "https://github.com/WaYdotNET/ai-tabs/issues"
|
|
31
|
+
Changelog = "https://github.com/WaYdotNET/ai-tabs/blob/main/CHANGELOG.md"
|
|
32
|
+
|
|
33
|
+
[project.scripts]
|
|
34
|
+
ai-tabs = "ai_tabs.cli:run"
|
|
35
|
+
|
|
36
|
+
[dependency-groups]
|
|
37
|
+
dev = [
|
|
38
|
+
"pytest>=8",
|
|
39
|
+
"ruff>=0.14",
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
[build-system]
|
|
43
|
+
requires = ["uv_build>=0.9,<0.14"]
|
|
44
|
+
build-backend = "uv_build"
|
|
45
|
+
|
|
46
|
+
[tool.ruff]
|
|
47
|
+
line-length = 120
|
|
48
|
+
target-version = "py315"
|
|
49
|
+
|
|
50
|
+
[tool.ruff.lint]
|
|
51
|
+
select = ["E", "F", "I", "B", "UP", "SIM"]
|
|
52
|
+
|
|
53
|
+
[tool.pytest.ini_options]
|
|
54
|
+
testpaths = ["tests"]
|