@@ -24,7 +24,10 @@ import {
2424 toPersistenceSqlError ,
2525 type ProjectionRepositoryError ,
2626} from "../../persistence/Errors.ts" ;
27- import { ProjectionOverviewQuery , type ProjectionOverviewQueryShape } from "../Services/ProjectionOverviewQuery.ts" ;
27+ import {
28+ ProjectionOverviewQuery ,
29+ type ProjectionOverviewQueryShape ,
30+ } from "../Services/ProjectionOverviewQuery.ts" ;
2831import { ProjectionState } from "../../persistence/Services/ProjectionState.ts" ;
2932import { ProjectionProject } from "../../persistence/Services/ProjectionProjects.ts" ;
3033import { ProjectionThread } from "../../persistence/Services/ProjectionThreads.ts" ;
@@ -75,7 +78,9 @@ const ProjectionThreadPlanSummaryRow = Schema.Struct({
7578const ProjectionStateDbRowSchema = ProjectionState ;
7679const ProjectionThreadSessionDbRowSchema = ProjectionThreadSession ;
7780
78- function parseGithubRef ( serialized : string | null ) : OrchestrationOverviewThread [ "githubRef" ] | undefined {
81+ function parseGithubRef (
82+ serialized : string | null ,
83+ ) : OrchestrationOverviewThread [ "githubRef" ] | undefined {
7984 if ( ! serialized ) return undefined ;
8085 try {
8186 return JSON . parse ( serialized ) as OrchestrationOverviewThread [ "githubRef" ] ;
@@ -153,13 +158,14 @@ function hasActionablePlan(
153158 const matchingTurnPlan =
154159 latestTurnId === null
155160 ? null
156- : [ ...plans ]
161+ : ( [ ...plans ]
157162 . filter ( ( plan ) => plan . turnId === latestTurnId )
158163 . toSorted (
159164 ( left , right ) =>
160- left . updatedAt . localeCompare ( right . updatedAt ) || left . planId . localeCompare ( right . planId ) ,
165+ left . updatedAt . localeCompare ( right . updatedAt ) ||
166+ left . planId . localeCompare ( right . planId ) ,
161167 )
162- . at ( - 1 ) ?? null ;
168+ . at ( - 1 ) ?? null ) ;
163169 if ( matchingTurnPlan ) {
164170 return matchingTurnPlan . implementedAt === null ;
165171 }
@@ -315,109 +321,120 @@ const makeProjectionOverviewQuery = Effect.gen(function* () {
315321 } ) ;
316322
317323 const getOverview : ProjectionOverviewQueryShape [ "getOverview" ] = ( ) =>
318- sql . withTransaction (
319- Effect . gen ( function * ( ) {
320- const [ projectRows , threadRows , latestTurnRows , sessionRows , planRows , stateRows ] =
321- yield * Effect . all ( [
322- listProjectRows ( undefined ) ,
323- listThreadRows ( undefined ) ,
324- listLatestTurnRows ( undefined ) ,
325- listSessionRows ( undefined ) ,
326- listPlanRows ( undefined ) ,
327- listProjectionStateRows ( undefined ) ,
328- ] ) ;
324+ sql
325+ . withTransaction (
326+ Effect . gen ( function * ( ) {
327+ const [ projectRows , threadRows , latestTurnRows , sessionRows , planRows , stateRows ] =
328+ yield * Effect . all ( [
329+ listProjectRows ( undefined ) ,
330+ listThreadRows ( undefined ) ,
331+ listLatestTurnRows ( undefined ) ,
332+ listSessionRows ( undefined ) ,
333+ listPlanRows ( undefined ) ,
334+ listProjectionStateRows ( undefined ) ,
335+ ] ) ;
329336
330- const latestTurnByThread = new Map < string , OrchestrationLatestTurn > ( ) ;
331- for ( const row of latestTurnRows ) {
332- if ( ! latestTurnByThread . has ( row . threadId ) ) {
333- latestTurnByThread . set ( row . threadId , toLatestTurn ( row ) ) ;
337+ const latestTurnByThread = new Map < string , OrchestrationLatestTurn > ( ) ;
338+ for ( const row of latestTurnRows ) {
339+ if ( ! latestTurnByThread . has ( row . threadId ) ) {
340+ latestTurnByThread . set ( row . threadId , toLatestTurn ( row ) ) ;
341+ }
334342 }
335- }
336343
337- const sessionByThread = new Map < string , OrchestrationSession > ( ) ;
338- for ( const row of sessionRows ) {
339- sessionByThread . set ( row . threadId , {
340- threadId : row . threadId ,
341- status : row . status ,
342- providerName : row . providerName ,
343- runtimeMode : row . runtimeMode ,
344- activeTurnId : row . activeTurnId ,
345- lastError : row . lastError ,
346- updatedAt : row . updatedAt ,
347- } ) ;
348- }
349-
350- const plansByThread = new Map < string , Array < Schema . Schema . Type < typeof ProjectionThreadPlanSummaryRow > > > ( ) ;
351- for ( const row of planRows ) {
352- const plans = plansByThread . get ( row . threadId ) ?? [ ] ;
353- plans . push ( row ) ;
354- plansByThread . set ( row . threadId , plans ) ;
355- }
344+ const sessionByThread = new Map < string , OrchestrationSession > ( ) ;
345+ for ( const row of sessionRows ) {
346+ sessionByThread . set ( row . threadId , {
347+ threadId : row . threadId ,
348+ status : row . status ,
349+ providerName : row . providerName ,
350+ runtimeMode : row . runtimeMode ,
351+ activeTurnId : row . activeTurnId ,
352+ lastError : row . lastError ,
353+ updatedAt : row . updatedAt ,
354+ } ) ;
355+ }
356356
357- const projects : OrchestrationOverviewProject [ ] = projectRows . map ( ( row ) => ( {
358- id : row . projectId ,
359- title : row . title ,
360- workspaceRoot : row . workspaceRoot ,
361- defaultModel : row . defaultModel ,
362- scripts : row . scripts ,
363- activeThreadCount : row . activeThreadCount ,
364- createdAt : row . createdAt ,
365- updatedAt : row . updatedAt ,
366- } ) ) ;
357+ const plansByThread = new Map <
358+ string ,
359+ Array < Schema . Schema . Type < typeof ProjectionThreadPlanSummaryRow > >
360+ > ( ) ;
361+ for ( const row of planRows ) {
362+ const plans = plansByThread . get ( row . threadId ) ?? [ ] ;
363+ plans . push ( row ) ;
364+ plansByThread . set ( row . threadId , plans ) ;
365+ }
367366
368- const threads : OrchestrationOverviewThread [ ] = threadRows . map ( ( row ) => {
369- const latestTurn = latestTurnByThread . get ( row . threadId ) ?? null ;
370- return {
371- id : row . threadId ,
372- projectId : row . projectId ,
367+ const projects : OrchestrationOverviewProject [ ] = projectRows . map ( ( row ) => ( {
368+ id : row . projectId ,
373369 title : row . title ,
374- model : row . model ,
375- runtimeMode : row . runtimeMode ,
376- interactionMode : row . interactionMode ,
377- branch : row . branch ,
378- worktreePath : row . worktreePath ,
379- ...( parseGithubRef ( row . githubRef ) ? { githubRef : parseGithubRef ( row . githubRef ) } : { } ) ,
380- latestTurn,
381- session : sessionByThread . get ( row . threadId ) ?? null ,
370+ workspaceRoot : row . workspaceRoot ,
371+ defaultModel : row . defaultModel ,
372+ scripts : row . scripts ,
373+ activeThreadCount : row . activeThreadCount ,
382374 createdAt : row . createdAt ,
383375 updatedAt : row . updatedAt ,
384- lastUserMessageAt : row . lastUserMessageAt ,
385- pendingApprovalCount : row . pendingApprovalCount ,
386- pendingUserInputCount : row . pendingUserInputCount ,
387- hasActionablePlan : hasActionablePlan ( plansByThread . get ( row . threadId ) ?? [ ] , latestTurn ) ,
388- } ;
389- } ) ;
376+ } ) ) ;
390377
391- const updatedAtCandidates = [
392- ...projectRows . map ( ( row ) => row . updatedAt ) ,
393- ...threadRows . map ( ( row ) => row . updatedAt ) ,
394- ...sessionRows . map ( ( row ) => row . updatedAt ) ,
395- ...stateRows . map ( ( row ) => row . updatedAt ) ,
396- ] ;
378+ const threads : OrchestrationOverviewThread [ ] = threadRows . map ( ( row ) => {
379+ const latestTurn = latestTurnByThread . get ( row . threadId ) ?? null ;
380+ return {
381+ id : row . threadId ,
382+ projectId : row . projectId ,
383+ title : row . title ,
384+ model : row . model ,
385+ runtimeMode : row . runtimeMode ,
386+ interactionMode : row . interactionMode ,
387+ branch : row . branch ,
388+ worktreePath : row . worktreePath ,
389+ ...( parseGithubRef ( row . githubRef )
390+ ? { githubRef : parseGithubRef ( row . githubRef ) }
391+ : { } ) ,
392+ latestTurn,
393+ session : sessionByThread . get ( row . threadId ) ?? null ,
394+ createdAt : row . createdAt ,
395+ updatedAt : row . updatedAt ,
396+ lastUserMessageAt : row . lastUserMessageAt ,
397+ pendingApprovalCount : row . pendingApprovalCount ,
398+ pendingUserInputCount : row . pendingUserInputCount ,
399+ hasActionablePlan : hasActionablePlan (
400+ plansByThread . get ( row . threadId ) ?? [ ] ,
401+ latestTurn ,
402+ ) ,
403+ } ;
404+ } ) ;
397405
398- return Schema . decodeUnknownSync ( OrchestrationOverviewSnapshot ) ( {
399- snapshotSequence : computeSnapshotSequence ( stateRows ) ,
400- limits : {
401- maxProjects : MAX_PROJECTS ,
402- maxThreadsPerProject : MAX_THREADS_PER_PROJECT ,
403- } ,
404- projects,
405- threads,
406- updatedAt :
407- updatedAtCandidates . sort ( ( left , right ) => ( left < right ? 1 : left > right ? - 1 : 0 ) ) [ 0 ] ??
408- new Date ( 0 ) . toISOString ( ) ,
409- } ) ;
410- } ) ,
411- ) . pipe (
412- Effect . mapError ( ( cause ) : ProjectionRepositoryError => {
413- if ( Schema . isSchemaError ( cause ) ) {
414- return toPersistenceDecodeError ( "ProjectionOverviewQuery.getOverview:decode" ) ( cause ) ;
415- }
416- return isPersistenceError ( cause )
417- ? cause
418- : toPersistenceSqlError ( "ProjectionOverviewQuery.getOverview:query" ) ( cause ) ;
419- } ) ,
420- ) ;
406+ const updatedAtCandidates = [
407+ ...projectRows . map ( ( row ) => row . updatedAt ) ,
408+ ...threadRows . map ( ( row ) => row . updatedAt ) ,
409+ ...sessionRows . map ( ( row ) => row . updatedAt ) ,
410+ ...stateRows . map ( ( row ) => row . updatedAt ) ,
411+ ] ;
412+
413+ return Schema . decodeUnknownSync ( OrchestrationOverviewSnapshot ) ( {
414+ snapshotSequence : computeSnapshotSequence ( stateRows ) ,
415+ limits : {
416+ maxProjects : MAX_PROJECTS ,
417+ maxThreadsPerProject : MAX_THREADS_PER_PROJECT ,
418+ } ,
419+ projects,
420+ threads,
421+ updatedAt :
422+ updatedAtCandidates . sort ( ( left , right ) =>
423+ left < right ? 1 : left > right ? - 1 : 0 ,
424+ ) [ 0 ] ?? new Date ( 0 ) . toISOString ( ) ,
425+ } ) ;
426+ } ) ,
427+ )
428+ . pipe (
429+ Effect . mapError ( ( cause ) : ProjectionRepositoryError => {
430+ if ( Schema . isSchemaError ( cause ) ) {
431+ return toPersistenceDecodeError ( "ProjectionOverviewQuery.getOverview:decode" ) ( cause ) ;
432+ }
433+ return isPersistenceError ( cause )
434+ ? cause
435+ : toPersistenceSqlError ( "ProjectionOverviewQuery.getOverview:query" ) ( cause ) ;
436+ } ) ,
437+ ) ;
421438
422439 return { getOverview } satisfies ProjectionOverviewQueryShape ;
423440} ) ;
0 commit comments