opencode-sesh 1.0.1 → 1.0.2
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/AGENTS.md +4 -0
- package/CHANGELOG.md +7 -0
- package/README.md +12 -8
- package/package.json +1 -1
- package/tui-plugins/sesh-panel/tui.tsx +55 -7
package/AGENTS.md
CHANGED
|
@@ -203,6 +203,10 @@ Resume happens in place (`exec` after `cd` to the session's cwd).
|
|
|
203
203
|
- **The sidebar never binds arrow keys globally.** Keyboard navigation is
|
|
204
204
|
opt-in: clicking the *Sessions* heading (or its search box) activates a
|
|
205
205
|
priority-20 layer, because a global `↑`/`↓` would hijack the main prompt.
|
|
206
|
+
Clicking outside the sidebar, opening a session, or navigating releases it
|
|
207
|
+
again (with search, hover and any armed delete), so the sidebar cannot
|
|
208
|
+
shadow the composer afterwards. Sidebar-internal clicks stop propagation so
|
|
209
|
+
the outside-click release cannot undo them.
|
|
206
210
|
Cursor state is derived from `itemRows()`, so hover and cursor resolve to the
|
|
207
211
|
same row. The section lists every session with no row cap
|
|
208
212
|
(`tests/tui.mjs` asserts the cap stays out); overflow scrolls inside the
|
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,12 @@ All notable changes to this project are documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.0.2] - 2026-10-08
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- **tui:** Release sidebar captures when focus returns to composer
|
|
13
|
+
|
|
8
14
|
## [1.0.1] - 2026-10-08
|
|
9
15
|
|
|
10
16
|
### Fixed
|
|
@@ -424,6 +430,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
424
430
|
- Fixture-database regression suite, TypeScript typechecking, and ShellCheck in
|
|
425
431
|
CI.
|
|
426
432
|
|
|
433
|
+
[1.0.2]: https://github.com/ozandogrultan/opencode-sesh/compare/v1.0.1...v1.0.2
|
|
427
434
|
[1.0.1]: https://github.com/ozandogrultan/opencode-sesh/compare/v1.0.0...v1.0.1
|
|
428
435
|
[1.0.0]: https://github.com/ozandogrultan/opencode-sesh/compare/v0.14.1...v1.0.0
|
|
429
436
|
[0.14.1]: https://github.com/ozandogrultan/opencode-sesh/compare/v0.14.0...v0.14.1
|
package/README.md
CHANGED
|
@@ -18,14 +18,18 @@ grouped by directory, full-text searchable, and previewable from anywhere.
|
|
|
18
18
|
[](https://github.com/ozandogrultan/opencode-sesh/stargazers)
|
|
19
19
|
|
|
20
20
|
```text
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
21
|
+
Sessions (8) ▾ hide
|
|
22
|
+
search…
|
|
23
|
+
▾ …/Projects/portal (5)
|
|
24
|
+
├○ Retry the OAuth token refr… 2h
|
|
25
|
+
├○ Login rate limiting notes 3d
|
|
26
|
+
├○ Draft the release notes 7d
|
|
27
|
+
├○ Auth middleware cleanup 11d
|
|
28
|
+
└○ Rotate the signing keys 12d
|
|
29
|
+
▾ ~/Projects/mobile (3)
|
|
30
|
+
├○ Author avatar upload retry 1d
|
|
31
|
+
├○ Fix session cookie on Safari 2d
|
|
32
|
+
└○ Auth redirect loop after log… 6d
|
|
29
33
|
```
|
|
30
34
|
|
|
31
35
|
## Why sesh
|
package/package.json
CHANGED
|
@@ -1050,7 +1050,17 @@ function SidebarSessions(props: { api: TuiPluginApi } & PinProps) {
|
|
|
1050
1050
|
setSectionCollapsed((value) => !value)
|
|
1051
1051
|
}
|
|
1052
1052
|
|
|
1053
|
-
const openSession = (entry: Entry) =>
|
|
1053
|
+
const openSession = (entry: Entry) => {
|
|
1054
|
+
// Opening a session hands input back to the main view: release every
|
|
1055
|
+
// sidebar capture first, so its key layers cannot shadow the composer's
|
|
1056
|
+
// once the new session is open.
|
|
1057
|
+
menu.close()
|
|
1058
|
+
cancelDelete()
|
|
1059
|
+
setNavActive(false)
|
|
1060
|
+
setSearching(false)
|
|
1061
|
+
setHovered(undefined)
|
|
1062
|
+
props.api.route.navigate("session", { sessionID: entry.id })
|
|
1063
|
+
}
|
|
1054
1064
|
|
|
1055
1065
|
// Flat order of the rows a cursor can land on, so keyboard navigation and
|
|
1056
1066
|
// mouse hover resolve to the same row.
|
|
@@ -1064,6 +1074,15 @@ function SidebarSessions(props: { api: TuiPluginApi } & PinProps) {
|
|
|
1064
1074
|
return `${route.name}:${id}`
|
|
1065
1075
|
})
|
|
1066
1076
|
createEffect(on(routeKey, () => menu.close(), { defer: true }))
|
|
1077
|
+
// Navigating away also releases the sidebar's keyboard captures: a nav,
|
|
1078
|
+
// search, hover or armed delete left over from the previous session must
|
|
1079
|
+
// not shadow the composer's keys in the next one.
|
|
1080
|
+
createEffect(on(routeKey, () => {
|
|
1081
|
+
cancelDelete()
|
|
1082
|
+
setNavActive(false)
|
|
1083
|
+
setSearching(false)
|
|
1084
|
+
setHovered(undefined)
|
|
1085
|
+
}, { defer: true }))
|
|
1067
1086
|
createEffect(() => {
|
|
1068
1087
|
const state = menuState()
|
|
1069
1088
|
if (state && !itemRows().some((entry) => entry.id === state.entry.id)) menu.close()
|
|
@@ -1276,6 +1295,12 @@ function SidebarSessions(props: { api: TuiPluginApi } & PinProps) {
|
|
|
1276
1295
|
return
|
|
1277
1296
|
}
|
|
1278
1297
|
if (searching()) setSearching(false)
|
|
1298
|
+
// A click anywhere outside the sidebar means input is back in the main
|
|
1299
|
+
// view: release the nav layer, hover shortcuts and any armed delete so
|
|
1300
|
+
// the sidebar's keys and rows stop shadowing the composer.
|
|
1301
|
+
cancelDelete()
|
|
1302
|
+
if (navActive()) setNavActive(false)
|
|
1303
|
+
setHovered(undefined)
|
|
1279
1304
|
}
|
|
1280
1305
|
|
|
1281
1306
|
onMount(() => {
|
|
@@ -1346,6 +1371,8 @@ function SidebarSessions(props: { api: TuiPluginApi } & PinProps) {
|
|
|
1346
1371
|
|
|
1347
1372
|
// Keyboard navigation is opt-in (click the "Sessions" heading or the search
|
|
1348
1373
|
// box) so the sidebar never steals the arrow keys from the main prompt.
|
|
1374
|
+
// Clicking anywhere outside the sidebar, opening a session, or navigating
|
|
1375
|
+
// releases it again, so its layers cannot shadow the composer afterwards.
|
|
1349
1376
|
createEffect(() => {
|
|
1350
1377
|
disposeNav?.()
|
|
1351
1378
|
disposeNav = undefined
|
|
@@ -1450,7 +1477,10 @@ function SidebarSessions(props: { api: TuiPluginApi } & PinProps) {
|
|
|
1450
1477
|
return (
|
|
1451
1478
|
<box flexDirection="column" paddingRight={1} flexGrow={1} flexShrink={1}>
|
|
1452
1479
|
<box flexDirection="row" justifyContent="space-between" gap={1}>
|
|
1453
|
-
<text flexShrink={1} onMouseDown={() => {
|
|
1480
|
+
<text flexShrink={1} onMouseDown={(event: { stopPropagation: () => void }) => {
|
|
1481
|
+
// Sidebar-internal: keep this click from reaching the root handler,
|
|
1482
|
+
// which would release the nav layer this toggle just activated.
|
|
1483
|
+
event.stopPropagation()
|
|
1454
1484
|
if (!sectionCollapsed()) setNavActive((value) => !value)
|
|
1455
1485
|
}}>
|
|
1456
1486
|
<b>Sessions</b>
|
|
@@ -1462,7 +1492,10 @@ function SidebarSessions(props: { api: TuiPluginApi } & PinProps) {
|
|
|
1462
1492
|
<span style={{ fg: theme().warning }}> · {waitingEntries().length} need input</span>
|
|
1463
1493
|
</Show>
|
|
1464
1494
|
</text>
|
|
1465
|
-
<text flexShrink={0} style={{ fg: theme().textMuted }} onMouseDown={
|
|
1495
|
+
<text flexShrink={0} style={{ fg: theme().textMuted }} onMouseDown={(event: { stopPropagation: () => void }) => {
|
|
1496
|
+
event.stopPropagation()
|
|
1497
|
+
toggleSection()
|
|
1498
|
+
}}>
|
|
1466
1499
|
{sectionCollapsed() ? "▸ show" : "▾ hide"}
|
|
1467
1500
|
</text>
|
|
1468
1501
|
</box>
|
|
@@ -1481,7 +1514,10 @@ function SidebarSessions(props: { api: TuiPluginApi } & PinProps) {
|
|
|
1481
1514
|
paddingLeft={1}
|
|
1482
1515
|
paddingRight={1}
|
|
1483
1516
|
backgroundColor={searching() ? theme().backgroundElement : RGBA.fromInts(0, 0, 0, 0)}
|
|
1484
|
-
onMouseDown={() => {
|
|
1517
|
+
onMouseDown={(event: { stopPropagation: () => void }) => {
|
|
1518
|
+
// Sidebar-internal: the root handler must not see this click, or
|
|
1519
|
+
// it would clear the search this box just activated.
|
|
1520
|
+
event.stopPropagation()
|
|
1485
1521
|
insideSearchBox = true
|
|
1486
1522
|
setSearching(true)
|
|
1487
1523
|
}}
|
|
@@ -1497,7 +1533,10 @@ function SidebarSessions(props: { api: TuiPluginApi } & PinProps) {
|
|
|
1497
1533
|
{searching() ? "▏" : ""}
|
|
1498
1534
|
</text>
|
|
1499
1535
|
<Show when={query()}>
|
|
1500
|
-
<text flexShrink={0} style={{ fg: theme().textMuted }} onMouseDown={() =>
|
|
1536
|
+
<text flexShrink={0} style={{ fg: theme().textMuted }} onMouseDown={(event: { stopPropagation: () => void }) => {
|
|
1537
|
+
event.stopPropagation()
|
|
1538
|
+
setQuery("")
|
|
1539
|
+
}}>
|
|
1501
1540
|
✕
|
|
1502
1541
|
</text>
|
|
1503
1542
|
</Show>
|
|
@@ -1513,7 +1552,10 @@ function SidebarSessions(props: { api: TuiPluginApi } & PinProps) {
|
|
|
1513
1552
|
<For each={tree()}>
|
|
1514
1553
|
{(row) => {
|
|
1515
1554
|
if (row.kind === "group") return (
|
|
1516
|
-
<box flexDirection="row" paddingTop={1} onMouseDown={() =>
|
|
1555
|
+
<box flexDirection="row" paddingTop={1} onMouseDown={(event: { stopPropagation: () => void }) => {
|
|
1556
|
+
event.stopPropagation()
|
|
1557
|
+
toggleGroup(row.dir)
|
|
1558
|
+
}}>
|
|
1517
1559
|
<text flexGrow={1} flexShrink={1} wrapMode="none">
|
|
1518
1560
|
<span style={{ fg: theme().textMuted }}>{collapsed()[row.dir] ? "▸ " : "▾ "}</span>
|
|
1519
1561
|
<b>{props.pins().directories.includes(row.dir) ? "★ " : ""}{truncate(row.label, SIDEBAR_GROUP_WIDTH - (props.pins().directories.includes(row.dir) ? 2 : 0))}</b>
|
|
@@ -1550,7 +1592,13 @@ function SidebarSessions(props: { api: TuiPluginApi } & PinProps) {
|
|
|
1550
1592
|
if (event.button === RIGHT_BUTTON) {
|
|
1551
1593
|
event.stopPropagation()
|
|
1552
1594
|
menu.open(row.entry, event.x, event.y)
|
|
1553
|
-
} else
|
|
1595
|
+
} else {
|
|
1596
|
+
// Sidebar-internal: openSession releases the sidebar's own
|
|
1597
|
+
// captures, so this click must not also reach the root
|
|
1598
|
+
// handler as an outside click.
|
|
1599
|
+
event.stopPropagation()
|
|
1600
|
+
void openSession(row.entry)
|
|
1601
|
+
}
|
|
1554
1602
|
}}
|
|
1555
1603
|
>
|
|
1556
1604
|
<text flexShrink={0}>
|