Skip to content

Commit 94b0ff0

Browse files
author
Sorra
committed
SB-0MNM9ZYAZ000R2IZ: Ensure immediate confirmation includes OpenBrain item ID
1 parent 46e73a3 commit 94b0ff0

File tree

2 files changed

+240
-74
lines changed

2 files changed

+240
-74
lines changed

.opencode/package-lock.json

Lines changed: 115 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/index.ts

Lines changed: 125 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,11 @@ async function processUrlWithProgress(
540540
let terminalPhaseSeen = false;
541541
let eventCount = 0;
542542
let finalResult: AddResult | undefined;
543+
// Keep a reference to the last posted Discord message so we can
544+
// append the created item link/ID to it when the CLI returns the ID.
545+
// In real runtime this will be a discord.js Message; in tests the
546+
// mocked send/reply helpers may return undefined which we handle.
547+
let lastPostedMessage: any = null;
543548

544549
// Process progress events using manual iteration to capture return value
545550
logger.info("Waiting for CLI progress events...", { messageId: message.id, url });
@@ -582,10 +587,10 @@ async function processUrlWithProgress(
582587
}
583588

584589
// Only send update if phase changed (avoid spam)
585-
if (event.phase !== lastPhase) {
586-
lastPhase = event.phase;
590+
if (event.phase !== lastPhase) {
591+
lastPhase = event.phase;
587592

588-
const progressMsg = formatProgressMessage(event);
593+
const progressMsg = formatProgressMessage(event);
589594

590595
// Always ensure URLs shown to users are wrapped in backticks to avoid embeds.
591596
// If event contains a url or title, prefer showing the title wrapped in ticks.
@@ -599,37 +604,42 @@ async function processUrlWithProgress(
599604
}
600605
})();
601606

602-
if (thread) {
603-
try {
604-
await thread.send(safeProgressMsg);
605-
} catch (error) {
606-
logger.warn("Failed to send progress update to thread; falling back to channel reply", {
607-
threadId: thread.id,
608-
phase: event.phase,
609-
error: error instanceof Error ? error.message : String(error),
610-
});
611-
// Fallback: reply in channel so user still receives updates
607+
if (thread) {
612608
try {
613-
await message.reply(safeProgressMsg);
609+
// Capture the returned message when possible so we can edit it
610+
// later to append the created item link/ID.
611+
const posted = await thread.send(safeProgressMsg);
612+
lastPostedMessage = posted ?? lastPostedMessage;
613+
} catch (error) {
614+
logger.warn("Failed to send progress update to thread; falling back to channel reply", {
615+
threadId: thread.id,
616+
phase: event.phase,
617+
error: error instanceof Error ? error.message : String(error),
618+
});
619+
// Fallback: reply in channel so user still receives updates
620+
try {
621+
const posted = await message.reply(safeProgressMsg);
622+
lastPostedMessage = posted ?? lastPostedMessage;
623+
} catch (err) {
624+
logger.warn("Failed to send fallback progress reply to channel", {
625+
messageId: message.id,
626+
error: err instanceof Error ? err.message : String(err),
627+
});
628+
}
629+
}
630+
} else {
631+
// No thread available -> send progress updates to channel (safe)
632+
try {
633+
const posted = await message.reply(safeProgressMsg);
634+
lastPostedMessage = posted ?? lastPostedMessage;
614635
} catch (err) {
615-
logger.warn("Failed to send fallback progress reply to channel", {
636+
logger.warn("Failed to send progress update to channel", {
616637
messageId: message.id,
638+
phase: event.phase,
617639
error: err instanceof Error ? err.message : String(err),
618640
});
619641
}
620642
}
621-
} else {
622-
// No thread available -> send progress updates to channel (safe)
623-
try {
624-
await message.reply(safeProgressMsg);
625-
} catch (err) {
626-
logger.warn("Failed to send progress update to channel", {
627-
messageId: message.id,
628-
phase: event.phase,
629-
error: err instanceof Error ? err.message : String(err),
630-
});
631-
}
632-
}
633643

634644
// If this event indicates a terminal state, mark it so we ignore
635645
// any subsequent non-actionable events.
@@ -643,58 +653,99 @@ async function processUrlWithProgress(
643653
}
644654
}
645655

646-
if (finalResult) {
647-
logger.info("CLI processing complete", {
648-
messageId: message.id,
649-
url,
650-
success: finalResult.success,
651-
title: finalResult.title,
652-
error: finalResult.error
653-
});
654-
655-
if (finalResult.success) {
656-
// Remove processing reaction and add success reaction
657-
await removeReaction(message, PROCESSING_REACTION);
658-
await addReaction(message, SUCCESS_REACTION);
659-
660-
// Ensure title or URL displayed is wrapped in backticks to avoid embeds
661-
const displayName = finalResult.title ? `\`${finalResult.title}\`` : `\`${url}\``;
662-
const successMsg = `✅ Added: ${displayName}`;
656+
if (finalResult) {
657+
logger.info("CLI processing complete", {
658+
messageId: message.id,
659+
url,
660+
success: finalResult.success,
661+
title: finalResult.title,
662+
error: finalResult.error
663+
});
664+
665+
if (finalResult.success) {
666+
// Remove processing reaction and add success reaction
667+
await removeReaction(message, PROCESSING_REACTION);
668+
await addReaction(message, SUCCESS_REACTION);
669+
670+
// Ensure title or URL displayed is wrapped in backticks to avoid embeds
671+
const displayName = finalResult.title ? `\`${finalResult.title}\`` : `\`${url}\``;
672+
// If we already have an item id, prepare an item link for the
673+
// immediate confirmation so users see the created item id/link
674+
// as soon as possible.
675+
let successMsg = `✅ Added: ${displayName}`;
676+
const itemId = finalResult.id;
677+
const itemLink = itemId !== undefined ? buildOpenBrainItemLink(itemId, finalResult.url || url) : undefined;
678+
if (itemLink) {
679+
// Use an angle-bracketed link to avoid Discord embeds
680+
successMsg = `✅ Added: ${displayName} — OpenBrain item: <${itemLink}>`;
681+
}
663682

664-
let summaryTargetThread: ThreadChannel | null = thread;
683+
let summaryTargetThread: ThreadChannel | null = thread;
665684

666-
// If we already observed a 'completed' progress event earlier and
667-
// posted it to the thread/channel, avoid posting a duplicate final
668-
// success message. We detect this by checking the lastPhase value.
669-
const alreadyCompleted = lastPhase === "completed";
685+
// If we already observed a 'completed' progress event earlier and
686+
// posted it to the thread/channel, avoid posting a duplicate final
687+
// success message. We detect this by checking the lastPhase value.
688+
const alreadyCompleted = lastPhase === "completed";
670689

671-
if (!alreadyCompleted) {
672-
if (thread) {
673-
try {
674-
await thread.send(successMsg);
675-
} catch (error) {
676-
logger.warn("Failed to send final success message to thread; falling back to channel reply", {
677-
threadId: thread.id,
678-
error: error instanceof Error ? error.message : String(error),
679-
});
680-
summaryTargetThread = null;
681-
// Fallback to channel reply
682-
try {
683-
await message.reply(successMsg);
684-
} catch (err) {
685-
logger.warn("Failed to send fallback success reply to channel", {
686-
messageId: message.id,
687-
error: err instanceof Error ? err.message : String(err),
688-
});
690+
if (!alreadyCompleted) {
691+
if (thread) {
692+
try {
693+
const posted = await thread.send(successMsg);
694+
// capture the final posted message when possible
695+
lastPostedMessage = posted ?? lastPostedMessage;
696+
} catch (error) {
697+
logger.warn("Failed to send final success message to thread; falling back to channel reply", {
698+
threadId: thread.id,
699+
error: error instanceof Error ? error.message : String(error),
700+
});
701+
summaryTargetThread = null;
702+
// Fallback to channel reply
703+
try {
704+
const posted = await message.reply(successMsg);
705+
lastPostedMessage = posted ?? lastPostedMessage;
706+
} catch (err) {
707+
logger.warn("Failed to send fallback success reply to channel", {
708+
messageId: message.id,
709+
error: err instanceof Error ? err.message : String(err),
710+
});
711+
}
712+
}
713+
} else {
714+
// Fallback to message reply if no thread
715+
const posted = await message.reply(successMsg);
716+
lastPostedMessage = posted ?? lastPostedMessage;
717+
}
718+
} else {
719+
// We previously posted a 'completed' progress message. If the
720+
// CLI also returned an item id, append it to the posted message
721+
// so users see the created item id immediately. If editing the
722+
// posted message is not possible, send a concise follow-up.
723+
if (itemId !== undefined) {
724+
try {
725+
const appended = `\n\nOpenBrain item: <${itemLink}>\nItem ID: ${itemId}`;
726+
if (lastPostedMessage && typeof lastPostedMessage.edit === "function") {
727+
// Try to augment the existing message
728+
const prevContent = typeof lastPostedMessage.content === "string" ? lastPostedMessage.content : successMsg;
729+
try {
730+
await lastPostedMessage.edit(prevContent + appended);
731+
} catch (err) {
732+
logger.warn("Failed to edit completed message with item id", { messageId: message.id, error: err instanceof Error ? err.message : String(err) });
733+
// Fallback: post a short follow-up containing the item link
734+
if (thread) await thread.send(`✅ OpenBrain item: <${itemLink}>`);
735+
else await message.reply(`✅ OpenBrain item: <${itemLink}>`);
736+
}
737+
} else {
738+
// Cannot edit previous message – send a short follow-up
739+
if (thread) await thread.send(`✅ OpenBrain item: <${itemLink}>`);
740+
else await message.reply(`✅ OpenBrain item: <${itemLink}>`);
741+
}
742+
} catch (err) {
743+
logger.warn("Failed to post item link follow-up", { messageId: message.id, error: err instanceof Error ? err.message : String(err) });
744+
}
745+
} else {
746+
logger.debug("Skipping duplicate final success message because completed event was already posted", { messageId: message.id, url });
689747
}
690748
}
691-
} else {
692-
// Fallback to message reply if no thread
693-
await message.reply(successMsg);
694-
}
695-
} else {
696-
logger.debug("Skipping duplicate final success message because completed event was already posted", { messageId: message.id, url });
697-
}
698749

699750
await sendGeneratedSummary(message, summaryTargetThread, finalResult);
700751

0 commit comments

Comments
 (0)