// Statische Regression-Guards: sichern die konkreten Fixes/Umbauten gegen versehentliches // Zurückdrehen ab. Prüft den Extension-Quelltext, ohne ihn auszuführen. import { test } from "node:test"; import assert from "node:assert/strict"; import { extSource } from "./helpers.mjs"; test("Crash-Fix: ctx.ui.select wird positional aufgerufen, nicht mit einem Objekt", () => { // Der Crash 'reading length' entstand durch ctx.ui.select({...}) statt select(title, options[]). assert.doesNotMatch(extSource, /ui\.select\(\s*\{/, "ui.select darf NICHT mit Objekt aufgerufen werden"); assert.match(extSource, /ui\.select\(\s*titleLine\s*,\s*\[/, "ui.select muss (title, options[]) erhalten"); }); test("Single-GPU: keine switchModel-Aufrufe mehr (durch selectRole ersetzt)", () => { assert.doesNotMatch(extSource, /switchModel\s*\(\s*pi/); assert.match(extSource, /function selectRole\b/); assert.match(extSource, /function ensureSingleModel\b/); }); test("System-Prompt-Rollen: before_agent_start-Hook injiziert Coder-/Judge-Persona", () => { assert.match(extSource, /pi\.on\(\s*["']before_agent_start["']/); assert.match(extSource, /function coderPersona\b/); assert.match(extSource, /function judgePersona\b/); // Persona wird angehängt, nicht ersetzt (Pi-Basis-System-Prompt bleibt erhalten). assert.match(extSource, /event\.systemPrompt\s*\+/); }); test("Quick-Judge abgeschafft: keine quickJudge-Prompt-Funktionen mehr", () => { assert.doesNotMatch(extSource, /function quickJudgePrompt\b/); assert.doesNotMatch(extSource, /function quickJudgeWithTestsPrompt\b/); }); test("Fix-Auslösung: PASS WITH CONCERNS gilt nur mit --approve-concerns als bestanden", () => { assert.match(extSource, /passed\s*=\s*verdict === "PASS"/); assert.match(extSource, /verdict === "PASS WITH CONCERNS"\s*&&\s*approveConcerns/); // und der Bestanden-Zweig nutzt 'passed', nicht mehr das alte 'verdict === PASS WITH CONCERNS'. assert.match(extSource, /if\s*\(\s*passed\s*\)/); }); test("Loop-Erkennung greift auch ohne Blocker-Abschnitt (Fallback auf Gesamttext)", () => { assert.match(extSource, /parseBlockers\(judgeText\)\s*\|\|\s*judgeText/); }); test("currentRole wird nach jedem Kommando auf 'idle' zurückgesetzt (kein Persona-Leak in freien Chat)", () => { // Initialwert und alle Reset-Stellen müssen "idle" sein, nicht "coder". assert.match(extSource, /currentRole:\s*"coder"\s*\|\s*"judge"\s*\|\s*"idle"/); assert.match(extSource, /=\s*"idle"/); assert.doesNotMatch(extSource, /currentRole\s*=\s*"coder"/); }); test("LICENCE.md: deterministisch in der Doku-Phase, nur wenn nicht vorhanden, proprietär", () => { assert.match(extSource, /function licenceMd\b/); assert.match(extSource, /async function writeLicenceMd\b/); // wird in runUpdateDoku aufgerufen assert.match(extSource, /await writeLicenceMd\(pi, ctx\)/); // existierende Lizenz wird nicht überschrieben assert.match(extSource, /test -f LICENCE\.md/); // proprietärer Default assert.match(extSource, /Alle Rechte vorbehalten/); // Inhaber aus git config, Jahr aus aktuellem Datum assert.match(extSource, /git config user\.name/); assert.match(extSource, /new Date\(\)\.getFullYear\(\)/); });