Glob
# grade this stage (from your course directory)
npx theinference test --stage glob --watchview reads one path you already know. Glob answers the question before that: which paths exist? Give it a pattern like src/** or **/*.ts and it walks the sandbox tree and returns every relative path that matches, sorted. This is how the model finds the file it's looking for without you spoon-feeding it the layout — and "sorted" is what makes the result deterministic enough to grade.
* → any run of characters except "/" (one path segment)
** → any characters including "/" (crosses directories)
? → exactly one non-"/" character
src/** matches src/a.ts, src/lib/b.ts (everything under src/)
**/*.ts matches a.ts, src/lib/b.ts (every .ts, any depth)
What to build
Implement Tools.glob
Implement Tools.glob(pattern) in src/tools.ts:
- Compile
patternto a regex anchored with^…$over the relative path:*→[^/]*,**→.*(consuming a trailing/sosrc/**also matchessrc/a.ts),?→[^/], and escape regex metacharacters. - Recursively walk the sandbox root. For each file, compute its path relative to the root and keep it if the regex matches.
- Return the matching relative paths sorted, one per line.
The program.ts glob subcommand builds a sandbox from case.files and prints tools.glob(case.pattern).
glob(pattern: string): ToolOutput {
// 1. compile pattern -> anchored RegExp (* -> [^/]*, ** -> .*, ? -> [^/])
// 2. walk the sandbox root; for each FILE, test the RELATIVE path
// 3. return matches sorted, one per line
}
The sandbox lives in a temp dir like /tmp/cc-task-XYZ/src/a.ts, but the pattern src/** is written against the tree root. Always test relative(root, full) — i.e. src/a.ts — not the absolute path, or src/** will silently match nothing. This is also why the output is reproducible: relative paths don't leak the random temp prefix into the graded result.
Directories are how you reach the files, not results in their own right. Walk into every subdirectory, but only push a path when it's a file. With case.files of src/a.ts, src/b.js, README.md, the pattern src/** yields exactly src/a.ts and src/b.js — README.md is at the root, outside src/, so it's excluded.
Process mode. The harness runs npx tsx program.ts glob fixtures/case.json and compares the printed JSON to fixtures/expected.json. Sort order is part of the contract: {"content":"src/a.ts\nsrc/b.js"} must come out in that exact order. An unsorted walk that happens to match the same set still fails the byte diff — the lexical .sort() is what makes the result deterministic across filesystems.