feat: isolate Claude and Codex session sources

Persist platform_source across session creation, transcript ingestion, API query paths, and viewer state so Claude and Codex data can coexist without bleeding into each other.

- add platform-source normalization helpers and persist platform_source in sdk_sessions via migration 24 with backfill and indexing
- thread platformSource through CLI hooks, transcript processing, context generation, pagination, search routes, SSE payloads, and session management
- expose source-aware project catalogs, viewer tabs, context preview selectors, and source badges for observations, prompts, and summaries
- start the transcript watcher from the worker for transcript-based clients and preserve platform source during Codex ingestion
- auto-start the worker from the MCP server for MCP-only clients and tighten stdio-driven cleanup during shutdown
- keep createSDKSession backward compatible with existing custom-title callers while allowing explicit platform source forwarding
This commit is contained in:
huakson
2026-03-24 08:43:56 -03:00
parent e2a230286d
commit 2b60dd2932
46 changed files with 3665 additions and 607 deletions
@@ -136,7 +136,17 @@ export function ContextSettingsModal({
}, [settings]);
// Get context preview based on current form state
const { preview, isLoading, error, projects, selectedProject, setSelectedProject } = useContextPreview(formState);
const {
preview,
isLoading,
error,
projects,
sources,
selectedSource,
setSelectedSource,
selectedProject,
setSelectedProject
} = useContextPreview(formState);
const updateSetting = useCallback((key: keyof Settings, value: string) => {
const newState = { ...formState, [key]: value };
@@ -174,10 +184,23 @@ export function ContextSettingsModal({
<h2>Settings</h2>
<div className="header-controls">
<label className="preview-selector">
Preview for:
Source:
<select
value={selectedSource || ''}
onChange={(e) => setSelectedSource(e.target.value)}
disabled={sources.length === 0}
>
{sources.map(source => (
<option key={source} value={source}>{source}</option>
))}
</select>
</label>
<label className="preview-selector">
Project:
<select
value={selectedProject || ''}
onChange={(e) => setSelectedProject(e.target.value)}
disabled={projects.length === 0}
>
{projects.map(project => (
<option key={project} value={project}>{project}</option>