@@ -4,8 +4,11 @@ import { runCli } from "./index.js";
44import {
55 captureOutput ,
66 createTempStorage ,
7+ createArchivedTask ,
78 CapturedOutput ,
9+ TASK_ID_REGEX ,
810} from "./test-helpers.js" ;
11+ import { ArchiveStorage } from "../core/storage/archive-storage.js" ;
912
1013describe ( "list command" , ( ) => {
1114 let storage : FileStorage ;
@@ -94,7 +97,7 @@ describe("list command", () => {
9497 await runCli ( [ "create" , "-n" , "Parent task" , "--description" , "ctx" ] , {
9598 storage,
9699 } ) ;
97- const parentId = output . stdout . join ( "\n" ) . match ( / \b ( [ a - z 0 - 9 ] { 8 } ) \b / ) ?. [ 1 ] ;
100+ const parentId = output . stdout . join ( "\n" ) . match ( TASK_ID_REGEX ) ?. [ 1 ] ;
98101 expect ( parentId ) . toBeDefined ( ) ;
99102
100103 await runCli (
@@ -140,7 +143,7 @@ describe("list command", () => {
140143 it ( "shows full tree with 3 levels" , async ( ) => {
141144 // Create epic -> task -> subtask hierarchy
142145 await runCli ( [ "create" , "-n" , "Epic" , "--description" , "ctx" ] , { storage } ) ;
143- const epicId = output . stdout . join ( "\n" ) . match ( / \b ( [ a - z 0 - 9 ] { 8 } ) \b / ) ?. [ 1 ] ;
146+ const epicId = output . stdout . join ( "\n" ) . match ( TASK_ID_REGEX ) ?. [ 1 ] ;
144147
145148 await runCli (
146149 [
@@ -154,7 +157,7 @@ describe("list command", () => {
154157 ] ,
155158 { storage } ,
156159 ) ;
157- const taskId = output . stdout . join ( "\n" ) . match ( / \b ( [ a - z 0 - 9 ] { 8 } ) \b / ) ?. [ 1 ] ;
160+ const taskId = output . stdout . join ( "\n" ) . match ( TASK_ID_REGEX ) ?. [ 1 ] ;
158161
159162 await runCli (
160163 [ "create" , "-n" , "Subtask" , "--description" , "ctx" , "--parent" , taskId ! ] ,
@@ -175,7 +178,7 @@ describe("list command", () => {
175178 await runCli ( [ "create" , "-n" , "Task A" , "--description" , "ctx" ] , {
176179 storage,
177180 } ) ;
178- const blockerMatch = output . stdout . join ( "\n" ) . match ( / \b ( [ a - z 0 - 9 ] { 8 } ) \b / ) ;
181+ const blockerMatch = output . stdout . join ( "\n" ) . match ( TASK_ID_REGEX ) ;
179182 const blockerId = blockerMatch ?. [ 1 ] ;
180183 expect ( blockerId ) . toBeDefined ( ) ;
181184
@@ -207,7 +210,7 @@ describe("list command", () => {
207210 await runCli ( [ "create" , "-n" , "Task A" , "--description" , "ctx" ] , {
208211 storage,
209212 } ) ;
210- const blockerMatch = output . stdout . join ( "\n" ) . match ( / \b ( [ a - z 0 - 9 ] { 8 } ) \b / ) ;
213+ const blockerMatch = output . stdout . join ( "\n" ) . match ( TASK_ID_REGEX ) ;
211214 const blockerId = blockerMatch ?. [ 1 ] ;
212215
213216 // Create blocked task
@@ -237,7 +240,7 @@ describe("list command", () => {
237240 await runCli ( [ "create" , "-n" , "Task A" , "--description" , "ctx" ] , {
238241 storage,
239242 } ) ;
240- const blockerMatch = output . stdout . join ( "\n" ) . match ( / \b ( [ a - z 0 - 9 ] { 8 } ) \b / ) ;
243+ const blockerMatch = output . stdout . join ( "\n" ) . match ( TASK_ID_REGEX ) ;
241244 const blockerId = blockerMatch ?. [ 1 ] ;
242245
243246 // Create blocked task
@@ -267,7 +270,7 @@ describe("list command", () => {
267270 await runCli ( [ "create" , "-n" , "GitHub task" , "--description" , "ctx" ] , {
268271 storage,
269272 } ) ;
270- const taskId = output . stdout . join ( "\n" ) . match ( / \b ( [ a - z 0 - 9 ] { 8 } ) \b / ) ?. [ 1 ] ;
273+ const taskId = output . stdout . join ( "\n" ) . match ( TASK_ID_REGEX ) ?. [ 1 ] ;
271274 expect ( taskId ) . toBeDefined ( ) ;
272275
273276 // Add GitHub metadata via store read/write
@@ -295,7 +298,7 @@ describe("list command", () => {
295298 await runCli ( [ "create" , "-n" , "Parent task" , "--description" , "ctx" ] , {
296299 storage,
297300 } ) ;
298- const parentId = output . stdout . join ( "\n" ) . match ( / \b ( [ a - z 0 - 9 ] { 8 } ) \b / ) ?. [ 1 ] ;
301+ const parentId = output . stdout . join ( "\n" ) . match ( TASK_ID_REGEX ) ?. [ 1 ] ;
299302 expect ( parentId ) . toBeDefined ( ) ;
300303
301304 // Add GitHub metadata to parent via store read/write
@@ -333,4 +336,145 @@ describe("list command", () => {
333336 // Both parent and subtask should show the GitHub indicator
334337 expect ( out ) . toContain ( "[GH-456]" ) ;
335338 } ) ;
339+
340+ describe ( "--archived flag" , ( ) => {
341+ it ( "lists archived tasks with --archived flag" , async ( ) => {
342+ // Add archived task directly to archive storage
343+ const archiveStorage = new ArchiveStorage ( {
344+ path : storage . getIdentifier ( ) ,
345+ } ) ;
346+ const archivedTask = createArchivedTask ( {
347+ id : "arch1234" ,
348+ name : "Old completed task" ,
349+ result : "Was done successfully" ,
350+ } ) ;
351+ archiveStorage . appendArchive ( [ archivedTask ] ) ;
352+
353+ await runCli ( [ "list" , "--archived" ] , { storage } ) ;
354+
355+ const out = output . stdout . join ( "\n" ) ;
356+ expect ( out ) . toContain ( "Old completed task" ) ;
357+ expect ( out ) . toContain ( "arch1234" ) ;
358+ } ) ;
359+
360+ it ( "shows empty state when no archived tasks" , async ( ) => {
361+ await runCli ( [ "list" , "--archived" ] , { storage } ) ;
362+
363+ const out = output . stdout . join ( "\n" ) ;
364+ expect ( out ) . toContain ( "No archived tasks" ) ;
365+ } ) ;
366+
367+ it ( "filters archived tasks by query" , async ( ) => {
368+ const archiveStorage = new ArchiveStorage ( {
369+ path : storage . getIdentifier ( ) ,
370+ } ) ;
371+ archiveStorage . appendArchive ( [
372+ createArchivedTask ( { id : "auth1234" , name : "Fix authentication bug" } ) ,
373+ createArchivedTask ( { id : "feat5678" , name : "Add new feature" } ) ,
374+ ] ) ;
375+
376+ await runCli ( [ "list" , "--archived" , "-q" , "auth" ] , { storage } ) ;
377+
378+ const out = output . stdout . join ( "\n" ) ;
379+ expect ( out ) . toContain ( "Fix authentication bug" ) ;
380+ expect ( out ) . not . toContain ( "Add new feature" ) ;
381+ } ) ;
382+
383+ it ( "outputs archived tasks as JSON with --json flag" , async ( ) => {
384+ const archiveStorage = new ArchiveStorage ( {
385+ path : storage . getIdentifier ( ) ,
386+ } ) ;
387+ const archivedTask = createArchivedTask ( {
388+ id : "json1234" ,
389+ name : "JSON archived task" ,
390+ result : "Done" ,
391+ } ) ;
392+ archiveStorage . appendArchive ( [ archivedTask ] ) ;
393+
394+ await runCli ( [ "list" , "--archived" , "--json" ] , { storage } ) ;
395+
396+ const parsed = JSON . parse ( output . stdout . join ( "\n" ) ) ;
397+ expect ( Array . isArray ( parsed ) ) . toBe ( true ) ;
398+ expect ( parsed [ 0 ] . name ) . toBe ( "JSON archived task" ) ;
399+ expect ( parsed [ 0 ] . archived_at ) . toBeDefined ( ) ;
400+ } ) ;
401+
402+ it ( "does not mix active and archived tasks" , async ( ) => {
403+ // Create an active task
404+ await runCli ( [ "create" , "-n" , "Active task" , "--description" , "ctx" ] , {
405+ storage,
406+ } ) ;
407+ output . stdout . length = 0 ;
408+
409+ // Create an archived task
410+ const archiveStorage = new ArchiveStorage ( {
411+ path : storage . getIdentifier ( ) ,
412+ } ) ;
413+ archiveStorage . appendArchive ( [
414+ createArchivedTask ( { id : "arch0001" , name : "Archived task" } ) ,
415+ ] ) ;
416+
417+ // List active tasks (no --archived)
418+ await runCli ( [ "list" ] , { storage } ) ;
419+ let out = output . stdout . join ( "\n" ) ;
420+ expect ( out ) . toContain ( "Active task" ) ;
421+ expect ( out ) . not . toContain ( "Archived task" ) ;
422+
423+ // List archived tasks
424+ output . stdout . length = 0 ;
425+ await runCli ( [ "list" , "--archived" ] , { storage } ) ;
426+ out = output . stdout . join ( "\n" ) ;
427+ expect ( out ) . toContain ( "Archived task" ) ;
428+ expect ( out ) . not . toContain ( "Active task" ) ;
429+ } ) ;
430+
431+ it ( "shows archived children count for parent tasks" , async ( ) => {
432+ const archiveStorage = new ArchiveStorage ( {
433+ path : storage . getIdentifier ( ) ,
434+ } ) ;
435+ archiveStorage . appendArchive ( [
436+ createArchivedTask ( {
437+ id : "parent01" ,
438+ name : "Epic with children" ,
439+ archived_children : [
440+ {
441+ id : "child-1" ,
442+ name : "Subtask 1" ,
443+ description : "" ,
444+ result : "Done" ,
445+ } ,
446+ {
447+ id : "child-2" ,
448+ name : "Subtask 2" ,
449+ description : "" ,
450+ result : "Done" ,
451+ } ,
452+ ] ,
453+ } ) ,
454+ ] ) ;
455+
456+ await runCli ( [ "list" , "--archived" ] , { storage } ) ;
457+
458+ const out = output . stdout . join ( "\n" ) ;
459+ expect ( out ) . toContain ( "Epic with children" ) ;
460+ // Should indicate it has children
461+ expect ( out ) . toMatch ( / 2 \s * ( s u b t a s k | c h i l d r e n ) / i) ;
462+ } ) ;
463+
464+ it ( "includes all archived tasks with --all flag" , async ( ) => {
465+ const archiveStorage = new ArchiveStorage ( {
466+ path : storage . getIdentifier ( ) ,
467+ } ) ;
468+ archiveStorage . appendArchive ( [
469+ createArchivedTask ( { id : "task0001" , name : "First archived" } ) ,
470+ createArchivedTask ( { id : "task0002" , name : "Second archived" } ) ,
471+ ] ) ;
472+
473+ await runCli ( [ "list" , "--archived" , "--all" ] , { storage } ) ;
474+
475+ const out = output . stdout . join ( "\n" ) ;
476+ expect ( out ) . toContain ( "First archived" ) ;
477+ expect ( out ) . toContain ( "Second archived" ) ;
478+ } ) ;
479+ } ) ;
336480} ) ;
0 commit comments