Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Fixed

- Branch, changes and pull request on the cards and the footer catch up within a second of a commit, checkout or edit made outside a turn, where they could lag up to three seconds, and selecting a card reads its checkout at once instead of showing what the last read found.
- Kiro CLI sessions follow `KIRO_HOME`. With it set, lich read Kiro's conversations, cost and context from `~/.kiro` while Kiro kept them under `KIRO_HOME`, so they showed nothing and History listed none; the agent that carries lich's hooks was installed where Kiro never looked, and a sandboxed session was not given the directory it writes into.

## [0.78.0] - 2026-10-22
Expand Down
3 changes: 2 additions & 1 deletion native/cmd/lich-native/cardstate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ func fakeUnread(t *testing.T, calls chan<- []any) *backend.Client {
_ = json.NewEncoder(w).Encode("")
case "/rpc/project.Home":
_ = json.NewEncoder(w).Encode(backend.Project{ID: "home", Path: "/home/me"})
case "/rpc/store.AddProject", "/rpc/store.AddSession":
case "/rpc/store.AddProject", "/rpc/store.AddSession",
"/rpc/project.Diff", "/rpc/project.BaseStatus", "/rpc/project.PullRequest":
_ = json.NewEncoder(w).Encode(nil)
case "/rpc/store.SetSessionUnread":
var args []api.SessionUnreadOptions
Expand Down
13 changes: 11 additions & 2 deletions native/cmd/lich-native/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ import (
)

// gitPoll is how often each shown path's branch and changes are re-read. The
// backend pushes no git events.
const gitPoll = 3 * time.Second
// backend pushes no git events. One second because a read is a few
// milliseconds per checkout (measured 3-35ms), while 3s left a commit made in a
// terminal off the card for long enough to read as lag.
const gitPoll = time.Second

// lastScreenKey is the global setting the last route is saved under, the one
// record of which project the user was on.
Expand Down Expand Up @@ -591,7 +593,14 @@ func (m *model) setActive(ctx context.Context, id string) {
}
readLeft := left != id && m.status.markSeen(left)
readNew := m.focused && m.status.markSeen(id)
shown := ""
if p, i := m.sessionAt(id); p != nil {
shown = m.shownPath(*p, p.Sessions[i])
}
m.mu.Unlock()
if shown != "" {
go m.refreshPath(ctx, shown)
}
if refocused {
m.saveLayouts()
}
Expand Down
27 changes: 27 additions & 0 deletions native/cmd/lich-native/stores_events_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,33 @@ func TestSessionTouchedReadsGitNowAndNudgesTheDiff(t *testing.T) {
}
}

func TestSelectingACardReadsItsGitWithoutATick(t *testing.T) {
var mu sync.Mutex
head := "h1"
stub := &rpcStub{answer: func(method string, _ []json.RawMessage) (any, int) {
mu.Lock()
defer mu.Unlock()
switch method {
case "project.Diff":
return backend.DiffStats{Branch: "main", Head: head}, http.StatusOK
case "project.BaseStatus", "project.PullRequest":
return nil, http.StatusOK
}
return failing("unexpected " + method)
}}
m := newTestModel(stub.client(t))
m.refreshGit(context.Background())

mu.Lock()
head = "h2"
mu.Unlock()
m.setActive(context.Background(), "s1")

eventually(t, "the selected card reads the new head without a tick", func() bool {
return cardOf(t, m).git.Head == "h2"
})
}

func TestSessionTouchedOfAnotherProjectWaitsForItsScreen(t *testing.T) {
stub := &rpcStub{answer: func(string, []json.RawMessage) (any, int) { return failing("unexpected") }}
m := newModel(stub.client(t), func() {})
Expand Down
Loading