feat(ui): hide observer-sessions project from UI lists

Observer sessions (internal SDK-driven worker queries) run under a
synthetic project name 'observer-sessions' to keep them out of
claude --resume. They were still surfacing in the viewer project
picker and unfiltered observation/summary/prompt feeds.

Filter them out at every UI-facing query:
- SessionStore.getAllProjects and getProjectCatalog
- timeline/queries.ts getAllProjects
- PaginationHelper observations/summaries/prompts when no project is selected

When a caller explicitly requests project='observer-sessions',
results are still returned (not a hard ban, just hidden by default).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Alex Newman
2026-04-16 20:05:37 -07:00
parent f6fda8fff4
commit d1601123fd
7 changed files with 116 additions and 96 deletions
+2
View File
@@ -1192,6 +1192,7 @@ export class SessionStore {
SELECT DISTINCT project
FROM sdk_sessions
WHERE project IS NOT NULL AND project != ''
AND project != 'observer-sessions'
`;
const params: unknown[] = [];
@@ -1218,6 +1219,7 @@ export class SessionStore {
MAX(started_at_epoch) as latest_epoch
FROM sdk_sessions
WHERE project IS NOT NULL AND project != ''
AND project != 'observer-sessions'
GROUP BY COALESCE(platform_source, '${DEFAULT_PLATFORM_SOURCE}'), project
ORDER BY latest_epoch DESC
`).all() as Array<{ platform_source: string; project: string; latest_epoch: number }>;
+1
View File
@@ -210,6 +210,7 @@ export function getAllProjects(db: Database): string[] {
SELECT DISTINCT project
FROM sdk_sessions
WHERE project IS NOT NULL AND project != ''
AND project != 'observer-sessions'
ORDER BY project ASC
`);
+9
View File
@@ -105,6 +105,9 @@ export class PaginationHelper {
// surfaces observations that originated under its merged children.
conditions.push('(o.project = ? OR o.merged_into_project = ?)');
params.push(project, project);
} else {
// Hide internal observer-session rows from the unfiltered UI list.
conditions.push("o.project != 'observer-sessions'");
}
if (platformSource) {
conditions.push(`COALESCE(s.platform_source, 'claude') = ?`);
@@ -163,6 +166,9 @@ export class PaginationHelper {
// surfaces rows that originated under its merged children.
conditions.push('(ss.project = ? OR ss.merged_into_project = ?)');
params.push(project, project);
} else {
// Hide internal observer-session rows from the unfiltered UI list.
conditions.push("ss.project != 'observer-sessions'");
}
if (platformSource) {
@@ -214,6 +220,9 @@ export class PaginationHelper {
if (project) {
conditions.push('s.project = ?');
params.push(project);
} else {
// Hide internal observer-session rows from the unfiltered UI list.
conditions.push("s.project != 'observer-sessions'");
}
if (platformSource) {
+4
View File
@@ -75,6 +75,10 @@ export const VECTOR_DB_DIR = join(DATA_DIR, 'vector-db');
// Sessions here won't appear in user's `claude --resume` for their actual projects
export const OBSERVER_SESSIONS_DIR = join(DATA_DIR, 'observer-sessions');
// Project name assigned to observer sessions (basename of OBSERVER_SESSIONS_DIR).
// UI queries filter this out so internal worker sessions don't pollute project lists.
export const OBSERVER_SESSIONS_PROJECT = 'observer-sessions';
// Claude integration paths
export const CLAUDE_SETTINGS_PATH = join(CLAUDE_CONFIG_DIR, 'settings.json');
export const CLAUDE_COMMANDS_DIR = join(CLAUDE_CONFIG_DIR, 'commands');