I’ve found a solution to my problem (perhaps not to my question about differences in behaviour of tools, but this is less important), from adapting the dir7.cwl tool in this post.
My new function is:
class: ExpressionTool cwlVersion: v1.1 doc: | This javascript takes two inputs, a list of files, and a project file. It will create a directory named after the project file, populate that directory with the files in the list, and return the directory. requirements: InlineJavascriptRequirement: {} inputs: external_files: File[] external_project_file: File outputs: project_work_dir: Directory expression: | ${ return {"project_work_dir": {"class": "Directory", "basename": inputs.external_project_file.basename, "listing": inputs.external_files} }; }
This now works as I want for the cwl-runner tool - a directory is created (named after the project file), and passed back with the files I require.
This also works in TOIL-CWL (I guess expression tools are more portable than command line tools), although I do need to use the --noMoveExports
flag in order to have the outputs copied, rather than linked.