(directory, client, sessionID)
| 864 | return (await fs.readFile(filePath, "utf8")).includes(needle) |
| 865 | } catch { return false } |
| 866 | } |
| 867 | |
| 868 | async function untilReached(directory, job) { |
| 869 | if (!job.until) return false |
| 870 | const files = ["progress.md", "PROGRESS.md", "todo.md", "TODO.md", "todolist.md", "TODOLIST.md", path.join(".opencode", "opencode-loop", "until.txt")] |
| 871 | for (const file of files) if (await fileContains(path.resolve(directory, file), job.until)) return true |
| 872 | let scanned = 0 |
| 873 | async function walk(current) { |
| 874 | if (scanned >= MAX_SCAN_FILES) return false |
| 875 | let entries |
| 876 | try { entries = await fs.readdir(current, { withFileTypes: true }) } catch { return false } |
| 877 | for (const entry of entries) { |
| 878 | if (scanned >= MAX_SCAN_FILES) return false |
| 879 | if ([".git", "node_modules", "dist", "build", ".next", "coverage"].includes(entry.name)) continue |
| 880 | const full = path.join(current, entry.name) |
| 881 | if (entry.isDirectory()) { if (await walk(full)) return true } |
| 882 | else if (entry.isFile() && /\.(md|txt|json|yaml|yml)$/i.test(entry.name)) { scanned++; if (await fileContains(full, job.until)) return true } |
| 883 | } |
| 884 | return false |
| 885 | } |
| 886 | return await walk(directory) |
| 887 | } |
| 888 | |
| 889 | async function createCheckpoint(directory, sessionID, job, client) { |
| 890 | if (!job.checkpointOnly && !job.gitCheckpoint) return |
| 891 | const inRepo = await runProcess("git", ["rev-parse", "--is-inside-work-tree"], directory, 10_000) |
| 892 | if (inRepo.code !== 0) return |
| 893 | const status = await runProcess("git", ["status", "--short"], directory, 30_000) |
no test coverage detected