Skip to content
Open
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
27 changes: 27 additions & 0 deletions src/controller.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,33 @@ describe("Discord controller flows", () => {
);
});

it("resolves channel identity from ctx.to when ctx.from is a slash identity in a new Discord thread", async () => {
// Regression test for brand-new Discord threads where the slash interaction
// places the slash user identity in ctx.from and the channel target in ctx.to.
const { controller, sendComponentMessage } = await createControllerHarness();

const reply = await controller.handleCommand(
"cas_resume",
buildDiscordCommandContext({
from: "slash:user-1",
to: "discord:channel:chan-1",
}),
);

expect(reply).toEqual({
text: "Sent a Codex thread picker to this Discord conversation.",
});
expect(sendComponentMessage).toHaveBeenCalledWith(
"channel:chan-1",
expect.objectContaining({
text: expect.stringContaining("Showing recent Codex sessions"),
}),
expect.objectContaining({
accountId: "default",
}),
);
});

it("sends Discord model pickers directly instead of returning Telegram buttons", async () => {
const { controller, sendComponentMessage } = await createControllerHarness();
await (controller as any).store.upsertBinding({
Expand Down
7 changes: 6 additions & 1 deletion src/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,12 @@ function toConversationTargetFromCommand(ctx: PluginCommandContext): Conversatio
};
}
if (isDiscordChannel(ctx.channel)) {
const conversationId = normalizeDiscordConversationId(ctx.from ?? ctx.to);
// In brand-new Discord threads, the slash interaction may place the slash
// user identity in ctx.from (e.g. "slash:user-id") while ctx.to holds the
// real channel target. Prefer ctx.to when ctx.from is a slash identity so
// /cas_resume resolves to the correct channel from the first attempt.
const sourceId = ctx.from?.startsWith("slash:") ? ctx.to : (ctx.from ?? ctx.to);
const conversationId = normalizeDiscordConversationId(sourceId);
if (!conversationId) {
return null;
}
Expand Down