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
13 changes: 11 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1667,8 +1667,17 @@ the popup shrinks as candidates drop out without moving the composer. Longer
lists scroll within the available space (arrows or mouse wheel in the terminal).
Up/Down selects, Tab completes the name, Enter opens its options and Escape
dismisses suggestions while retaining the draft and typing focus. Suggestions
are fetched asynchronously and filtered locally. They also work in a selected
wide terminal session row when space permits. In terminal full detail, pressing
are filtered locally. Codexometer warms command catalogues in the background as
connected sessions are discovered, retaining the submenus already fetched during
discovery and any deeper levels visited afterwards in a
bounded, in-memory tree shared by the terminal and web backends. Cached levels
can be reused for up to two minutes; connection, directory, name and model-setting
changes invalidate the affected metadata. The terminal opens warm menus immediately.
Local display commands remain available while initial discovery is running.
Explicit **Refresh** bypasses the cache, and applying a setting always validates
fresh server state. Nothing is written to disk; restarting clears the cache.
Suggestions also work in a selected wide terminal session row when space permits.
In terminal full detail, pressing
`/` also focuses the composer and starts this expansion when a composer is
available; read-only sessions retain a command picker for local display settings.
Submenus stay in that same expanding list above the command line: type to filter
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ require (
github.com/charmbracelet/x/term v0.2.2
github.com/gorilla/websocket v1.5.3
go.starlark.net v0.0.0-20260930220527-d7438c5a85ac
golang.org/x/sync v0.23.0
golang.org/x/sys v0.48.0
golang.org/x/text v0.42.0
)
Expand All @@ -27,5 +28,4 @@ require (
github.com/muesli/cancelreader v0.2.2 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
golang.org/x/sync v0.23.0 // indirect
)
12 changes: 10 additions & 2 deletions internal/codex/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,23 @@ func (c Client) FetchTokenUsage(ctx context.Context) (LiveUsageSnapshot, error)
if c.LiveUsage == nil {
return LiveUsageSnapshot{}, errors.New("local Codex session telemetry is not configured")
}
return c.LiveUsage.FetchTokenUsage(ctx)
usage, err := c.LiveUsage.FetchTokenUsage(ctx)
if err == nil {
c.warmSessionCommands(usage)
}
return usage, err
}

// FetchTokenUsageFresh forces complete local rollout discovery.
func (c Client) FetchTokenUsageFresh(ctx context.Context) (LiveUsageSnapshot, error) {
if c.LiveUsage == nil {
return LiveUsageSnapshot{}, errors.New("local Codex session telemetry is not configured")
}
return c.LiveUsage.FetchTokenUsageFresh(ctx)
usage, err := c.LiveUsage.FetchTokenUsageFresh(ctx)
if err == nil {
c.warmSessionCommands(usage)
}
return usage, err
}

type rpcError struct {
Expand Down
28 changes: 24 additions & 4 deletions internal/codex/daemon_status_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@ const (
)

type daemonStatusProvider struct {
queueRevision uint64
queueCapabilities map[string]queueCapability
contexts map[string]*daemonContextState
socketPath string
commandGeneration uint64
commandTransitions map[string]uint64
queueRevision uint64
queueCapabilities map[string]queueCapability
contexts map[string]*daemonContextState
socketPath string

mu sync.Mutex
connection *websocket.Conn
Expand Down Expand Up @@ -121,6 +123,11 @@ func (p *daemonStatusProvider) Fetch(ctx context.Context, threadIDs []string) (s
p.mu.Lock()
p.lastStatusAt = time.Now()
p.statusThreads = stringStructSet(threadIDs)
for id, status := range statuses {
if p.statuses[id] != status {
p.bumpCommandTransitionLocked(id)
}
}
p.statuses = cloneRuntimeStatuses(statuses)
snapshot := p.statusSnapshotLocked(threadIDs)
p.mu.Unlock()
Expand Down Expand Up @@ -251,6 +258,8 @@ func (p *daemonStatusProvider) ensureConnected(ctx context.Context) error {
return nil
}
p.connection = connection
p.commandGeneration++
p.commandTransitions = make(map[string]uint64)
p.pending = make(map[int64]chan daemonEnvelope)
p.subscribed = make(map[string]struct{})
p.reroutedTurns = make(map[daemonTurnKey]string)
Expand Down Expand Up @@ -421,6 +430,16 @@ func (p *daemonStatusProvider) readLoop(connection *websocket.Conn) {
}

func (p *daemonStatusProvider) handleNotification(method string, params json.RawMessage) {
// Turn events catch complete cycles between status polls. The counter is
// monotonic for this session and connection, so an old scope cannot revive.
if method == "turn/started" || method == "turn/completed" || method == "turn/interrupted" {
var event struct{ ThreadID string }
if json.Unmarshal(params, &event) == nil && event.ThreadID != "" {
p.mu.Lock()
p.bumpCommandTransitionLocked(event.ThreadID)
p.mu.Unlock()
}
}
switch method {
case "thread/settings/updated":
var notification struct {
Expand Down Expand Up @@ -536,6 +555,7 @@ func (p *daemonStatusProvider) disconnect(connection *websocket.Conn) {
p.lastStatusAt = time.Time{}
p.statusThreads = nil
p.statuses = nil
p.commandTransitions = nil
p.threadSettings = nil
p.threadDirectories = nil
if p.settingsSignal != nil {
Expand Down
2 changes: 2 additions & 0 deletions internal/codex/live_usage.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ type LiveUsageReader struct {
SessionsRoot string
WriterLocksRoot string
statusProvider sessionStatusProvider
commandMu sync.Mutex
commandMenus *sessionCommandCache

mu sync.Mutex
initialized bool
Expand Down
Loading
Loading