chenbhao commited on
Commit
3decf19
·
1 Parent(s): 2c4e38d

fix: /goal clear but /resume will get old goal

Browse files

/goal clear 只清了内存中的 AppState.goal,但在 reAppendSessionMetadata 退出时把旧缓存 currentSessionGoal 又写回了
transcript。而且 loadTranscriptFile 是 last-wins 逻辑,一条旧的 goal entry 永远不会被清除。

需要两个修复:
1. /goal clear 时写入一条 goal 且带 cleared 标记,或写入 null 来覆盖
2. reAppendSessionMetadata 不要在 goal 已清除时重新写入

最简洁的方案:写入一条 goal: null 的 entry,加载时遇到 null 就视为无 goal

Files changed (1) hide show
  1. src/utils/sessionStorage.ts +38 -6
src/utils/sessionStorage.ts CHANGED
@@ -546,7 +546,9 @@ class Project {
546
  currentSessionPrUrl: string | undefined
547
  currentSessionPrRepository: string | undefined
548
  // /goal state — re-appended on exit so --resume restores it
549
- currentSessionGoal: GoalEntry | undefined
 
 
550
 
551
  sessionFile: string | null = null
552
  // Entries buffered while sessionFile is null. Flushed by materializeSessionFile
@@ -843,6 +845,21 @@ class Project {
843
  ...this.currentSessionGoal,
844
  sessionId,
845
  })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
846
  }
847
  }
848
 
@@ -2951,12 +2968,27 @@ export function saveGoal(goal: GoalEntry): void {
2951
  }
2952
 
2953
  /**
2954
- * Clear the cached goal state. Called when /goal clear removes the goal,
2955
- * or when restoreSessionMetadata runs for a session that had no goal.
 
2956
  */
2957
  export function clearGoal(): void {
2958
  const project = getProject()
2959
- project.currentSessionGoal = undefined
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2960
  }
2961
 
2962
  /**
@@ -3655,7 +3687,7 @@ export async function loadTranscriptFile(
3655
  prUrls.set(entry.sessionId, entry.prUrl)
3656
  prRepositories.set(entry.sessionId, entry.prRepository)
3657
  } else if (entry.type === 'goal' && entry.sessionId) {
3658
- goal = entry
3659
  }
3660
  }
3661
  }
@@ -3725,7 +3757,7 @@ export async function loadTranscriptFile(
3725
  prUrls.set(entry.sessionId, entry.prUrl)
3726
  prRepositories.set(entry.sessionId, entry.prRepository)
3727
  } else if (entry.type === 'goal' && entry.sessionId) {
3728
- goal = entry
3729
  } else if (entry.type === 'file-history-snapshot') {
3730
  fileHistorySnapshots.set(entry.messageId, entry)
3731
  } else if (entry.type === 'attribution-snapshot') {
 
546
  currentSessionPrUrl: string | undefined
547
  currentSessionPrRepository: string | undefined
548
  // /goal state — re-appended on exit so --resume restores it
549
+ // Tri-state: undefined = never touched, GoalEntry = active goal,
550
+ // null = cleared (write a tombstone so resume doesn't restore stale goal).
551
+ currentSessionGoal: GoalEntry | null | undefined
552
 
553
  sessionFile: string | null = null
554
  // Entries buffered while sessionFile is null. Flushed by materializeSessionFile
 
845
  ...this.currentSessionGoal,
846
  sessionId,
847
  })
848
+ } else if (this.currentSessionGoal === null) {
849
+ // Goal was explicitly cleared — write a tombstone so resume
850
+ // doesn't restore a stale goal from an earlier entry.
851
+ appendEntryToFile(this.sessionFile, {
852
+ type: 'goal',
853
+ id: '__cleared__',
854
+ objective: '',
855
+ status: 'achieved',
856
+ startedAt: 0,
857
+ startCostUSD: 0,
858
+ startTokensUsed: 0,
859
+ continuationCount: 0,
860
+ lastUpdatedAt: 0,
861
+ sessionId,
862
+ })
863
  }
864
  }
865
 
 
2968
  }
2969
 
2970
  /**
2971
+ * Clear the goal state and write a tombstone entry to the transcript.
2972
+ * Without the tombstone, a stale goal entry from earlier in the session
2973
+ * would be restored on --resume (last-wins, but no later entry to win).
2974
  */
2975
  export function clearGoal(): void {
2976
  const project = getProject()
2977
+ project.currentSessionGoal = null
2978
+ if (project.sessionFile) {
2979
+ appendEntryToFile(project.sessionFile, {
2980
+ type: 'goal',
2981
+ id: '__cleared__',
2982
+ objective: '',
2983
+ status: 'achieved',
2984
+ startedAt: 0,
2985
+ startCostUSD: 0,
2986
+ startTokensUsed: 0,
2987
+ continuationCount: 0,
2988
+ lastUpdatedAt: 0,
2989
+ sessionId: getSessionId(),
2990
+ })
2991
+ }
2992
  }
2993
 
2994
  /**
 
3687
  prUrls.set(entry.sessionId, entry.prUrl)
3688
  prRepositories.set(entry.sessionId, entry.prRepository)
3689
  } else if (entry.type === 'goal' && entry.sessionId) {
3690
+ goal = entry.id === '__cleared__' ? undefined : entry
3691
  }
3692
  }
3693
  }
 
3757
  prUrls.set(entry.sessionId, entry.prUrl)
3758
  prRepositories.set(entry.sessionId, entry.prRepository)
3759
  } else if (entry.type === 'goal' && entry.sessionId) {
3760
+ goal = entry.id === '__cleared__' ? undefined : entry
3761
  } else if (entry.type === 'file-history-snapshot') {
3762
  fileHistorySnapshots.set(entry.messageId, entry)
3763
  } else if (entry.type === 'attribution-snapshot') {