fix: before_agent_start-Hook nur bei aktivem Coding-Workflow Persona injizieren
currentRole erhält dritten Zustand "idle" (Initialwert + Reset nach jedem Kommando). Der Hook injiziert nur noch eine Persona wenn currentRole "coder" oder "judge" ist — im freien Chat bleibt der System-Prompt unverändert, sodass andere Extensions (z. B. research-web.ts) nicht durch die Coding-Persona gestört werden. Alle Kommando-Handler (/coder, /judge, /fix, /shipit, /optimize, /patch, /quick_check, /plan, /continue) und runUpdateDoku setzen currentRole am Ende auf "idle" zurück. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
42d8e921fa
commit
bba630cbbb
2 changed files with 19 additions and 6 deletions
|
|
@ -762,6 +762,7 @@ async function runUpdateDoku(pi: ExtensionAPI, ctx: ExtensionCommandContext): Pr
|
||||||
|
|
||||||
ctx.ui.setStatus("update_doku", "✓ Dokumentation abgeschlossen");
|
ctx.ui.setStatus("update_doku", "✓ Dokumentation abgeschlossen");
|
||||||
ctx.ui.notify("Dokumentations-Phase abgeschlossen. Commit angelegt.", "info");
|
ctx.ui.notify("Dokumentations-Phase abgeschlossen. Commit angelegt.", "info");
|
||||||
|
currentRole = "idle";
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Versions-Verwaltung (SemVer + Git-Tags) ──────────────────────────────────
|
// ── Versions-Verwaltung (SemVer + Git-Tags) ──────────────────────────────────
|
||||||
|
|
@ -923,7 +924,8 @@ let cancelRequested = false;
|
||||||
let currentModelKey = ""; // Cache für ensureSingleModel() — verhindert redundante setModel()-Aufrufe
|
let currentModelKey = ""; // Cache für ensureSingleModel() — verhindert redundante setModel()-Aufrufe
|
||||||
// Aktive Rolle für die Single-Server-Architektur: steuert, welcher Persona-System-Prompt
|
// Aktive Rolle für die Single-Server-Architektur: steuert, welcher Persona-System-Prompt
|
||||||
// im before_agent_start-Hook injiziert wird. Wird ausschließlich über selectRole() gesetzt.
|
// im before_agent_start-Hook injiziert wird. Wird ausschließlich über selectRole() gesetzt.
|
||||||
let currentRole: "coder" | "judge" = "coder";
|
// "idle" = kein aktiver Coding-Workflow → Hook injiziert keine Persona (freier Chat).
|
||||||
|
let currentRole: "coder" | "judge" | "idle" = "idle";
|
||||||
let interactivePauseActive = false;
|
let interactivePauseActive = false;
|
||||||
let interactiveContinueRequested = false;
|
let interactiveContinueRequested = false;
|
||||||
let interactivePauseTask = "";
|
let interactivePauseTask = "";
|
||||||
|
|
@ -999,6 +1001,7 @@ export default function (pi: ExtensionAPI) {
|
||||||
// erhalten bleibt. So unterscheiden sich Coder- und Judge-Turns auf System-Prompt-Ebene,
|
// erhalten bleibt. So unterscheiden sich Coder- und Judge-Turns auf System-Prompt-Ebene,
|
||||||
// ohne Server- oder Modellwechsel.
|
// ohne Server- oder Modellwechsel.
|
||||||
pi.on("before_agent_start", function (event) {
|
pi.on("before_agent_start", function (event) {
|
||||||
|
if (currentRole === "idle") return {};
|
||||||
const persona = currentRole === "judge" ? judgePersona() : coderPersona();
|
const persona = currentRole === "judge" ? judgePersona() : coderPersona();
|
||||||
return { systemPrompt: event.systemPrompt + "\n\n" + persona };
|
return { systemPrompt: event.systemPrompt + "\n\n" + persona };
|
||||||
});
|
});
|
||||||
|
|
@ -1079,6 +1082,7 @@ export default function (pi: ExtensionAPI) {
|
||||||
await selectRole(pi, ctx, "coder");
|
await selectRole(pi, ctx, "coder");
|
||||||
currentActivity = "Coder implementiert…";
|
currentActivity = "Coder implementiert…";
|
||||||
await sendAndWait(pi, ctx, coderKickoff(task));
|
await sendAndWait(pi, ctx, coderKickoff(task));
|
||||||
|
currentRole = "idle";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -1092,6 +1096,7 @@ export default function (pi: ExtensionAPI) {
|
||||||
await selectRole(pi, ctx, "judge");
|
await selectRole(pi, ctx, "judge");
|
||||||
currentActivity = "Judge reviewt…";
|
currentActivity = "Judge reviewt…";
|
||||||
await sendAndWait(pi, ctx, judgePrompt(args || ""));
|
await sendAndWait(pi, ctx, judgePrompt(args || ""));
|
||||||
|
currentRole = "idle";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -1105,6 +1110,7 @@ export default function (pi: ExtensionAPI) {
|
||||||
await selectRole(pi, ctx, "coder");
|
await selectRole(pi, ctx, "coder");
|
||||||
currentActivity = "Coder fixt Judge-Kritik…";
|
currentActivity = "Coder fixt Judge-Kritik…";
|
||||||
await sendAndWait(pi, ctx, fixPrompt(args || ""));
|
await sendAndWait(pi, ctx, fixPrompt(args || ""));
|
||||||
|
currentRole = "idle";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -1127,6 +1133,7 @@ export default function (pi: ExtensionAPI) {
|
||||||
} else if (shipVerdict === "NO-SHIP") {
|
} else if (shipVerdict === "NO-SHIP") {
|
||||||
ctx.ui.notify("NO-SHIP — noch Blocker offen. Bitte /fix aufrufen.", "error");
|
ctx.ui.notify("NO-SHIP — noch Blocker offen. Bitte /fix aufrufen.", "error");
|
||||||
}
|
}
|
||||||
|
currentRole = "idle";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -1388,9 +1395,8 @@ export default function (pi: ExtensionAPI) {
|
||||||
// Sicherstellen dass keine Zustandsvariable in späteren /optimize-Aufruf leckt
|
// Sicherstellen dass keine Zustandsvariable in späteren /optimize-Aufruf leckt
|
||||||
cancelRequested = false;
|
cancelRequested = false;
|
||||||
currentModelKey = "";
|
currentModelKey = "";
|
||||||
// Rolle auf den Standard (coder) zurücksetzen, damit freier Chat nach einem
|
// Zurück auf idle: freier Chat nach dem Lauf soll keine Coding-Persona erhalten.
|
||||||
// Lauf nicht versehentlich die Judge-Persona behält (before_agent_start-Hook).
|
currentRole = "idle";
|
||||||
currentRole = "coder";
|
|
||||||
interactivePauseActive = false;
|
interactivePauseActive = false;
|
||||||
interactiveContinueRequested = false;
|
interactiveContinueRequested = false;
|
||||||
interactivePauseTask = "";
|
interactivePauseTask = "";
|
||||||
|
|
@ -1415,6 +1421,7 @@ export default function (pi: ExtensionAPI) {
|
||||||
await selectRole(pi, ctx, "coder");
|
await selectRole(pi, ctx, "coder");
|
||||||
currentActivity = "Coder patcht…";
|
currentActivity = "Coder patcht…";
|
||||||
await sendAndWait(pi, ctx, patchPrompt(change));
|
await sendAndWait(pi, ctx, patchPrompt(change));
|
||||||
|
currentRole = "idle";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -1428,6 +1435,7 @@ export default function (pi: ExtensionAPI) {
|
||||||
await selectRole(pi, ctx, "judge");
|
await selectRole(pi, ctx, "judge");
|
||||||
currentActivity = "Judge: Schnellcheck…";
|
currentActivity = "Judge: Schnellcheck…";
|
||||||
await sendAndWait(pi, ctx, quickCheckPrompt(args || ""));
|
await sendAndWait(pi, ctx, quickCheckPrompt(args || ""));
|
||||||
|
currentRole = "idle";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -1500,6 +1508,7 @@ export default function (pi: ExtensionAPI) {
|
||||||
await sendAndWait(pi, ctx, planPrompt(task));
|
await sendAndWait(pi, ctx, planPrompt(task));
|
||||||
ctx.ui.setStatus("plan", "");
|
ctx.ui.setStatus("plan", "");
|
||||||
finalNotify(ctx, "📋 Plan", "Analyse abgeschlossen — PLAN.md + Chat");
|
finalNotify(ctx, "📋 Plan", "Analyse abgeschlossen — PLAN.md + Chat");
|
||||||
|
currentRole = "idle";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -1587,6 +1596,7 @@ export default function (pi: ExtensionAPI) {
|
||||||
"5. Fahre direkt mit dem nächsten sinnvollen Schritt fort — kein langer Bericht, einfach weitermachen.",
|
"5. Fahre direkt mit dem nächsten sinnvollen Schritt fort — kein langer Bericht, einfach weitermachen.",
|
||||||
].join("\n"));
|
].join("\n"));
|
||||||
ctx.ui.setStatus("continue", "");
|
ctx.ui.setStatus("continue", "");
|
||||||
|
currentRole = "idle";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,8 +41,11 @@ test("Loop-Erkennung greift auch ohne Blocker-Abschnitt (Fallback auf Gesamttext
|
||||||
assert.match(extSource, /parseBlockers\(judgeText\)\s*\|\|\s*judgeText/);
|
assert.match(extSource, /parseBlockers\(judgeText\)\s*\|\|\s*judgeText/);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("currentRole wird nach jedem optimize-Lauf auf 'coder' zurückgesetzt", () => {
|
test("currentRole wird nach jedem Kommando auf 'idle' zurückgesetzt (kein Persona-Leak in freien Chat)", () => {
|
||||||
assert.match(extSource, /currentRole\s*=\s*"coder"/);
|
// 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", () => {
|
test("LICENCE.md: deterministisch in der Doku-Phase, nur wenn nicht vorhanden, proprietär", () => {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue