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
+20 -19
View File
@@ -66,8 +66,8 @@ export class DataRoutes extends BaseRouteHandler {
* Get paginated observations
*/
private handleGetObservations = this.wrapHandler((req: Request, res: Response): void => {
const { offset, limit, project } = this.parsePaginationParams(req);
const result = this.paginationHelper.getObservations(offset, limit, project);
const { offset, limit, project, platformSource } = this.parsePaginationParams(req);
const result = this.paginationHelper.getObservations(offset, limit, project, platformSource);
res.json(result);
});
@@ -75,8 +75,8 @@ export class DataRoutes extends BaseRouteHandler {
* Get paginated summaries
*/
private handleGetSummaries = this.wrapHandler((req: Request, res: Response): void => {
const { offset, limit, project } = this.parsePaginationParams(req);
const result = this.paginationHelper.getSummaries(offset, limit, project);
const { offset, limit, project, platformSource } = this.parsePaginationParams(req);
const result = this.paginationHelper.getSummaries(offset, limit, project, platformSource);
res.json(result);
});
@@ -84,8 +84,8 @@ export class DataRoutes extends BaseRouteHandler {
* Get paginated user prompts
*/
private handleGetPrompts = this.wrapHandler((req: Request, res: Response): void => {
const { offset, limit, project } = this.parsePaginationParams(req);
const result = this.paginationHelper.getPrompts(offset, limit, project);
const { offset, limit, project, platformSource } = this.parsePaginationParams(req);
const result = this.paginationHelper.getPrompts(offset, limit, project, platformSource);
res.json(result);
});
@@ -256,19 +256,19 @@ export class DataRoutes extends BaseRouteHandler {
* GET /api/projects
*/
private handleGetProjects = this.wrapHandler((req: Request, res: Response): void => {
const db = this.dbManager.getSessionStore().db;
const store = this.dbManager.getSessionStore();
const platformSource = req.query.platformSource as string | undefined;
const rows = db.prepare(`
SELECT DISTINCT project
FROM observations
WHERE project IS NOT NULL
GROUP BY project
ORDER BY MAX(created_at_epoch) DESC
`).all() as Array<{ project: string }>;
if (platformSource) {
res.json({
projects: store.getAllProjects(platformSource),
sources: [platformSource],
projectsBySource: { [platformSource]: store.getAllProjects(platformSource) }
});
return;
}
const projects = rows.map(row => row.project);
res.json({ projects });
res.json(store.getProjectCatalog());
});
/**
@@ -299,12 +299,13 @@ export class DataRoutes extends BaseRouteHandler {
/**
* Parse pagination parameters from request query
*/
private parsePaginationParams(req: Request): { offset: number; limit: number; project?: string } {
private parsePaginationParams(req: Request): { offset: number; limit: number; project?: string; platformSource?: string } {
const offset = parseInt(req.query.offset as string, 10) || 0;
const limit = Math.min(parseInt(req.query.limit as string, 10) || 20, 100); // Max 100
const project = req.query.project as string | undefined;
const platformSource = req.query.platformSource as string | undefined;
return { offset, limit, project };
return { offset, limit, project, platformSource };
}
/**