Automate Microsoft Forms submission with Playwright, dual-calendar auto-fill, and M365 number-matching MFA support.
bash
cd <skill-directory>
npm install
npx playwright install chromium
bash
node scripts/setup-credentials.js
Creates config/credentials.json (gitignored) with M365 email/password.
bash
xvfb-run --auto-servernum node scripts/mfa-login.js
When prompted, enter the 6-digit code from your Authenticator app. Saves auth state to config/storageState.json for headless reuse.
bash
node scripts/calendar-fetch.js # Today (SGT)
node scripts/calendar-fetch.js --date 2026-03-18 # Specific date
Returns JSON with all form fields auto-populated from both calendars.
bash
node scripts/submit-daily.js
Reads today's entry from daily-entries/YYYY-MM-DD.json and submits.
CalendarURL SourcePurpose**Training (TMS)**Built into scriptTraining Hours (source of truth)OutlookBuilt into scriptContent Dev Hours, Other Items
#FieldSource1DateToday (M/d/yyyy)2Training HoursTraining calendar events3Content Dev HoursOutlook calendar (content dev blockouts)4Content Dev TopicEvent description from Outlook5Learning Hoursmax(0, 8 - training - contentDev)6Learning Topic2-3 random topics + any KT Sessions7Other Items"Preparation, testing, and rehearsal for my next class" + Outlook events (excludes KT Sessions, training duplicates)8Team HoursBlank9Team DescriptionBlank
FieldFallbackTraining Hours0Content Dev Hours0Content Dev TopicNALearning Hours8Learning Topic3 random topics from poolOther Items"Preparation, testing, and rehearsal for my next class"
ScriptPurposescripts/calendar-fetch.jsFetch both calendars, output all form fieldsscripts/submit-with-mfa.jsPrimary: Combined MFA login + form submit in one sessionscripts/submit-daily.jsSubmit form using saved storageState (no MFA)scripts/mfa-login.jsStandalone MFA login (headed mode, saves state)scripts/fill-form.jsCLI form filler with --date, --training, etc. argsscripts/setup-credentials.jsOne-time credential setup
text
5:45 PM SGT → Pre-Fill cron (isolated) → calendar-fetch.js → draft entry JSON
6:00 PM SGT → Submit cron (main session) → asks Master for MFA code →
submit-with-mfa.js --code CODE → login + submit in one session → done
Why main session? The submit job runs in the main session so it can ask Master Phil for the 6-digit Authenticator code. Speed is critical — the MFA code expires in ~30 seconds, so the login and submit happen in a single browser session via submit-with-mfa.js.
FilePurposeGitignored?config/credentials.jsonM365 email + password✅config/storageState.jsonSaved browser session (cookies)✅config/calendars.jsonCalendar URLs (contains auth tokens)✅config/calendars.json.exampleTemplate for calendar URLs❌config/form-values.jsonLegacy form value defaults❌daily-entries/Daily submission audit trail✅
This skill now intelligently handles both MFA and non-MFA scenarios:
Auto-detection: The script attempts credential login first, then checks if MFA is required
Flexible invocation:
node scripts/submit-with-mfa.js - Tries credentials only; if MFA appears, waits 30s for manual code entry or exits with code 2node scripts/submit-with-mfa.js --code XXXXXX - Provides MFA code upfront; uses it if MFA appears, otherwise proceedsGraceful fallback: If credentials alone are sufficient (no MFA prompt), it works without requiring a code
Exit codes:
0 — Success1 — General error / invalid credentials2 — MFA required but no code provided (use --code flag)3 — MFA code wrong or expired4 — Form submission failedFor daily cron (6 PM SGT):
text
node scripts/submit-with-mfa.js --code [MFA_CODE_HERE]
This ensures speed (code ready) and handles both cases:
For manual testing (unknown MFA requirement):
text
node scripts/submit-with-mfa.js
The script will wait 30 seconds on the MFA screen if needed, allowing you to manually type the code from your Authenticator app.
Microsoft's M365 authentication can be inconsistent:
The new logic eliminates the "always ask for MFA" problem by making the code optional and only using it when the MFA prompt actually appears.
xvfb-run --auto-servernum node scripts/mfa-login.js with a fresh Authenticator codescripts/submit-daily.jsnode scripts/calendar-fetch.js --date YYYY-MM-DD to verify calendar datareferences/TESTING_AUTH_WORKFLOW.md for comprehensive authentication workflow testing scenarios