Add a German prompt that prepares a school day

Tagesvorbereitung is where the two systems meet. It attaches the day's
timetable and then asks for the rest: match each lesson to its Schulcloud
course, read what is new there, look at what the previous lesson covered,
check both lists of due work, and read the notes on the periods, where the
announced tests are. Written for the morning before school, so it asks for
something short.

The argument takes heute, morgen, übermorgen or a date in either notation,
because evening preparation is the normal case and a German keyboard writes
21.09.2026. Registered only with WebUntis configured: a Tagesvorbereitung
that has to ask which lessons exist is not one.

readTimetable is shared with untis_timetable, the way readCourse is shared
with get_course, so an attached day reads exactly like a fetched one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-09-17 20:43:24 +02:00
parent 74b97bc4dc
commit eaf9c7aa38
3 changed files with 151 additions and 2 deletions

View File

@@ -2,7 +2,7 @@ import assert from 'node:assert/strict';
import { describe, it } from 'node:test';
import { ErrorCode } from '@modelcontextprotocol/sdk/types.js';
import { germanDate } from '../src/core/dates.ts';
import { argumentText, examPrompt, resolveTarget, summaryPrompt, type Target } from '../src/mcp/prompts.ts';
import { argumentText, dayPrompt, examPrompt, resolveDay, resolveTarget, summaryPrompt, type Target } from '../src/mcp/prompts.ts';
import { ProtocolError } from '../src/mcp/tools/result.ts';
const CANDIDATES: Target[] = [
@@ -153,3 +153,38 @@ describe('germanDate', () => {
});
});
describe('resolveDay', () => {
const today = '2026-09-17';
it('takes the words a person types in the evening', () => {
assert.equal(resolveDay(undefined, today), today);
assert.equal(resolveDay('heute', today), today);
assert.equal(resolveDay('morgen', today), '2026-09-18');
assert.equal(resolveDay('Übermorgen', today), '2026-09-19');
assert.equal(resolveDay('uebermorgen', today), '2026-09-19');
});
it('takes a date in either notation, because a German keyboard writes one of them', () => {
assert.equal(resolveDay('2026-09-21', today), '2026-09-21');
assert.equal(resolveDay('21.09.2026', today), '2026-09-21');
assert.equal(resolveDay('1.9.2026', today), '2026-09-01');
});
it('refuses anything else, in German', () => {
assert.throws(() => resolveDay('irgendwann', today), /ist kein Tag/);
assert.throws(() => resolveDay('2026-02-30', today), /ist kein Tag/);
});
});
describe('dayPrompt', () => {
it('names the day and keeps the two lists of due work apart', () => {
const prompt = dayPrompt('2026-09-21');
assert.match(prompt, /Montag, 21\.09\.2026/);
assert.match(prompt, /list_tasks/);
assert.match(prompt, /untis_homework/);
assert.match(prompt, /zwei getrennte Listen/);
// The prompt has to survive a day without lessons, which is common here.
assert.match(prompt, /kein Unterricht/);
assert.match(prompt, /Antworte auf Deutsch/);
});
});