sessionview 0.3.1__tar.gz → 0.3.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. {sessionview-0.3.1 → sessionview-0.3.2}/PKG-INFO +56 -21
  2. {sessionview-0.3.1 → sessionview-0.3.2}/README.md +55 -20
  3. {sessionview-0.3.1 → sessionview-0.3.2}/bin/sessionview +8 -5
  4. {sessionview-0.3.1 → sessionview-0.3.2}/bin/sessionview-autostart +6 -1
  5. {sessionview-0.3.1 → sessionview-0.3.2}/bin/sessionview-frame +18 -4
  6. {sessionview-0.3.1 → sessionview-0.3.2}/bin/sessionview-install +4 -2
  7. {sessionview-0.3.1 → sessionview-0.3.2}/bin/sessionview-messages +8 -3
  8. {sessionview-0.3.1 → sessionview-0.3.2}/bin/sessionview-session +93 -33
  9. {sessionview-0.3.1 → sessionview-0.3.2}/bin/tmux-sidebar +286 -54
  10. sessionview-0.3.2/changelog.d/README.md +102 -0
  11. {sessionview-0.3.1 → sessionview-0.3.2}/config/README.md +12 -3
  12. {sessionview-0.3.1 → sessionview-0.3.2}/config/config.json +6 -2
  13. {sessionview-0.3.1 → sessionview-0.3.2}/docs/configuration.md +18 -4
  14. sessionview-0.3.2/docs/decisions/state-and-log-home.md +557 -0
  15. {sessionview-0.3.1 → sessionview-0.3.2}/docs/dependencies.md +5 -5
  16. {sessionview-0.3.1 → sessionview-0.3.2}/docs/sessionview.md +16 -7
  17. {sessionview-0.3.1 → sessionview-0.3.2}/docs/settings.md +4 -1
  18. sessionview-0.3.2/lib/landing.sh +67 -0
  19. sessionview-0.3.2/lib/state.sh +99 -0
  20. {sessionview-0.3.1 → sessionview-0.3.2}/macos/SessionView.applescript +31 -5
  21. {sessionview-0.3.1 → sessionview-0.3.2}/pyproject.toml +1 -1
  22. {sessionview-0.3.1 → sessionview-0.3.2}/src/sessionview/__init__.py +1 -1
  23. sessionview-0.3.1/lib/state.sh +0 -13
  24. {sessionview-0.3.1 → sessionview-0.3.2}/.gitignore +0 -0
  25. {sessionview-0.3.1 → sessionview-0.3.2}/LICENSE +0 -0
  26. {sessionview-0.3.1 → sessionview-0.3.2}/bin/sessionview-app-install +0 -0
  27. {sessionview-0.3.1 → sessionview-0.3.2}/bin/sessionview-config +0 -0
  28. {sessionview-0.3.1 → sessionview-0.3.2}/bin/sessionview-from +0 -0
  29. {sessionview-0.3.1 → sessionview-0.3.2}/bin/sessionview-newtab +0 -0
  30. {sessionview-0.3.1 → sessionview-0.3.2}/bin/sessionview-send +0 -0
  31. {sessionview-0.3.1 → sessionview-0.3.2}/bin/sessionview-sidebar-toggle +0 -0
  32. {sessionview-0.3.1 → sessionview-0.3.2}/bin/sessionview-terminal +0 -0
  33. {sessionview-0.3.1 → sessionview-0.3.2}/bin/sessionview-usermail +0 -0
  34. {sessionview-0.3.1 → sessionview-0.3.2}/bin/tmux-send-agent +0 -0
  35. {sessionview-0.3.1 → sessionview-0.3.2}/config/keys.md +0 -0
  36. {sessionview-0.3.1 → sessionview-0.3.2}/config/neomuttrc +0 -0
  37. {sessionview-0.3.1 → sessionview-0.3.2}/lib/client.sh +0 -0
  38. {sessionview-0.3.1 → sessionview-0.3.2}/lib/python.sh +0 -0
  39. {sessionview-0.3.1 → sessionview-0.3.2}/lib/sessionview-config-screen +0 -0
  40. {sessionview-0.3.1 → sessionview-0.3.2}/macos/dreamcatcher.icns +0 -0
  41. {sessionview-0.3.1 → sessionview-0.3.2}/plugins/session/plugin.toml +0 -0
  42. {sessionview-0.3.1 → sessionview-0.3.2}/plugins/session/start-agent +0 -0
  43. {sessionview-0.3.1 → sessionview-0.3.2}/plugins/taskmaster/plugin.toml +0 -0
  44. {sessionview-0.3.1 → sessionview-0.3.2}/plugins/taskmaster/tasks-tab +0 -0
  45. {sessionview-0.3.1 → sessionview-0.3.2}/plugins/voicemode/plugin.toml +0 -0
  46. {sessionview-0.3.1 → sessionview-0.3.2}/plugins/voicemode/speak +0 -0
  47. {sessionview-0.3.1 → sessionview-0.3.2}/skills/tmux/SKILL.md +0 -0
  48. {sessionview-0.3.1 → sessionview-0.3.2}/skills/tmux/scripts/tmux-peek +0 -0
  49. {sessionview-0.3.1 → sessionview-0.3.2}/skills/tmux/scripts/tmux-show +0 -0
  50. {sessionview-0.3.1 → sessionview-0.3.2}/skills/tmux/scripts/tmux-type +0 -0
  51. {sessionview-0.3.1 → sessionview-0.3.2}/skills/tmux/scripts/tmux-where +0 -0
  52. {sessionview-0.3.1 → sessionview-0.3.2}/tmux/agent-menu.conf +0 -0
  53. {sessionview-0.3.1 → sessionview-0.3.2}/tmux/frame.conf +0 -0
  54. {sessionview-0.3.1 → sessionview-0.3.2}/tmux/tabs-top.conf +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: sessionview
3
- Version: 0.3.1
3
+ Version: 0.3.2
4
4
  Summary: A sidebar for tmux: your projects (sessions) and your agents, here and on remote hosts.
5
5
  Project-URL: Homepage, https://github.com/sessionkit/sessionview
6
6
  Project-URL: Repository, https://github.com/sessionkit/sessionview
@@ -26,8 +26,11 @@ Install from PyPI: `uv tool install sessionview` (see [Install](#install)).
26
26
 
27
27
  sessionview
28
28
 
29
- In this terminal, that puts the sidebar on the left and the session
30
- `main` on the right; a private outer tmux holds the two panes.
29
+ In this terminal, that puts the sidebar on the left and a tmux session
30
+ on the right; a private outer tmux holds the two panes. The session is
31
+ one tmux already has: your default assistant's, else the one you last
32
+ attached, else the newest. Only when tmux has no session at all does
33
+ sessionview make one, named `main`.
31
34
  `sessionview NAME` attaches the session NAME instead, which must exist.
32
35
  In any tmux client, `prefix H` opens the same sidebar as a popup.
33
36
  Every verb, its form and an example: [the sessionview command](docs/sessionview.md).
@@ -92,8 +95,12 @@ agents, or the menu): the names `session start` knows, pinned ones first.
92
95
  not start. An agent already running is never started twice.
93
96
  - *Agents have a home* — an agent's own file says where it wakes
94
97
  (`start: directory:`); a project's menu starts it in the project.
95
- - *Consent on first open* — Dreamcatcher asks once which agent to start
96
- when it opens (a numbered pick, or never), and remembers.
98
+ - *Consent on first open* — the first time it opens, sessionview asks
99
+ which agent to start whenever it opens, and remembers the answer. It
100
+ says *sessionview can start an agent for you each time it opens*, lists
101
+ your agents by number and asks `Which? (number, name, or "n")`. When it cannot get the
102
+ list it asks `Which agent? (a name, or "no" to never ask again)`. `n` or
103
+ `no` means never; `autostart_agent` in Settings changes it later.
97
104
 
98
105
  **Settings** — every setting, its default, its note and where its value
99
106
  comes from, in a small screen (project menu → Settings); the rows come
@@ -135,7 +142,8 @@ hand. Blink Shell on iPad is wanted and not yet connecting.
135
142
  claude-code: short, safe driving skills with tools
136
143
 
137
144
  Paths resolve from the checkout (`SESSIONVIEW_ROOT`); state lives in
138
- `~/.local/state/sessionview` (`SESSIONVIEW_STATE`). Its direct dependencies:
145
+ `~/.sessionkit/view/state` (`SESSIONVIEW_STATE`) and the log in
146
+ `~/.sessionkit/view/log` (`SESSIONVIEW_LOG`). Its direct dependencies:
139
147
  [dependencies](docs/dependencies.md).
140
148
 
141
149
  ## Install
@@ -235,14 +243,13 @@ beside it. Each line says what puts it there and what takes it away.
235
243
  sessionview` drops this package's entries, and `uv cache prune` drops
236
244
  the ones nothing uses.
237
245
  - **Folders, each made by a verb you run:**
238
- - `~/.local/state/sessionview/`: the state folder, made the first time
239
- `sessionview` opens (or `sessionview session` or `sessionview
240
- messages` runs). `SESSIONVIEW_STATE` moves it. An older release's
241
- `~/.local/state/herd/` is renamed to it then, when only the old
242
- one exists. In it:
246
+ - `~/.sessionkit/view/state/`: the state folder, mode 0700, made the
247
+ first time `sessionview` opens (or `sessionview session` or
248
+ `sessionview messages` runs). `SESSIONVIEW_STATE` names another
249
+ folder instead. Each file sessionview makes in it is private (mode
250
+ 0600). In it:
243
251
  - `frame-PID.tty`, one while each frame is open. The frame deletes
244
252
  it when it closes; a frame killed outright can leave it behind.
245
- - `sessionview.log`, the log ([Logs](#logs)).
246
253
  - `recent.tsv`, a line each time `sessionview session` opens a
247
254
  project, for the picker's order.
248
255
  - `picker-order`, when you flip the picker's sort.
@@ -254,6 +261,23 @@ beside it. Each line says what puts it there and what takes it away.
254
261
  - `sidebar-remote-HOST.json`, what the sidebar last saw from each
255
262
  host in your `remotes` setting.
256
263
  - `mutt/`, an rc file for each box `sessionview messages` opens.
264
+ - `~/.sessionkit/view/log/`: the log folder, mode 0700, made at the
265
+ same time. It holds `sessionview.log` ([Logs](#logs)).
266
+ `SESSIONVIEW_LOG` names another log file. When `SESSIONVIEW_STATE`
267
+ is set, the log is `sessionview.log` in that folder instead.
268
+ - `~/.local/state/sessionview/`: the state folder of releases before
269
+ this one. Nothing new is made there. On an upgrade, the first start
270
+ hard-links `recent.tsv`, `picker-order`, `sidebar-mail.txt` and each
271
+ file in `mutt/` into the new state folder. The old names are kept,
272
+ so the two names are one file, and a sidebar still running from
273
+ before the upgrade stays correct. The old folder is left in place,
274
+ with the old `sessionview.log`, `sidebar-mouse.log`, the frame pins
275
+ and the plugin and remote files, which are not carried over. One
276
+ line is added to the end of the old log, naming the new one. Each
277
+ start sets the old folder to mode 0700, so the old names are private
278
+ too; the files in it keep their modes. An
279
+ older release's `~/.local/state/herd/` is renamed to this folder
280
+ first, when only the herd one exists.
257
281
  - `~/Applications/SessionView.app`: `sessionview install --app` (or
258
282
  `make app` in a checkout), or in `DEST` when that is set. It is
259
283
  built in a temporary folder that is deleted after, and a rebuild
@@ -320,21 +344,25 @@ rm ~/.local/bin/sessionview ~/.local/bin/sessionview-* ~/.local/bin/tmux-sidebar
320
344
  ```
321
345
 
322
346
  That leaves what the verbs made, listed above. The Dock app, the
323
- plugin's cached copy and the state folder are sessionview's alone. To
324
- delete them:
347
+ plugin's cached copy, and the state and log folders are sessionview's
348
+ alone. To delete them:
325
349
 
326
350
  ```bash
327
351
  rm -rf "${HOME:?}/Applications/SessionView.app"
328
352
  rm -rf "${HOME:?}/.claude/plugins/cache/sessionview"
353
+ rm -rf "${HOME:?}/.sessionkit/view/state" "${HOME:?}/.sessionkit/view/log"
329
354
  rm -rf "${HOME:?}/.local/state/sessionview"
330
355
  ```
331
356
 
357
+ The last line is for an upgrade from an earlier release: it removes the
358
+ old state folder, with the old log in it.
359
+
332
360
  uv's cache stays too, with the other things uv installed; `uv cache
333
361
  clean sessionview` drops this package's entries. The key bindings go
334
362
  when your tmux server next exits.
335
363
 
336
364
  The rest is your data: delete it by hand only if you want it gone.
337
- `~/.sessionkit/view/` holds your settings, and the kit's other packages
365
+ `~/.sessionkit/view/settings/` holds your settings, and the kit's other packages
338
366
  keep theirs beside it in `~/.sessionkit/`.
339
367
 
340
368
  ## Keys and clicks
@@ -380,8 +408,9 @@ The look follows herdr's; its colours were matched from herdr's own window.
380
408
  - **Environment:** `SESSIONVIEW_CONFIG` (another file for yours),
381
409
  `SESSIONVIEW_FROM` (the name mail is sent as, else `mail_from`, else
382
410
  `$USER`; `sessionview from` prints the name in effect), `SESSIONVIEW_STATE`
383
- (state, default `~/.local/state/sessionview`), `SESSIONVIEW_PLUGINS`
384
- (another plugin directory).
411
+ (state, default `~/.sessionkit/view/state`), `SESSIONVIEW_LOG` (the log
412
+ file, default `~/.sessionkit/view/log/sessionview.log`),
413
+ `SESSIONVIEW_PLUGINS` (another plugin directory).
385
414
  - sessionview does not read the kit's settings cascade today, only these.
386
415
 
387
416
  Every file, variable and tmux option is in
@@ -391,19 +420,25 @@ and every key in
391
420
 
392
421
  ## Logs
393
422
 
394
- - `~/.local/state/sessionview/sessionview.log`: what went wrong, one
423
+ - `~/.sessionkit/view/log/sessionview.log`: what went wrong, one
395
424
  entry each, starting with the time (a failed tmux call, an uncaught
396
425
  error with its traceback). Follow it with
397
- `tail -f ~/.local/state/sessionview/sessionview.log` when a click
426
+ `tail -f ~/.sessionkit/view/log/sessionview.log` when a click
398
427
  seems to do nothing.
428
+ - **After an upgrade:** the log of earlier releases,
429
+ `~/.local/state/sessionview/sessionview.log`, stays where it is and
430
+ is never moved. Its last line names the new log, and the new log's
431
+ first line names the old one.
399
432
  - **Levels:** `log_level` in your settings (or `$SESSIONVIEW_LOG_LEVEL`
400
433
  for one run). `error`, the default, logs only what went wrong.
401
434
  `timing` adds a line per click or key with its milliseconds, and each
402
435
  command that took 50 ms or more, so a slow click names its slow part.
403
436
  `debug` adds every command and every mouse event (what the old
404
437
  `sidebar-mouse.log` held).
405
- - It sits under `$SESSIONVIEW_STATE` when that is set. It is not rotated:
406
- turn `timing` or `debug` on while you look, then back to `error`.
438
+ - `$SESSIONVIEW_LOG` names another log file. Without it, a
439
+ `$SESSIONVIEW_STATE` that names another folder keeps the log there, as
440
+ `sessionview.log`. It is not rotated: turn `timing` or `debug` on
441
+ while you look, then back to `error`.
407
442
  - **Health:** `sessionview install --check`: exit 0 and `ready` when
408
443
  every requirement is present, exit 1 with each MISSING one named
409
444
  otherwise. It checks the machine, not a running sidebar.
@@ -9,8 +9,11 @@ Install from PyPI: `uv tool install sessionview` (see [Install](#install)).
9
9
 
10
10
  sessionview
11
11
 
12
- In this terminal, that puts the sidebar on the left and the session
13
- `main` on the right; a private outer tmux holds the two panes.
12
+ In this terminal, that puts the sidebar on the left and a tmux session
13
+ on the right; a private outer tmux holds the two panes. The session is
14
+ one tmux already has: your default assistant's, else the one you last
15
+ attached, else the newest. Only when tmux has no session at all does
16
+ sessionview make one, named `main`.
14
17
  `sessionview NAME` attaches the session NAME instead, which must exist.
15
18
  In any tmux client, `prefix H` opens the same sidebar as a popup.
16
19
  Every verb, its form and an example: [the sessionview command](docs/sessionview.md).
@@ -75,8 +78,12 @@ agents, or the menu): the names `session start` knows, pinned ones first.
75
78
  not start. An agent already running is never started twice.
76
79
  - *Agents have a home* — an agent's own file says where it wakes
77
80
  (`start: directory:`); a project's menu starts it in the project.
78
- - *Consent on first open* — Dreamcatcher asks once which agent to start
79
- when it opens (a numbered pick, or never), and remembers.
81
+ - *Consent on first open* — the first time it opens, sessionview asks
82
+ which agent to start whenever it opens, and remembers the answer. It
83
+ says *sessionview can start an agent for you each time it opens*, lists
84
+ your agents by number and asks `Which? (number, name, or "n")`. When it cannot get the
85
+ list it asks `Which agent? (a name, or "no" to never ask again)`. `n` or
86
+ `no` means never; `autostart_agent` in Settings changes it later.
80
87
 
81
88
  **Settings** — every setting, its default, its note and where its value
82
89
  comes from, in a small screen (project menu → Settings); the rows come
@@ -118,7 +125,8 @@ hand. Blink Shell on iPad is wanted and not yet connecting.
118
125
  claude-code: short, safe driving skills with tools
119
126
 
120
127
  Paths resolve from the checkout (`SESSIONVIEW_ROOT`); state lives in
121
- `~/.local/state/sessionview` (`SESSIONVIEW_STATE`). Its direct dependencies:
128
+ `~/.sessionkit/view/state` (`SESSIONVIEW_STATE`) and the log in
129
+ `~/.sessionkit/view/log` (`SESSIONVIEW_LOG`). Its direct dependencies:
122
130
  [dependencies](docs/dependencies.md).
123
131
 
124
132
  ## Install
@@ -218,14 +226,13 @@ beside it. Each line says what puts it there and what takes it away.
218
226
  sessionview` drops this package's entries, and `uv cache prune` drops
219
227
  the ones nothing uses.
220
228
  - **Folders, each made by a verb you run:**
221
- - `~/.local/state/sessionview/`: the state folder, made the first time
222
- `sessionview` opens (or `sessionview session` or `sessionview
223
- messages` runs). `SESSIONVIEW_STATE` moves it. An older release's
224
- `~/.local/state/herd/` is renamed to it then, when only the old
225
- one exists. In it:
229
+ - `~/.sessionkit/view/state/`: the state folder, mode 0700, made the
230
+ first time `sessionview` opens (or `sessionview session` or
231
+ `sessionview messages` runs). `SESSIONVIEW_STATE` names another
232
+ folder instead. Each file sessionview makes in it is private (mode
233
+ 0600). In it:
226
234
  - `frame-PID.tty`, one while each frame is open. The frame deletes
227
235
  it when it closes; a frame killed outright can leave it behind.
228
- - `sessionview.log`, the log ([Logs](#logs)).
229
236
  - `recent.tsv`, a line each time `sessionview session` opens a
230
237
  project, for the picker's order.
231
238
  - `picker-order`, when you flip the picker's sort.
@@ -237,6 +244,23 @@ beside it. Each line says what puts it there and what takes it away.
237
244
  - `sidebar-remote-HOST.json`, what the sidebar last saw from each
238
245
  host in your `remotes` setting.
239
246
  - `mutt/`, an rc file for each box `sessionview messages` opens.
247
+ - `~/.sessionkit/view/log/`: the log folder, mode 0700, made at the
248
+ same time. It holds `sessionview.log` ([Logs](#logs)).
249
+ `SESSIONVIEW_LOG` names another log file. When `SESSIONVIEW_STATE`
250
+ is set, the log is `sessionview.log` in that folder instead.
251
+ - `~/.local/state/sessionview/`: the state folder of releases before
252
+ this one. Nothing new is made there. On an upgrade, the first start
253
+ hard-links `recent.tsv`, `picker-order`, `sidebar-mail.txt` and each
254
+ file in `mutt/` into the new state folder. The old names are kept,
255
+ so the two names are one file, and a sidebar still running from
256
+ before the upgrade stays correct. The old folder is left in place,
257
+ with the old `sessionview.log`, `sidebar-mouse.log`, the frame pins
258
+ and the plugin and remote files, which are not carried over. One
259
+ line is added to the end of the old log, naming the new one. Each
260
+ start sets the old folder to mode 0700, so the old names are private
261
+ too; the files in it keep their modes. An
262
+ older release's `~/.local/state/herd/` is renamed to this folder
263
+ first, when only the herd one exists.
240
264
  - `~/Applications/SessionView.app`: `sessionview install --app` (or
241
265
  `make app` in a checkout), or in `DEST` when that is set. It is
242
266
  built in a temporary folder that is deleted after, and a rebuild
@@ -303,21 +327,25 @@ rm ~/.local/bin/sessionview ~/.local/bin/sessionview-* ~/.local/bin/tmux-sidebar
303
327
  ```
304
328
 
305
329
  That leaves what the verbs made, listed above. The Dock app, the
306
- plugin's cached copy and the state folder are sessionview's alone. To
307
- delete them:
330
+ plugin's cached copy, and the state and log folders are sessionview's
331
+ alone. To delete them:
308
332
 
309
333
  ```bash
310
334
  rm -rf "${HOME:?}/Applications/SessionView.app"
311
335
  rm -rf "${HOME:?}/.claude/plugins/cache/sessionview"
336
+ rm -rf "${HOME:?}/.sessionkit/view/state" "${HOME:?}/.sessionkit/view/log"
312
337
  rm -rf "${HOME:?}/.local/state/sessionview"
313
338
  ```
314
339
 
340
+ The last line is for an upgrade from an earlier release: it removes the
341
+ old state folder, with the old log in it.
342
+
315
343
  uv's cache stays too, with the other things uv installed; `uv cache
316
344
  clean sessionview` drops this package's entries. The key bindings go
317
345
  when your tmux server next exits.
318
346
 
319
347
  The rest is your data: delete it by hand only if you want it gone.
320
- `~/.sessionkit/view/` holds your settings, and the kit's other packages
348
+ `~/.sessionkit/view/settings/` holds your settings, and the kit's other packages
321
349
  keep theirs beside it in `~/.sessionkit/`.
322
350
 
323
351
  ## Keys and clicks
@@ -363,8 +391,9 @@ The look follows herdr's; its colours were matched from herdr's own window.
363
391
  - **Environment:** `SESSIONVIEW_CONFIG` (another file for yours),
364
392
  `SESSIONVIEW_FROM` (the name mail is sent as, else `mail_from`, else
365
393
  `$USER`; `sessionview from` prints the name in effect), `SESSIONVIEW_STATE`
366
- (state, default `~/.local/state/sessionview`), `SESSIONVIEW_PLUGINS`
367
- (another plugin directory).
394
+ (state, default `~/.sessionkit/view/state`), `SESSIONVIEW_LOG` (the log
395
+ file, default `~/.sessionkit/view/log/sessionview.log`),
396
+ `SESSIONVIEW_PLUGINS` (another plugin directory).
368
397
  - sessionview does not read the kit's settings cascade today, only these.
369
398
 
370
399
  Every file, variable and tmux option is in
@@ -374,19 +403,25 @@ and every key in
374
403
 
375
404
  ## Logs
376
405
 
377
- - `~/.local/state/sessionview/sessionview.log`: what went wrong, one
406
+ - `~/.sessionkit/view/log/sessionview.log`: what went wrong, one
378
407
  entry each, starting with the time (a failed tmux call, an uncaught
379
408
  error with its traceback). Follow it with
380
- `tail -f ~/.local/state/sessionview/sessionview.log` when a click
409
+ `tail -f ~/.sessionkit/view/log/sessionview.log` when a click
381
410
  seems to do nothing.
411
+ - **After an upgrade:** the log of earlier releases,
412
+ `~/.local/state/sessionview/sessionview.log`, stays where it is and
413
+ is never moved. Its last line names the new log, and the new log's
414
+ first line names the old one.
382
415
  - **Levels:** `log_level` in your settings (or `$SESSIONVIEW_LOG_LEVEL`
383
416
  for one run). `error`, the default, logs only what went wrong.
384
417
  `timing` adds a line per click or key with its milliseconds, and each
385
418
  command that took 50 ms or more, so a slow click names its slow part.
386
419
  `debug` adds every command and every mouse event (what the old
387
420
  `sidebar-mouse.log` held).
388
- - It sits under `$SESSIONVIEW_STATE` when that is set. It is not rotated:
389
- turn `timing` or `debug` on while you look, then back to `error`.
421
+ - `$SESSIONVIEW_LOG` names another log file. Without it, a
422
+ `$SESSIONVIEW_STATE` that names another folder keeps the log there, as
423
+ `sessionview.log`. It is not rotated: turn `timing` or `debug` on
424
+ while you look, then back to `error`.
390
425
  - **Health:** `sessionview install --check`: exit 0 and `ready` when
391
426
  every requirement is present, exit 1 with each MISSING one named
392
427
  otherwise. It checks the machine, not a running sidebar.
@@ -6,7 +6,8 @@
6
6
  # sessionview --help | --version
7
7
  #
8
8
  # sessionview [SESSION] the frame: sidebar on the left, SESSION attached on
9
- # the right (default main; a named SESSION must exist).
9
+ # the right (default: one the server has, else main;
10
+ # a named SESSION must exist).
10
11
  # --sock names its tmux server; --width, columns.
11
12
  # sessionview config settings: no verb opens the screen (get/set/list ...)
12
13
  # sessionview session NAME open a project session with its standard tabs
@@ -22,7 +23,7 @@
22
23
  #
23
24
  # Also: prefix H in any tmux client opens the sidebar as a popup.
24
25
  # Config: ~/.sessionkit/view/settings/view.json over the shipped config/config.json.
25
- # State: ~/.local/state/sessionview (SESSIONVIEW_STATE=).
26
+ # State: ~/.sessionkit/view/state (SESSIONVIEW_STATE=). Log: ~/.sessionkit/view/log (SESSIONVIEW_LOG=).
26
27
  # (end of usage)
27
28
  # Ghostty was stripped out so this works in any terminal with only tmux. It
28
29
  # started as ghostty-herd; the Ghostty launcher, the split hook and cmd+d
@@ -66,7 +67,7 @@ case "${1:-}" in
66
67
  "$SESSIONVIEW_ROOT/bin/tmux-sidebar" --help >&2
67
68
  exit 2
68
69
  fi
69
- SESSIONVIEW_STATE="${SESSIONVIEW_STATE:-$HOME/.local/state/sessionview}"; . "$SESSIONVIEW_ROOT/lib/state.sh"; . "$SESSIONVIEW_ROOT/lib/python.sh"; export SESSIONVIEW_ROOT SESSIONVIEW_STATE
70
+ . "$SESSIONVIEW_ROOT/lib/state.sh"; . "$SESSIONVIEW_ROOT/lib/python.sh"; export SESSIONVIEW_ROOT SESSIONVIEW_STATE
70
71
  # The supervisor: q = exit 0 = reload (picks up an edited tmux-sidebar or
71
72
  # sidebar.toml), Q = exit 3 = quit. A CRASH IS NOT A QUIT: any other exit
72
73
  # holds the error on screen and waits (one undefined name once took the
@@ -86,7 +87,9 @@ esac
86
87
  # (--sock, else this tmux's own server when run inside one, else default):
87
88
  # a typo or a probe word must not mean "open a frame on a new session named
88
89
  # after it". Read-only check; on a miss, usage and exit 2, nothing touched.
89
- # A new named session is `sessionview session NAME`. No word = main, as before.
90
+ # A new named session is `sessionview session NAME`. No word: the frame picks
91
+ # a session the server already has, and makes main only when it has none
92
+ # (lib/landing.sh).
90
93
  word=""; sock=""; prev=""
91
94
  for a in "$@"; do
92
95
  case "$prev" in --sock) sock="$a"; prev=""; continue;; --width) prev=""; continue;; esac
@@ -110,5 +113,5 @@ if [ -n "$word" ]; then
110
113
  # the frame looks where this checked: inside tmux, the caller's own server
111
114
  [ -n "$extra" ] && set -- "$@" --sock "$sock"
112
115
  fi
113
- SESSIONVIEW_STATE="${SESSIONVIEW_STATE:-$HOME/.local/state/sessionview}"; . "$SESSIONVIEW_ROOT/lib/state.sh"; . "$SESSIONVIEW_ROOT/lib/python.sh"; export SESSIONVIEW_ROOT SESSIONVIEW_STATE
116
+ . "$SESSIONVIEW_ROOT/lib/state.sh"; . "$SESSIONVIEW_ROOT/lib/python.sh"; export SESSIONVIEW_ROOT SESSIONVIEW_STATE
114
117
  exec "$SESSIONVIEW_ROOT/bin/sessionview-frame" "$@"
@@ -116,9 +116,14 @@ sys.exit(1)' "$1"
116
116
  # that then fails to start. Empty output, missing command, any error: the
117
117
  # free-text question below still works, so this fails open like everything
118
118
  # else in this file.
119
+ #
120
+ # Each line is NAME, then a TAB and a mark (`claude<TAB>built in`), or the
121
+ # NAME alone. Only the field before the first TAB is a name: the mark can hold
122
+ # a space, and splitting the whole output on whitespace offered "built" and
123
+ # "in" as agents.
119
124
  agent_list() {
120
125
  command -v session >/dev/null 2>&1 || return 0
121
- session start --list-agents 2>/dev/null
126
+ session start --list-agents 2>/dev/null | awk -F '\t' '$1 != "" { print $1 }'
122
127
  }
123
128
 
124
129
  # Discard every byte waiting to be read on the terminal. ask() calls this once
@@ -7,7 +7,9 @@
7
7
  #
8
8
  # sessionview-frame [SESSION] [--sock SOCKET] [--width N]
9
9
  #
10
- # SESSION what the right pane attaches (default: main)
10
+ # SESSION what the right pane attaches (default: a session the server
11
+ # already has: the default seat's, else the last attached, else
12
+ # the newest; main, made, only when the server has none)
11
13
  # --sock the tmux server SESSION lives on (default: default; a store's is
12
14
  # tm-store-NAME)
13
15
  # --width sidebar columns (default: config width via sessionview-config, else 34)
@@ -32,7 +34,7 @@ while [ $# -gt 0 ]; do case "$1" in
32
34
  *) SESSION="$1"; GIVEN=1;;
33
35
  esac; shift; done
34
36
  # The state dir and the Python only after the flags: -h touches nothing.
35
- SESSIONVIEW_STATE="${SESSIONVIEW_STATE:-$HOME/.local/state/sessionview}"; . "$SESSIONVIEW_ROOT/lib/state.sh"; . "$SESSIONVIEW_ROOT/lib/python.sh"; export SESSIONVIEW_ROOT SESSIONVIEW_STATE
37
+ . "$SESSIONVIEW_ROOT/lib/state.sh"; . "$SESSIONVIEW_ROOT/lib/python.sh"; export SESSIONVIEW_ROOT SESSIONVIEW_STATE
36
38
  # The frame takes over the terminal it runs in, so it needs one: a script or
37
39
  # an agent's shell (stdin/stdout not a tty) is refused and nothing is touched.
38
40
  # Every refusal is one line on stderr, exit 2.
@@ -72,11 +74,21 @@ if [ -n "${TMUX:-}" ]; then
72
74
  # (measured: SESSIONVIEW_FRAME_SOCK set here did not reach the frame,
73
75
  # which landed on the default frame server) - carry what matters by hand.
74
76
  cmd="SESSIONVIEW_ROOT=$(q "$SESSIONVIEW_ROOT") SESSIONVIEW_STATE=$(q "$SESSIONVIEW_STATE") SESSIONVIEW_PYTHON=$(q "${SESSIONVIEW_PYTHON:-}")"
77
+ # A log the user gave goes too; a derived one never does (lib/state.sh).
78
+ if [ -n "${SESSIONVIEW_LOG:-}" ]; then cmd="$cmd SESSIONVIEW_LOG=$(q "$SESSIONVIEW_LOG")"; fi
75
79
  cmd="$cmd SESSIONVIEW_FRAME_SOCK=$(q "$FRAME_SOCK") TMUX="
76
80
  cmd="$cmd exec $(q "$0") $(q "$SESSION") --sock $(q "$SOCK")"
77
81
  [ -n "$WIDTH" ] && cmd="$cmd --width $(q "$WIDTH")"
78
82
  exec tmux -S "$here_path" detach-client -t "$ctty" -E "$cmd"
79
83
  fi
84
+ # Outside tmux with no SESSION named: land in a session the server already
85
+ # has (the default seat's, else the last attached, else the newest; the rule
86
+ # and its reasons are in lib/landing.sh). `main` is made below only when the
87
+ # server has no session at all.
88
+ if [ -z "$GIVEN" ]; then
89
+ . "$SESSIONVIEW_ROOT/lib/landing.sh"
90
+ if sv_landing "$SOCK"; then SESSION="$SV_LANDING"; fi
91
+ fi
80
92
  if [ -z "$WIDTH" ]; then
81
93
  WIDTH="$("$SESSIONVIEW_ROOT/bin/sessionview-config" get width 2>/dev/null || true)"
82
94
  WIDTH="${WIDTH:-34}"
@@ -209,7 +221,9 @@ o resize-pane -t "$SIDE" -x "$WIDTH"
209
221
  TTY="$(tty 2>/dev/null || echo none)"
210
222
  o set-hook -g "client-detached[$$]" "if -F '#{==:#{hook_client},$TTY}' 'kill-session -t =$F'"
211
223
  o select-pane -t "$MAIN"
212
- # pin = the client pane's tty: that is the client the sidebar may move
213
- o display-message -p -t "$MAIN" '#{pane_tty}' >"$PIN"
224
+ # pin = the client pane's tty: that is the client the sidebar may move. Made
225
+ # 0600: the umask is the subshell's alone, never this script's, which starts
226
+ # the user's tmux server (a server keeps its umask for every pane it opens).
227
+ ( umask 077; o display-message -p -t "$MAIN" '#{pane_tty}' >"$PIN" )
214
228
  o attach -t "=$F"
215
229
  cleanup
@@ -157,13 +157,15 @@ fi
157
157
  if command -v session >/dev/null 2>&1; then say PASS "session on PATH"
158
158
  else say WARN "session not on PATH - the sidebar lists tmux sessions without it, but no agent rows, so no agent menu (Message, Settle, ...), and no 'Start an agent' (uv tool install sessiontools)"; fi
159
159
  # neomutt - the messages tab (bin/sessionview-messages runs `neomutt -R`, exit 2 without
160
- # it). MISSING, not WARN: sessionview needs NeoMutt.
160
+ # it). A WARN, not MISSING: that tab is made only when sessionmail, which is optional,
161
+ # is installed, so sessionview runs without neomutt and the check still says ready.
162
+ # (It was MISSING until 2026-10-28, when neomutt was ruled optional for the check.)
161
163
  if command -v neomutt >/dev/null 2>&1; then
162
164
  nv="$(neomutt -v 2>/dev/null | sed -n 's/^NeoMutt \([0-9]*\).*/\1/p' | head -1)"
163
165
  if neomutt -v 2>/dev/null | grep -q '+notmuch'; then say PASS "neomutt ${nv:-?} with notmuch"
164
166
  else say WARN "neomutt ${nv:-?} built without notmuch - the messages tab opens, with no sidebar (brew install neomutt)"; fi
165
167
  else
166
- fail "neomutt - brew install neomutt (the messages tab)"
168
+ say WARN "neomutt not on PATH - the messages tab, which sessionview makes only when sessionmail is installed, cannot open (brew install neomutt)"
167
169
  fi
168
170
  # notmuch - the messages tab's sidebar queries Type: and Project:; unindexed, the Asks
169
171
  # rows are every mail to NAME+ask, with no error
@@ -108,16 +108,21 @@ if command -v notmuch >/dev/null 2>&1; then
108
108
  *) SIDEBAR_WHY="$FOLDER is not under notmuch database.path $DB";;
109
109
  esac; fi
110
110
  else SIDEBAR_WHY="no notmuch on PATH (brew install notmuch)"; fi
111
- SESSIONVIEW_STATE="${SESSIONVIEW_STATE:-$HOME/.local/state/sessionview}"; . "$SESSIONVIEW_ROOT/lib/state.sh"; STATE="$SESSIONVIEW_STATE/mutt"; mkdir -p "$STATE"
111
+ . "$SESSIONVIEW_ROOT/lib/state.sh"; STATE="$SESSIONVIEW_STATE/mutt"; mkdir -p -m 700 "$STATE"
112
112
  RC="$STATE/${BOX//\//-}.rc"
113
- {
113
+ # Written IN PLACE (> truncates the same file), never a temp file renamed over
114
+ # it: the rc may have a second name, a hard link in the old state dir's mutt/
115
+ # (docs/decisions/state-and-log-home.md, section 3). Made 0600 when it is new:
116
+ # the umask is the subshell's alone, never this script's, which execs neomutt;
117
+ # an existing rc keeps its mode.
118
+ ( umask 077; {
114
119
  printf 'set mbox_type=Maildir\nset folder="%s"\nset spoolfile=+\nset mark_old=no\n' "$FOLDER"
115
120
  [ -n "$SIDEBAR_WHY" ] && printf '# sidebar: %s\n' "$SIDEBAR_WHY"
116
121
  [ -n "$SIDEBAR" ] && printf '%s\n' "$SIDEBAR"
117
122
  printf 'source "%s"\n' "$SESSIONVIEW_ROOT/config/neomuttrc"
118
123
  [ -z "$SIDEBAR" ] && printf 'set sidebar_visible=no\n'
119
124
  [ -f "$VIEW_SETTINGS/neomuttrc" ] && printf 'source "%s"\n' "$VIEW_SETTINGS/neomuttrc"
120
- } >"$RC"
125
+ } >"$RC" )
121
126
  if [ "$PRINT" = 1 ]; then
122
127
  echo "box=$BOX folder=$FOLDER rc=$RC"
123
128
  if [ -n "$SIDEBAR" ]; then echo "sidebar=$NAME, Asks, Asks · threads${SIDEBAR_WHY:+ ($SIDEBAR_WHY)}"