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
19 changes: 11 additions & 8 deletions src/lib/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ export interface SessionBarConfig {
// "unfinished" drops the sessions that completed, errored, or were stopped,
// leaving the conversations still going. "all" keeps them.
statuses?: 'all' | 'unfinished'
// Only sessions started these ways, e.g. ["cli", "manual"]. Omit for all of
// them. Laptop sessions never appear whatever this says: there is nothing in
// the cloud to open.
// Only sessions started these ways, e.g. ["cli", "manual"]. An empty list
// means every source. Laptop sessions never appear whatever this says: there
// is nothing in the cloud to open.
Comment on lines +47 to +49

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

README's sessionBar docs now contradict this behavior and need the same edit.

README:188-190 says sources "lists only sessions started those ways ...; leave it out for all of them", and README:192 says the sample block's values "are what you get with no sessionBar at all". After this change omitting the key hides react/cron and [] is the only way to get them back — nothing in the README mentions either, and sessionBarFilterLabel (the one place that would have explained it in the UI) has no callers, so a user whose automated sessions vanished has no documented path back.

sources?: string[]
}

Expand Down Expand Up @@ -234,14 +234,16 @@ export function clearAllTokens(): void {
// standing in and the last week, which is short enough to read at a glance
// without hiding a session you are likely to reopen. `repo: 'cwd'` falls back
// to every repository outside a repo, so the bar is never mysteriously empty.
// The default sources are the ones a person started; `react` and `cron` fire on
// their own and would bury the sessions you are actually working in.
export const SESSION_BAR_DEFAULTS: Required<Omit<SessionBarConfig, 'sources'>> & {
sources: string[] | undefined
} = {
hidden: false,
days: 7,
repo: 'cwd',
statuses: 'all',
sources: undefined,
sources: ['manual', 'cli', 'mention'],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new default silently drops api sessions too, not just react/cron; add api to the list.

SESSION_SOURCES (config.ts:251) has six values and the default keeps three, so api is filtered out as well — neither the comment at 237-238 nor the PR description mentions it. The CLI is documented to run against an ELLIPSIS_API_TOKEN credential (config.ts:288, and test/sessions.test.ts:246 covers the API-key path), and the server derives a session's source from the credential (constants.ts:17), so sessions this CLI starts under an API key come back as api. With this default the poll (SessionsApp.tsx:164) sends source=manual,cli,mention and never returns them — a user authenticated by env token sees an empty session list containing none of their own sessions.

Suggested change
sources: ['manual', 'cli', 'mention'],
sources: ['manual', 'cli', 'mention', 'api'],

}

export type ResolvedSessionBar = typeof SESSION_BAR_DEFAULTS
Expand All @@ -257,7 +259,7 @@ export function sessionBar(): ResolvedSessionBar {
if (!raw || typeof raw !== 'object') return { ...SESSION_BAR_DEFAULTS }
const sources = Array.isArray(raw.sources)
? raw.sources.filter((s) => SESSION_SOURCES.includes(s))
: undefined
: null
Comment on lines 260 to +262

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A sources list whose entries are all unknown still resolves to "every source", so a typo now widens the list instead of narrowing it — fall back to the default instead.

With {"sessionBar": {"sources": ["mannual"]}} the filter at 261 yields [], line 277 maps that to undefined, and sessionBarQuery omits the source filter — the user asked for one source and gets react and cron as well. Before this change undefined and "key absent" were the same thing, so the typo was harmless; now it is the widest possible setting. (test/config.test.ts:259 pins the old behavior and would need updating.)

Suggested change
const sources = Array.isArray(raw.sources)
? raw.sources.filter((s) => SESSION_SOURCES.includes(s))
: undefined
: null
const known = Array.isArray(raw.sources)
? raw.sources.filter((s) => SESSION_SOURCES.includes(s))
: null
// An all-unknown list is a typo, not the [] "every source" escape hatch.
const sources =
known && known.length === 0 && Array.isArray(raw.sources) && raw.sources.length > 0
? null
: known

return {
hidden: raw.hidden === true,
days:
Expand All @@ -269,9 +271,10 @@ export function sessionBar(): ResolvedSessionBar {
raw.statuses === 'unfinished' || raw.statuses === 'all'
? raw.statuses
: SESSION_BAR_DEFAULTS.statuses,
// An explicit [] would list nothing at all, which no one means; treat it
// as "every source", the same as leaving the key out.
sources: sources && sources.length > 0 ? sources : undefined,
// An explicit [] would list nothing at all, which no one means; treat it as
// "every source" — the only way to ask for the automated ones too. Leaving
// the key out keeps the human-started default.
sources: sources === null ? SESSION_BAR_DEFAULTS.sources : sources.length > 0 ? sources : undefined,
}
}

Expand Down
12 changes: 8 additions & 4 deletions src/lib/sessions.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { sessionStatusWord } from '@ellipsis-dev/sdk/stream'
import type { Session as FrameSession } from '@ellipsis-dev/sdk'
import { SESSION_BAR_DEFAULTS } from './config'
import { theme } from './theme'
import type {
AgentSession,
Expand Down Expand Up @@ -212,9 +213,9 @@ export function sessionBarQuery(
export const SESSION_BAR_FETCH = 50

// The picker header's description of the bar's active filters — the answer to
// "where are the rest of my sessions?". Mirrors sessionBarQuery exactly: a
// clause appears here iff the matching filter went into the query. null when
// the list is unfiltered.
// "where are the rest of my sessions?". Mirrors sessionBarQuery, with one
// exception: the default sources are not named, since "manual/cli/mention" is
// what everyone sees and answers no question. null when there is nothing to say.
export function sessionBarFilterLabel(
bar: {
days: number
Expand All @@ -228,7 +229,10 @@ export function sessionBarFilterLabel(
if (bar.repo === 'cwd' && detectedRepo) clauses.push(detectedRepo)
if (bar.days > 0) clauses.push(`last ${bar.days === 1 ? 'day' : `${bar.days} days`}`)
if (bar.statuses === 'unfinished') clauses.push('unfinished')
if (bar.sources) clauses.push(`source ${bar.sources.join('/')}`)
const sources = bar.sources?.join('/')
if (sources && sources !== SESSION_BAR_DEFAULTS.sources?.join('/')) {
clauses.push(`source ${sources}`)
}
if (clauses.length === 0) return null
return `filtering to ${clauses.join(' · ')}`
}
Expand Down
5 changes: 5 additions & 0 deletions test/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,11 @@ describe('sessionBar', () => {
expect(sessionBar().sources).toBeUndefined()
})

it('defaults to the human-started sources when the key is absent', () => {
writeConfig({ version: 2, hosts: {}, sessionBar: { days: 3 } })
expect(sessionBar().sources).toEqual(['manual', 'cli', 'mention'])
})

it('takes days 0 as "no age cutoff", not as a missing value', () => {
writeConfig({ version: 2, hosts: {}, sessionBar: { days: 0 } })
expect(sessionBar().days).toBe(0)
Expand Down