@@ -53,9 +53,11 @@ import {
5353 awaitCIWithFailFast ,
5454 getLatestCIRun as getCIRunDetails ,
5555 extractAllPreviews ,
56- extractLinkedIssuesFromPR ,
56+ extractLinkedIssuesWithInfo ,
5757 type GroupedPreviewUrls ,
58+ type LinkedIssueInfo ,
5859} from '../shared/hooks/utils/ci-status.js' ;
60+ import { getSessionIssues , type IssueReference } from '../shared/hooks/utils/session-issues.js' ;
5961import { addPRToState } from '../shared/hooks/utils/github-state.js' ;
6062import { exec } from 'child_process' ;
6163import { promisify } from 'util' ;
@@ -725,6 +727,33 @@ Session-Timestamp: ${timestamp}${branch ? `\nBranch: ${branch}` : ''}
725727Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>` ;
726728}
727729
730+ /**
731+ * Format a linked issue for display
732+ * @param issue - Issue info with number, url, and repo
733+ * @param prRepo - PR's repository for comparison
734+ * @returns Formatted issue string
735+ */
736+ function formatLinkedIssue ( issue : LinkedIssueInfo , prRepo : string ) : string {
737+ // If same repo as PR, show just #number
738+ // If different repo, show owner/repo#number
739+ const prefix = issue . repo === prRepo ? `#${ issue . number } ` : `${ issue . repo } #${ issue . number } ` ;
740+ const titlePart = issue . title ? ` - ${ issue . title } ` : '' ;
741+ return `${ prefix } ${ titlePart } → ${ issue . url } ` ;
742+ }
743+
744+ /**
745+ * Format a session issue for display (other issues section)
746+ * @param issue - Issue reference from session tracking
747+ * @param currentRepo - Current repository for comparison
748+ * @returns Formatted issue string
749+ */
750+ function formatSessionIssue ( issue : IssueReference , currentRepo : string ) : string {
751+ // If same repo, show just #number; if different, show owner/repo#number
752+ const prefix = issue . repo === currentRepo ? `#${ issue . number } ` : `${ issue . repo } #${ issue . number } ` ;
753+ const titlePart = issue . title ? ` - ${ issue . title } ` : '' ;
754+ return `${ prefix } ${ titlePart } → ${ issue . url } ` ;
755+ }
756+
728757/**
729758 * Format PR status message when commit was made and PR exists
730759 * @param commitSha - Commit SHA
@@ -737,7 +766,9 @@ Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>`;
737766 * @param ciRun.conclusion - CI run conclusion
738767 * @param ciRun.name - CI run name
739768 * @param groupedPreviews - Preview URLs grouped by provider
740- * @param linkedIssues - Issue numbers linked from PR body
769+ * @param linkedIssues - Issues linked from PR body (closes when merged)
770+ * @param otherIssues - Other issues created during session but not linked to PR
771+ * @param prRepo - PR's repository name (owner/repo)
741772 * @returns Formatted message
742773 * @example
743774 */
@@ -746,7 +777,9 @@ function formatPRStatusWithCommit(
746777 prCheck : { prNumber : number ; prUrl : string } ,
747778 ciRun : { url ?: string ; status ?: string ; conclusion ?: string ; name ?: string } ,
748779 groupedPreviews : GroupedPreviewUrls ,
749- linkedIssues : number [ ]
780+ linkedIssues : LinkedIssueInfo [ ] ,
781+ otherIssues : IssueReference [ ] ,
782+ prRepo : string
750783) : string {
751784 const ciPassed = ciRun . conclusion === 'success' ;
752785 const ciFailed = ciRun . conclusion === 'failure' ;
@@ -762,11 +795,19 @@ function formatPRStatusWithCommit(
762795 message += `🔄 CI: ${ ciRun . url } ${ statusIcon } ${ ciRun . conclusion || ciRun . status || 'pending' } \n` ;
763796 }
764797
765- // Linked issues (if any)
798+ // Linked issues (closes when merged) - nested under PR
766799 if ( linkedIssues . length > 0 ) {
767- message += '\n📌 Linked Issue(s):\n' ;
768- for ( const issueNum of linkedIssues ) {
769- message += ` • #${ issueNum } \n` ;
800+ message += '\n 📌 Linked Issues (closes when merged):\n' ;
801+ for ( const issue of linkedIssues ) {
802+ message += ` • ${ formatLinkedIssue ( issue , prRepo ) } \n` ;
803+ }
804+ }
805+
806+ // Other issues created during session (not linked to PR)
807+ if ( otherIssues . length > 0 ) {
808+ message += '\n📝 Other Issues Created:\n' ;
809+ for ( const issue of otherIssues ) {
810+ message += ` • ${ formatSessionIssue ( issue , prRepo ) } \n` ;
770811 }
771812 }
772813
@@ -809,15 +850,19 @@ function formatPRStatusWithCommit(
809850 * @param ciRun.conclusion - CI run conclusion
810851 * @param ciRun.name - CI run name
811852 * @param groupedPreviews - Preview URLs grouped by provider
812- * @param linkedIssues - Issue numbers linked from PR body
853+ * @param linkedIssues - Issues linked from PR body (closes when merged)
854+ * @param otherIssues - Other issues created during session but not linked to PR
855+ * @param prRepo - PR's repository name (owner/repo)
813856 * @returns Formatted message
814857 * @example
815858 */
816859function formatPRStatusInfo (
817860 prCheck : { prNumber : number ; prUrl : string } ,
818861 ciRun : { url ?: string ; status ?: string ; conclusion ?: string ; name ?: string } ,
819862 groupedPreviews : GroupedPreviewUrls ,
820- linkedIssues : number [ ]
863+ linkedIssues : LinkedIssueInfo [ ] ,
864+ otherIssues : IssueReference [ ] ,
865+ prRepo : string
821866) : string {
822867 // Header (simplified - this function only called when CI passed or pending)
823868 let message = '✅ PR Ready for Review\n\n' ;
@@ -830,11 +875,19 @@ function formatPRStatusInfo(
830875 message += `🔄 [View CI Run](${ ciRun . url } ) ✅ success\n` ;
831876 }
832877
833- // Linked issues (if any)
878+ // Linked issues (closes when merged) - nested under PR
834879 if ( linkedIssues . length > 0 ) {
835- message += '\n📌 Linked Issue(s):\n' ;
836- for ( const issueNum of linkedIssues ) {
837- message += ` • #${ issueNum } \n` ;
880+ message += '\n 📌 Linked Issues (closes when merged):\n' ;
881+ for ( const issue of linkedIssues ) {
882+ message += ` • ${ formatLinkedIssue ( issue , prRepo ) } \n` ;
883+ }
884+ }
885+
886+ // Other issues created during session (not linked to PR)
887+ if ( otherIssues . length > 0 ) {
888+ message += '\n📝 Other Issues Created:\n' ;
889+ for ( const issue of otherIssues ) {
890+ message += ` • ${ formatSessionIssue ( issue , prRepo ) } \n` ;
838891 }
839892 }
840893
@@ -1215,22 +1268,33 @@ ${checksTable}
12151268 checks : ciResult . checks
12161269 } ) ;
12171270
1218- // Fetch PR details, previews, and linked issues in parallel
1219- const [ ciRun , groupedPreviews , linkedIssues ] = await Promise . all ( [
1271+ // Fetch PR details, previews, linked issues, and session issues in parallel
1272+ const [ ciRun , groupedPreviews , linkedIssues , sessionIssues ] = await Promise . all ( [
12201273 getCIRunDetails ( prCheck . prNumber , repoRoot ) . then ( r => r ?? { } ) ,
12211274 extractAllPreviews ( prCheck . prNumber , repoRoot ) ,
1222- extractLinkedIssuesFromPR ( prCheck . prNumber , repoRoot ) ,
1275+ extractLinkedIssuesWithInfo ( prCheck . prNumber , repoRoot ) ,
1276+ getSessionIssues ( input . session_id , repoRoot ) ,
12231277 ] ) ;
12241278
1225- // Track PR in github.json
1279+ // Extract PR repo from URL for display formatting
1280+ const prRepoMatch = prCheck . prUrl . match ( / g i t h u b \. c o m \/ ( [ ^ / ] + \/ [ ^ / ] + ) \/ p u l l / ) ;
1281+ const prRepo = prRepoMatch ? prRepoMatch [ 1 ] : '' ;
1282+
1283+ // Filter session issues to find "other issues" not linked to the PR
1284+ const linkedIssueKeys = new Set ( linkedIssues . map ( i => `${ i . repo } #${ i . number } ` ) ) ;
1285+ const otherIssues = sessionIssues . filter (
1286+ issue => ! linkedIssueKeys . has ( `${ issue . repo } #${ issue . number } ` )
1287+ ) ;
1288+
1289+ // Track PR in github.json (store just issue numbers for backwards compatibility)
12261290 await addPRToState (
12271291 input . session_id ,
12281292 {
12291293 number : prCheck . prNumber ,
12301294 url : prCheck . prUrl ,
12311295 title : '' , // We don't have title here, could fetch if needed
12321296 createdAt : new Date ( ) . toISOString ( ) ,
1233- linkedIssues,
1297+ linkedIssues : linkedIssues . map ( i => i . number ) ,
12341298 } ,
12351299 repoRoot
12361300 ) ;
@@ -1252,19 +1316,19 @@ ${checksTable}
12521316 // Show PR status after commit (non-blocking)
12531317 return {
12541318 decision : 'approve' ,
1255- systemMessage : formatPRStatusWithCommit ( commitSha , { prNumber : prCheck . prNumber , prUrl : prCheck . prUrl } , ciRun , groupedPreviews , linkedIssues ) ,
1319+ systemMessage : formatPRStatusWithCommit ( commitSha , { prNumber : prCheck . prNumber , prUrl : prCheck . prUrl } , ciRun , groupedPreviews , linkedIssues , otherIssues , prRepo ) ,
12561320 } ;
12571321 } else if ( commitsAheadOfMain > 0 ) {
12581322 // Show PR status to user (non-blocking)
12591323 return {
12601324 decision : 'approve' ,
1261- systemMessage : formatPRStatusInfo ( { prNumber : prCheck . prNumber , prUrl : prCheck . prUrl } , ciRun , groupedPreviews , linkedIssues ) ,
1325+ systemMessage : formatPRStatusInfo ( { prNumber : prCheck . prNumber , prUrl : prCheck . prUrl } , ciRun , groupedPreviews , linkedIssues , otherIssues , prRepo ) ,
12621326 } ;
12631327 } else {
12641328 // Always show PR status when PR exists, even if no new commits this session (non-blocking)
12651329 return {
12661330 decision : 'approve' ,
1267- systemMessage : formatPRStatusInfo ( { prNumber : prCheck . prNumber , prUrl : prCheck . prUrl } , ciRun , groupedPreviews , linkedIssues ) ,
1331+ systemMessage : formatPRStatusInfo ( { prNumber : prCheck . prNumber , prUrl : prCheck . prUrl } , ciRun , groupedPreviews , linkedIssues , otherIssues , prRepo ) ,
12681332 } ;
12691333 }
12701334 }
0 commit comments