Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions src/resources/extensions/ask-user-questions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,10 +135,14 @@ export default function AskUserQuestions(pi: ExtensionAPI) {
}
}

// Try remote first if configured (works in both interactive and headless modes).
// tryRemoteQuestions returns null when no remote channel is configured, so
// this is a no-op when the user has not set up Slack/Discord/Telegram.
const { tryRemoteQuestions } = await import("./remote-questions/manager.js");
const remoteResult = await tryRemoteQuestions(params.questions, signal);
if (remoteResult) return { ...remoteResult, details: remoteResult.details as unknown };

if (!ctx.hasUI) {
const { tryRemoteQuestions } = await import("./remote-questions/manager.js");
const remoteResult = await tryRemoteQuestions(params.questions, signal);
if (remoteResult) return { ...remoteResult, details: remoteResult.details as unknown };
return errorResult("Error: UI not available (non-interactive mode)", params.questions);
}

Expand Down
21 changes: 21 additions & 0 deletions src/resources/extensions/gsd/tests/remote-questions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -739,6 +739,27 @@ test("config source-level: hydration skips api_key entries with empty keys", ()
);
});

test("ask-user-questions source-level: tryRemoteQuestions is called before the hasUI guard", () => {
// Regression test for #3480 — remote questions were silently skipped in interactive
// mode because tryRemoteQuestions was gated behind `if (!ctx.hasUI)`.
// The fix moved the remote call before that guard so configured channels
// (Telegram/Slack/Discord) fire regardless of UI availability.
const src = readFileSync(
join(__dirname, "..", "..", "ask-user-questions.ts"),
"utf-8",
);

const remoteCallIdx = src.indexOf("tryRemoteQuestions(params.questions");
const hasUIGuardIdx = src.indexOf("if (!ctx.hasUI)");

assert.ok(remoteCallIdx !== -1, "tryRemoteQuestions call should exist in ask-user-questions.ts");
assert.ok(hasUIGuardIdx !== -1, "!ctx.hasUI guard should exist in ask-user-questions.ts");
assert.ok(
remoteCallIdx < hasUIGuardIdx,
"tryRemoteQuestions must be called before the !ctx.hasUI guard — otherwise remote questions are skipped in interactive mode",
);
});

test("config source-level: removeProviderToken uses auth.remove not auth.set with empty key", () => {
const commandSrc = readFileSync(
join(__dirname, "..", "..", "remote-questions", "remote-command.ts"),
Expand Down
Loading