@@ -556,7 +556,15 @@ describe("Pipelines Registry - CQRS Tools", () => {
556556 expect ( mockEnhancedFetch ) . toHaveBeenCalledWith (
557557 "https://gitlab.example.com/api/v4/projects/test%2Fproject/jobs/1/trace"
558558 ) ;
559- expect ( result ) . toEqual ( { trace : mockTrace , totalLines : 3 , shownLines : 3 } ) ;
559+ // All 3 lines fit within default 200, no truncation
560+ expect ( result ) . toEqual ( {
561+ trace : mockTrace ,
562+ totalLines : 3 ,
563+ shownLines : 3 ,
564+ startLine : 0 ,
565+ hasMore : false ,
566+ nextStart : null ,
567+ } ) ;
560568 } ) ;
561569
562570 it ( "should default to 200 lines when no limit specified" , async ( ) => {
@@ -575,24 +583,36 @@ describe("Pipelines Registry - CQRS Tools", () => {
575583 action : "logs" ,
576584 project_id : "test/project" ,
577585 job_id : "1" ,
578- } ) ) as { trace : string ; totalLines : number ; shownLines : number } ;
586+ } ) ) as {
587+ trace : string ;
588+ totalLines : number ;
589+ shownLines : number ;
590+ startLine : number ;
591+ hasMore : boolean ;
592+ nextStart : number | null ;
593+ } ;
579594
580595 expect ( result ) . toHaveProperty ( "trace" ) ;
581596 expect ( result ) . toHaveProperty ( "totalLines" , 300 ) ;
582597 expect ( result ) . toHaveProperty ( "shownLines" , 200 ) ;
598+ // Default behavior (no start): shows last 200 lines, startLine=100
599+ expect ( result ) . toHaveProperty ( "startLine" , 100 ) ;
600+ expect ( result ) . toHaveProperty ( "hasMore" , false ) ;
601+ expect ( result ) . toHaveProperty ( "nextStart" , null ) ;
583602
584603 const trace = result . trace ;
585604 const traceLines = trace . split ( "\n" ) ;
586605
587606 expect ( traceLines ) . toHaveLength ( 201 ) ;
588- expect ( trace ) . toContain ( "100 lines hidden" ) ;
607+ // Default/negative start shows "last N" message
589608 expect ( trace ) . toContain ( "Showing last 200 of 300 lines" ) ;
609+ expect ( trace ) . toContain ( "lines 100-299" ) ;
590610 expect ( trace ) . toContain ( "Line 101: Some output here" ) ;
591611 expect ( trace ) . toContain ( "Line 300: Some output here" ) ;
592612 expect ( trace ) . not . toContain ( "Line 100: Some output here" ) ;
593613 } ) ;
594614
595- it ( "should truncate long job trace when limit is provided" , async ( ) => {
615+ it ( "should truncate long job trace when per_page is provided" , async ( ) => {
596616 const longTrace = Array ( 1000 ) . fill ( "Very long line with lots of content here" ) . join ( "\n" ) ;
597617 mockEnhancedFetch . mockResolvedValueOnce ( {
598618 ok : true ,
@@ -606,17 +626,29 @@ describe("Pipelines Registry - CQRS Tools", () => {
606626 action : "logs" ,
607627 project_id : "test/project" ,
608628 job_id : "1" ,
609- limit : 50 ,
610- } ) ) as { trace : string ; totalLines : number ; shownLines : number } ;
629+ per_page : 50 ,
630+ } ) ) as {
631+ trace : string ;
632+ totalLines : number ;
633+ shownLines : number ;
634+ startLine : number ;
635+ hasMore : boolean ;
636+ nextStart : number | null ;
637+ } ;
611638
612639 expect ( result ) . toHaveProperty ( "trace" ) ;
613- expect ( result . trace ) . toContain ( "lines hidden" ) ;
640+ // Default behavior (no start) shows last 50 lines
641+ expect ( result . trace ) . toContain ( "Showing last 50 of 1000 lines" ) ;
614642 expect ( result . trace . length ) . toBeLessThan ( longTrace . length ) ;
615643 expect ( result . totalLines ) . toBe ( 1000 ) ;
616644 expect ( result . shownLines ) . toBe ( 50 ) ;
645+ expect ( result . startLine ) . toBe ( 950 ) ;
646+ expect ( result . hasMore ) . toBe ( false ) ;
647+ expect ( result . nextStart ) . toBeNull ( ) ;
617648 } ) ;
618649
619- it ( "should handle start + limit combination correctly" , async ( ) => {
650+ it ( "should handle start + per_page combination correctly" , async ( ) => {
651+ // Positive start=50 with per_page=10: shows lines 50-59 from middle of log
620652 const lines = Array . from ( { length : 100 } , ( _ , i ) => `Line ${ i + 1 } content` ) ;
621653 const fullTrace = lines . join ( "\n" ) ;
622654
@@ -633,21 +665,35 @@ describe("Pipelines Registry - CQRS Tools", () => {
633665 project_id : "test/project" ,
634666 job_id : "1" ,
635667 start : 50 ,
636- limit : 10 ,
637- } ) ) as { trace : string ; totalLines : number ; shownLines : number } ;
668+ per_page : 10 ,
669+ } ) ) as {
670+ trace : string ;
671+ totalLines : number ;
672+ shownLines : number ;
673+ startLine : number ;
674+ hasMore : boolean ;
675+ nextStart : number | null ;
676+ } ;
638677
639678 const trace = result . trace ;
640679 const traceLines = trace . split ( "\n" ) ;
641680
681+ // 10 data lines + 1 truncation header
642682 expect ( traceLines ) . toHaveLength ( 11 ) ;
683+ // Positive start: position-aware message "Showing lines X-Y of Z"
684+ expect ( trace ) . toContain ( "Showing lines 50-59 of 100" ) ;
643685 expect ( trace ) . toContain ( "Line 51 content" ) ;
644686 expect ( trace ) . toContain ( "Line 60 content" ) ;
645687 expect ( trace ) . not . toContain ( "Line 61 content" ) ;
646688 expect ( result . totalLines ) . toBe ( 100 ) ;
647689 expect ( result . shownLines ) . toBe ( 10 ) ;
690+ expect ( result . startLine ) . toBe ( 50 ) ;
691+ expect ( result . hasMore ) . toBe ( true ) ;
692+ expect ( result . nextStart ) . toBe ( 60 ) ;
648693 } ) ;
649694
650695 it ( "should handle negative start correctly" , async ( ) => {
696+ // Negative start=-50 with per_page=30: takes last 50, then limits to last 30
651697 const lines = Array . from ( { length : 200 } , ( _ , i ) => `Line ${ i + 1 } content` ) ;
652698 const fullTrace = lines . join ( "\n" ) ;
653699
@@ -664,16 +710,28 @@ describe("Pipelines Registry - CQRS Tools", () => {
664710 project_id : "test/project" ,
665711 job_id : "1" ,
666712 start : - 50 ,
667- max_lines : 30 ,
668- } ) ) as { trace : string ; totalLines : number ; shownLines : number } ;
713+ per_page : 30 ,
714+ } ) ) as {
715+ trace : string ;
716+ totalLines : number ;
717+ shownLines : number ;
718+ startLine : number ;
719+ hasMore : boolean ;
720+ nextStart : number | null ;
721+ } ;
669722
670723 const trace = result . trace ;
671724
725+ // Negative start: "Showing last N" message
726+ expect ( trace ) . toContain ( "Showing last 30 of 200 lines" ) ;
672727 expect ( trace ) . toContain ( "Line 171 content" ) ;
673728 expect ( trace ) . toContain ( "Line 200 content" ) ;
674729 expect ( trace ) . not . toContain ( "Line 170 content" ) ;
675730 expect ( result . totalLines ) . toBe ( 200 ) ;
676731 expect ( result . shownLines ) . toBe ( 30 ) ;
732+ expect ( result . startLine ) . toBe ( 170 ) ;
733+ expect ( result . hasMore ) . toBe ( false ) ;
734+ expect ( result . nextStart ) . toBeNull ( ) ;
677735 } ) ;
678736
679737 it ( "should handle out of bounds start position" , async ( ) => {
@@ -693,12 +751,22 @@ describe("Pipelines Registry - CQRS Tools", () => {
693751 project_id : "test/project" ,
694752 job_id : "1" ,
695753 start : 100 ,
696- limit : 10 ,
697- } ) ) as { trace : string ; totalLines : number ; shownLines : number } ;
754+ per_page : 10 ,
755+ } ) ) as {
756+ trace : string ;
757+ totalLines : number ;
758+ shownLines : number ;
759+ startLine : number ;
760+ hasMore : boolean ;
761+ nextStart : number | null ;
762+ } ;
698763
699764 expect ( result . trace ) . toContain ( "OUT OF BOUNDS" ) ;
700765 expect ( result . totalLines ) . toBe ( 50 ) ;
701766 expect ( result . shownLines ) . toBe ( 0 ) ;
767+ expect ( result . startLine ) . toBe ( 100 ) ;
768+ expect ( result . hasMore ) . toBe ( false ) ;
769+ expect ( result . nextStart ) . toBeNull ( ) ;
702770 } ) ;
703771
704772 // Test for line 89: error handling when fetch returns non-ok response
@@ -720,7 +788,7 @@ describe("Pipelines Registry - CQRS Tools", () => {
720788 ) . rejects . toThrow ( "GitLab API error: 404 Not Found" ) ;
721789 } ) ;
722790
723- // Test for lines 120-121: partial request message when start + max_lines exceeds total
791+ // Test for partial request: start + per_page exceeds total lines
724792 it ( "should show partial request message when requested range exceeds available lines" , async ( ) => {
725793 const lines = Array . from ( { length : 50 } , ( _ , i ) => `Line ${ i + 1 } content` ) ;
726794 const fullTrace = lines . join ( "\n" ) ;
@@ -738,15 +806,63 @@ describe("Pipelines Registry - CQRS Tools", () => {
738806 project_id : "test/project" ,
739807 job_id : "1" ,
740808 start : 40 ,
741- max_lines : 20 ,
742- } ) ) as { trace : string ; totalLines : number ; shownLines : number } ;
809+ per_page : 20 ,
810+ } ) ) as {
811+ trace : string ;
812+ totalLines : number ;
813+ shownLines : number ;
814+ startLine : number ;
815+ hasMore : boolean ;
816+ nextStart : number | null ;
817+ } ;
743818
744- // start=40, max_lines =20 means requesting lines 40-59, but only 40-49 exist
819+ // start=40, per_page =20 means requesting lines 40-59, but only 40-49 exist
745820 expect ( result . trace ) . toContain ( "PARTIAL REQUEST" ) ;
746821 expect ( result . trace ) . toContain ( "Requested 20 lines from position 40" ) ;
747822 expect ( result . trace ) . toContain ( "only 10 lines available" ) ;
748823 expect ( result . totalLines ) . toBe ( 50 ) ;
749824 expect ( result . shownLines ) . toBe ( 10 ) ;
825+ expect ( result . startLine ) . toBe ( 40 ) ;
826+ expect ( result . hasMore ) . toBe ( false ) ;
827+ expect ( result . nextStart ) . toBeNull ( ) ;
828+ } ) ;
829+
830+ // Test: start=0 shows position-aware message, NOT "last N"
831+ it ( "should show position-aware message when start=0" , async ( ) => {
832+ const lines = Array . from ( { length : 100 } , ( _ , i ) => `Line ${ i + 1 } content` ) ;
833+ const fullTrace = lines . join ( "\n" ) ;
834+
835+ mockEnhancedFetch . mockResolvedValueOnce ( {
836+ ok : true ,
837+ status : 200 ,
838+ statusText : "OK" ,
839+ text : jest . fn ( ) . mockResolvedValue ( fullTrace ) ,
840+ } as never ) ;
841+
842+ const tool = pipelinesToolRegistry . get ( "browse_pipelines" ) ! ;
843+ const result = ( await tool . handler ( {
844+ action : "logs" ,
845+ project_id : "test/project" ,
846+ job_id : "1" ,
847+ start : 0 ,
848+ per_page : 15 ,
849+ } ) ) as {
850+ trace : string ;
851+ totalLines : number ;
852+ shownLines : number ;
853+ startLine : number ;
854+ hasMore : boolean ;
855+ nextStart : number | null ;
856+ } ;
857+
858+ // start=0: should say "Showing lines 0-14 of 100", NOT "Showing last 15"
859+ expect ( result . trace ) . toContain ( "Showing lines 0-14 of 100" ) ;
860+ expect ( result . trace ) . not . toContain ( "last" ) ;
861+ expect ( result . totalLines ) . toBe ( 100 ) ;
862+ expect ( result . shownLines ) . toBe ( 15 ) ;
863+ expect ( result . startLine ) . toBe ( 0 ) ;
864+ expect ( result . hasMore ) . toBe ( true ) ;
865+ expect ( result . nextStart ) . toBe ( 15 ) ;
750866 } ) ;
751867 } ) ;
752868
0 commit comments