```ts
export function runPatrol(width: number, start: number, moves: number[]): Record<string, number> {
    if (!Number.isInteger(width) || width <= 0) throw new Error('Invalid width');
    if (!Number.isInteger(start) || start < 0 || start >= width) throw new Error('Invalid start position');
    if (!Array.isArray(moves)) throw new Error('Invalid moves');

    const visited = new Set<number>();
    let position = start;
    let bumps = 0;

    visited.add(position);

    for (const move of moves) {
        if (!Number.isInteger(move) || move === 0) throw new Error('Invalid move');
        [position, bumps] = clampMove(position, move, width);
        visited.add(position);
    }

    return { position, bumps, visited: visited.size };
}

export function clampMove(position: number, delta: number, width: number): [number, boolean] {
    let newPosition = position + delta;
    let bumped = false;

    if (newPosition < 0) {
        newPosition = 0;
        bumped = true;
    } else if (newPosition >= width) {
        newPosition = width - 1;
        bumped = true;
    }

    return [newPosition, bumped];
}
```