diff --git a/src/resources/extensions/sf/auto-supervisor.ts b/src/resources/extensions/sf/auto-supervisor.ts index 1880285d3..e393c15ed 100644 --- a/src/resources/extensions/sf/auto-supervisor.ts +++ b/src/resources/extensions/sf/auto-supervisor.ts @@ -7,6 +7,7 @@ import { clearLock } from "./crash-recovery.js"; import { nativeHasChanges } from "./native-git-bridge.js"; import { releaseSessionLock } from "./session-lock.js"; +import { logWarning } from "./workflow-logger.js"; // ─── Signal Handling ───────────────────────────────────────────────────────── @@ -50,8 +51,13 @@ export function registerSigtermHandler( const handler = () => { try { onSignal?.(); - } catch { - // Best-effort: signal handler must not throw. + } catch (err) { + // Best-effort: signal handler must not throw — log and continue + // to lock cleanup so the user can still exit cleanly. + logWarning( + "session", + `auto-supervisor signal handler threw: ${(err as Error).message}`, + ); } clearLock(currentBasePath); releaseSessionLock(currentBasePath); diff --git a/src/resources/extensions/sf/tests/auto-session-encapsulation.test.ts b/src/resources/extensions/sf/tests/auto-session-encapsulation.test.ts index 510c5b41f..b69ee91b7 100644 --- a/src/resources/extensions/sf/tests/auto-session-encapsulation.test.ts +++ b/src/resources/extensions/sf/tests/auto-session-encapsulation.test.ts @@ -79,14 +79,19 @@ test("auto.ts has exactly one module-level const for AutoSession", () => { const source = getAutoTsSource(); const lines = source.split("\n"); + // Accept either historical shape: a direct `new AutoSession()` instantiation + // OR the current factory pattern `getAutoSession()` (auto/session.ts owns + // the singleton). The invariant is "exactly one module-level binding for + // the AutoSession instance" — not which constructor expression yielded it. const sessionConsts = lines.filter((line) => - /^const\s+\w+\s*=\s*new\s+AutoSession/.test(line), + /^const\s+\w+\s*=\s*(new\s+AutoSession|getAutoSession\s*\()/.test(line), ); assert.equal( sessionConsts.length, 1, - `auto.ts should have exactly one \`const s = new AutoSession()\`. ` + + `auto.ts should have exactly one module-level AutoSession binding ` + + `(\`const s = new AutoSession()\` or \`const s = getAutoSession()\`). ` + `Found ${sessionConsts.length}: ${sessionConsts.join(", ")}`, ); }); @@ -212,7 +217,8 @@ test("auto.ts module-level consts are only AutoSession instance, true constants, // Patterns that are acceptable at module level const allowedPatterns = [ - /^const s = new AutoSession/, // The session singleton + /^const s = new AutoSession/, // The session singleton (legacy shape) + /^const s = getAutoSession\s*\(/, // The session singleton (factory shape) /^const [A-Z_]+\s*=/, // UPPER_CASE constants /^const \w+StateAccessors/, // Static accessor objects /^const \w+:\s*\w+\s*=/, // Typed constants