@@ -166,19 +166,26 @@ function renderEnhancedOutput(
166166 let currentIsTrunk = false ;
167167 let currentIsForkPoint = false ; // Immutable commit included only for graph connectivity
168168 let currentIsBehindTrunk = false ; // Mutable commit whose parent is not current trunk
169+ let currentIsWorkingCopy = false ; // Whether this is the @ commit
170+ let _currentIsEmpty = false ; // Whether the change has no file modifications
169171 let pendingHints : string [ ] = [ ] ; // Buffer hints to output after COMMIT
170172
171- // Check if WC parent is a tracked bookmark ( for modify hint)
172- // We only show "arr modify" if WC is on top of a tracked change
173- const wcParentBookmark : string | null = null ;
173+ // Find WC parent bookmark for modify hint by looking at the next CHANGE after WC
174+ let wcParentBookmark : string | null = null ;
175+ let foundWC = false ;
174176 for ( const line of lines ) {
175- if ( line . includes ( "HINT:empty" ) ) {
176- // WC is empty - check if parent is a tracked bookmark by looking at graph structure
177- // The parent in jj graph is indicated by the line connecting @ to the next commit
178- // But we can't reliably parse this from output, so check tracked bookmarks
179- // If there's exactly one tracked bookmark that's a direct parent of @, use it
180- // For now, we'll be conservative and not show modify hint unless we're certain
181- // TODO: Query jj for @- to get actual parent
177+ if ( line . includes ( "@" ) && line . includes ( "CHANGE:" ) ) {
178+ foundWC = true ;
179+ continue ;
180+ }
181+ if ( foundWC && line . includes ( "CHANGE:" ) ) {
182+ // This is the first change after WC - check if it has a tracked bookmark
183+ const match = line . match ( / C H A N G E : [ ^ | ] + \| [ ^ | ] * \| [ ^ | ] * \| [ ^ | ] * \| ( [ ^ | ] * ) \| / ) ;
184+ if ( match ) {
185+ const bookmarks = parseBookmarks ( match [ 1 ] ) ;
186+ wcParentBookmark =
187+ bookmarks . find ( ( b ) => trackedBookmarks . includes ( b ) ) || null ;
188+ }
182189 break ;
183190 }
184191 }
@@ -223,6 +230,7 @@ function renderEnhancedOutput(
223230 const isEmpty = emptyFlag === "1" ;
224231 const isImmutable = immutableFlag === "1" ;
225232 const hasConflict = conflictFlag === "1" ;
233+ const isWorkingCopy = graphPrefix . includes ( "@" ) ;
226234
227235 // Update context for subsequent lines (TIME, PR, COMMIT)
228236 currentBookmark =
@@ -235,6 +243,8 @@ function renderEnhancedOutput(
235243 // Fork point: immutable commit that's not trunk (included for graph connectivity)
236244 currentIsForkPoint = isImmutable && ! isTrunk ;
237245 currentIsBehindTrunk = behindTrunkChanges . has ( changeId ) ;
246+ currentIsWorkingCopy = isWorkingCopy ;
247+ _currentIsEmpty = isEmpty ;
238248
239249 // Skip rendering fork points - just keep graph lines
240250 if ( currentIsForkPoint ) {
@@ -249,7 +259,7 @@ function renderEnhancedOutput(
249259 // Replace the marker in graphPrefix with our styled version
250260 // jj uses: @ for WC, ○ for mutable, ◆ for immutable
251261 let styledPrefix = graphPrefix ;
252- if ( graphPrefix . includes ( "@" ) ) {
262+ if ( isWorkingCopy ) {
253263 styledPrefix = graphPrefix . replace ( "@" , green ( "◉" ) ) ;
254264 } else if ( graphPrefix . includes ( "◆" ) ) {
255265 styledPrefix = graphPrefix . replace ( "◆" , "◯" ) ;
@@ -258,8 +268,8 @@ function renderEnhancedOutput(
258268 }
259269
260270 // Build the label
261- if ( isEmpty && ! description && ! isImmutable ) {
262- // Empty WC
271+ if ( isWorkingCopy && ! currentBookmark ) {
272+ // Working copy without a bookmark - show "(working copy)"
263273 output . push ( `${ styledPrefix } ${ blue ( "(working copy)" ) } ` ) ;
264274 } else if ( isTrunk ) {
265275 output . push ( `${ styledPrefix } ${ blue ( trunkName ) } ` ) ;
@@ -298,20 +308,8 @@ function renderEnhancedOutput(
298308 }
299309
300310 case "HINT:" : {
301- if ( data === "empty" ) {
302- // Buffer hints to output after COMMIT line
303- // Use a clean "│ " prefix, not the graph prefix which may have ~ terminators
304- const hintPrefix = "│ " ;
305- pendingHints . push (
306- `${ hintPrefix } ${ arr ( COMMANDS . create ) } ${ dim ( '"message"' ) } ${ dim ( "to save as new change" ) } ` ,
307- ) ;
308- // Only show modify hint if WC parent is a tracked bookmark
309- if ( wcParentBookmark ) {
310- pendingHints . push (
311- `${ hintPrefix } ${ arr ( COMMANDS . modify ) } ${ dim ( `to update ${ wcParentBookmark } ` ) } ` ,
312- ) ;
313- }
314- }
311+ // Hints are now handled in COMMIT case for all WC states
312+ // This case is kept for potential future use
315313 break ;
316314 }
317315
@@ -370,6 +368,20 @@ function renderEnhancedOutput(
370368 output . push (
371369 `${ prefix } ${ commitIdFormatted } ${ dim ( `- ${ description || "(no description)" } ` ) } ` ,
372370 ) ;
371+
372+ // Add hints for WC without a bookmark (whether empty or with changes)
373+ if ( currentIsWorkingCopy && ! currentBookmark ) {
374+ const hintPrefix = "│ " ;
375+ pendingHints . push (
376+ `${ hintPrefix } ${ arr ( COMMANDS . create ) } ${ dim ( '"message"' ) } ${ dim ( "to save as new change" ) } ` ,
377+ ) ;
378+ if ( wcParentBookmark ) {
379+ pendingHints . push (
380+ `${ hintPrefix } ${ arr ( COMMANDS . modify ) } ${ dim ( `to update ${ wcParentBookmark } ` ) } ` ,
381+ ) ;
382+ }
383+ }
384+
373385 // Output any pending hints after commit
374386 if ( pendingHints . length > 0 ) {
375387 for ( const hint of pendingHints ) {
0 commit comments