#!/bin/bash # Seeds the empty run workspace with a small volunteer-rota app (Node, node --test). # Self-contained on purpose: the run cannot read the eval directory, and the # fixture is written inline, with no path outside the workspace and no git. set -eu mkdir -p src tests cat > package.json <<'J' { "name": "rota", "version": "0.3.0", "type": "module", "private": true, "scripts": { "test": "node --test" } } J cat > src/duration.mjs <<'J' // Parses a shift length such as "90m" or "45s" into minutes. export function parseDuration(text) { const m = /^(\d+)([a-z]*)$/.exec(String(text).trim()); if (!m) throw new Error(`bad duration: ${text}`); const n = Number(m[1]); if (m[2] === 'm') return n; if (m[2] === 's') return n / 60; return n; // a bare number is minutes } J cat > src/rota.mjs <<'J' import { parseDuration } from './duration.mjs'; // Total minutes a volunteer is booked for, from shift strings. export function bookedMinutes(shifts) { return shifts.reduce((sum, s) => sum + parseDuration(s), 0); } J cat > tests/duration.test.mjs <<'J' import { test } from 'node:test'; import assert from 'node:assert/strict'; import { parseDuration } from '../src/duration.mjs'; test('minutes', () => assert.equal(parseDuration('90m'), 90)); test('seconds', () => assert.equal(parseDuration('30s'), 0.5)); test('bare number is minutes', () => assert.equal(parseDuration('15'), 15)); J cat > tests/rota.test.mjs <<'J' import { test } from 'node:test'; import assert from 'node:assert/strict'; import { bookedMinutes } from '../src/rota.mjs'; test('sums shifts', () => assert.equal(bookedMinutes(['90m', '30m', '15']), 135)); J