(raw, defaults = {})
| 148 | return runs > 0 ? { compactEveryRuns: runs } : {} |
| 149 | } |
| 150 | |
| 151 | function parseLoopArgs(raw, defaults = {}) { |
| 152 | let input = stripOuterQuotes(String(raw || "").trim()) |
| 153 | let first = "" |
| 154 | let rest = input |
| 155 | let intervalMs = defaults.intervalMs ?? null |
| 156 | |
| 157 | if (!input && defaults.action) { |
| 158 | rest = defaults.action |
| 159 | } else { |
| 160 | ;[first, rest] = splitFirst(input) |
| 161 | if (first === "--watch") { |
| 162 | intervalMs = defaults.intervalMs ?? 0 |
| 163 | rest = input |
| 164 | } else if (first) { |
| 165 | const parsedDuration = parseDuration(first) |
| 166 | if (parsedDuration !== null) intervalMs = parsedDuration |
| 167 | else if (intervalMs === null) return { ok: false, error: "Usage: /loop 0s <prompt> | /loop 5m <prompt> | /loop-goal <objective> | /loop-command 200m /compact | /loop-shell 10m npm test | /loop --watch progress.md <prompt>" } |
| 168 | else rest = input |
| 169 | } |
| 170 | } |
| 171 | |
| 172 | if (intervalMs === null) intervalMs = 0 |
| 173 | |
| 174 | const job = { |
| 175 | id: `${now().toString(36)}-${Math.random().toString(16).slice(2, 8)}`, |
| 176 | name: defaults.name, |
| 177 | action: defaults.action || "", |
| 178 | kind: defaults.kind || undefined, |
| 179 | intervalMs, |
| 180 | immediate: defaults.immediate ?? true, |
| 181 | maxRuns: defaults.maxRuns ?? 0, |
| 182 | maxRuntimeMs: defaults.maxRuntimeMs ?? 0, |
| 183 | maxFailures: defaults.maxFailures ?? 0, |
| 184 | timeoutMs: defaults.timeoutMs ?? 0, |
| 185 | until: defaults.until, |
| 186 | stopFile: defaults.stopFile, |
| 187 | progressFile: defaults.progressFile, |
| 188 | promptFile: defaults.promptFile, |
| 189 | includeFiles: Array.isArray(defaults.includeFiles) ? [...defaults.includeFiles] : [], |
| 190 | watchPaths: Array.isArray(defaults.watchPaths) ? [...defaults.watchPaths] : [], |
| 191 | compactEveryRuns: defaults.compactEveryRuns ?? 0, |
| 192 | compactEveryMs: defaults.compactEveryMs ?? 0, |
| 193 | testCommand: defaults.testCommand, |
| 194 | verifyCommand: defaults.verifyCommand, |
| 195 | preflightCommand: defaults.preflightCommand, |
| 196 | postrunCommand: defaults.postrunCommand, |
| 197 | notifyCommand: defaults.notifyCommand, |
| 198 | branch: defaults.branch, |
| 199 | branchDone: false, |
| 200 | goalStatus: defaults.goalStatus, |
| 201 | goalFile: defaults.goalFile, |
| 202 | goalAcceptance: Array.isArray(defaults.goalAcceptance) ? [...defaults.goalAcceptance] : [], |
| 203 | goalChecks: Array.isArray(defaults.goalChecks) ? [...defaults.goalChecks] : [], |
| 204 | goalCompleteWhenChecksPass: defaults.goalCompleteWhenChecksPass ?? false, |
| 205 | goalEvidenceFile: defaults.goalEvidenceFile, |
| 206 | goalSummary: defaults.goalSummary || "", |
| 207 | goalEvidence: defaults.goalEvidence || "", |
no test coverage detected