@@ -2,9 +2,8 @@ import fs from "node:fs/promises";
22import os from "node:os" ;
33import path from "node:path" ;
44import { describe , expect , it } from "vitest" ;
5- import { DEFAULT_WORKSPACE } from "./default-workspace.js" ;
65import { validateWorkspaceDoc , type WorkspaceDoc } from "./schema.js" ;
7- import { sweepExpiredEphemeral , WorkspaceStore } from "./store.js" ;
6+ import { WorkspaceStore } from "./store.js" ;
87
98async function withStore < T > ( run : ( store : WorkspaceStore ) => Promise < T > | T ) : Promise < T > {
109 const stateDir = await fs . mkdtemp ( path . join ( os . tmpdir ( ) , "openclaw-workspace-" ) ) ;
@@ -42,73 +41,56 @@ function docWithPendingWidget(store: WorkspaceStore): WorkspaceDoc {
4241}
4342
4443describe ( "WorkspaceStore" , ( ) => {
45- it ( "sweeps expired temporary widgets but preserves future and pinned widgets" , ( ) => {
46- const doc = validateWorkspaceDoc ( {
47- ...structuredClone ( DEFAULT_WORKSPACE ) ,
48- tabs : [
49- {
50- ...structuredClone ( DEFAULT_WORKSPACE . tabs [ 0 ] ! ) ,
51- widgets : [
52- {
53- id : "expired" ,
54- kind : "builtin:markdown" ,
55- grid : { x : 0 , y : 0 , w : 4 , h : 2 } ,
56- collapsed : false ,
57- hidden : false ,
58- createdBy : "agent:main" ,
59- ephemeral : { expiresAt : "2026-07-01T00:00:00Z" } ,
60- } ,
61- {
62- id : "future" ,
63- kind : "builtin:markdown" ,
64- grid : { x : 4 , y : 0 , w : 4 , h : 2 } ,
65- collapsed : false ,
66- hidden : false ,
67- createdBy : "agent:main" ,
68- ephemeral : { expiresAt : "2026-08-01T00:00:00Z" } ,
69- } ,
70- {
71- id : "pinned" ,
72- kind : "builtin:markdown" ,
73- grid : { x : 8 , y : 0 , w : 4 , h : 2 } ,
74- collapsed : false ,
75- hidden : false ,
76- createdBy : "agent:main" ,
77- } ,
78- ] ,
79- } ,
80- ] ,
81- } ) ;
82- const swept = sweepExpiredEphemeral ( doc , Date . parse ( "2026-07-13T00:00:00Z" ) ) ;
83- expect ( swept ?. tabs [ 0 ] ?. widgets . map ( ( widget ) => widget . id ) ) . toEqual ( [ "future" , "pinned" ] ) ;
84- } ) ;
85-
8644 it ( "sweeps a widget after it expires even when the document was cached" , async ( ) => {
8745 let now = Date . parse ( "2026-07-13T00:00:00Z" ) ;
8846 await withTimedStore (
8947 ( ) => now ,
9048 ( store ) => {
9149 store . mutate (
9250 ( draft ) => {
93- draft . tabs [ 0 ] ! . widgets . push ( {
94- id : "temporary" ,
95- kind : "builtin:markdown" ,
96- grid : { x : 0 , y : 2 , w : 4 , h : 2 } ,
97- collapsed : false ,
98- hidden : false ,
99- createdBy : "agent:main" ,
100- ephemeral : { expiresAt : "2026-07-14T00:00:00Z" } ,
101- } ) ;
51+ draft . tabs [ 0 ] ! . widgets . push (
52+ {
53+ id : "temporary" ,
54+ kind : "builtin:markdown" ,
55+ grid : { x : 0 , y : 2 , w : 4 , h : 2 } ,
56+ collapsed : false ,
57+ hidden : false ,
58+ createdBy : "agent:main" ,
59+ ephemeral : { expiresAt : "2026-07-14T00:00:00Z" } ,
60+ } ,
61+ {
62+ id : "future" ,
63+ kind : "builtin:markdown" ,
64+ grid : { x : 4 , y : 2 , w : 4 , h : 2 } ,
65+ collapsed : false ,
66+ hidden : false ,
67+ createdBy : "agent:main" ,
68+ ephemeral : { expiresAt : "2026-08-01T00:00:00Z" } ,
69+ } ,
70+ {
71+ id : "pinned" ,
72+ kind : "builtin:markdown" ,
73+ grid : { x : 8 , y : 2 , w : 4 , h : 2 } ,
74+ collapsed : false ,
75+ hidden : false ,
76+ createdBy : "agent:main" ,
77+ } ,
78+ ) ;
10279 } ,
10380 { actor : "agent:main" } ,
10481 ) ;
10582 expect ( store . read ( ) . tabs [ 0 ] ?. widgets . some ( ( widget ) => widget . id === "temporary" ) ) . toBe (
10683 true ,
10784 ) ;
10885 now = Date . parse ( "2026-07-15T00:00:00Z" ) ;
109- expect ( store . read ( ) . tabs [ 0 ] ?. widgets . some ( ( widget ) => widget . id === "temporary" ) ) . toBe (
110- false ,
111- ) ;
86+ expect (
87+ store
88+ . read ( )
89+ . tabs [ 0 ] ?. widgets . filter ( ( widget ) =>
90+ [ "temporary" , "future" , "pinned" ] . includes ( widget . id ) ,
91+ )
92+ . map ( ( widget ) => widget . id ) ,
93+ ) . toEqual ( [ "future" , "pinned" ] ) ;
11294 } ,
11395 ) ;
11496 } ) ;
0 commit comments