fix: RevertBanner UI shows no changes after successful file revert (#8121)

* core: fix revert diff showing incorrect changes after file restore

When reverting a session, the diff was computed after files were already
reverted to their pre-change state, producing an empty or wrong diff.
By computing the diff before restoring files, the revert summary now
correctly reflects what was actually undone for the user.

* core: reduce revert diff size in DB to save storage

Full file contents were being stored in the session summary diffs,
causing unnecessary database bloat. The webview RevertBanner only
needs file path, line counts, and status — not the full diff content.

* chore(cli): add kilocode_change markers to revert diff changes

---------

Co-authored-by: Marius <marius@kilocode.ai>
This commit is contained in:
Aarav
2026-04-02 12:21:43 +02:00
committed by GitHub
co-authored by Marius
parent 3b2db43a4b
commit 2e3b9a2432
5 changed files with 111 additions and 8 deletions
+13 -1
View File
@@ -130,7 +130,18 @@ export namespace Session {
additions: z.number(),
deletions: z.number(),
files: z.number(),
diffs: Snapshot.FileDiff.array().optional(),
// kilocode_change start - lightweight diff summary (no file contents)
diffs: z
.array(
z.object({
file: z.string(),
additions: z.number(),
deletions: z.number(),
status: z.enum(["added", "deleted", "modified"]).optional(),
}),
)
.optional(),
// kilocode_change end
})
.optional(),
share: z
@@ -483,6 +494,7 @@ export namespace Session {
summary_additions: input.summary?.additions,
summary_deletions: input.summary?.deletions,
summary_files: input.summary?.files,
summary_diffs: input.summary?.diffs ?? null, // kilocode_change
time_updated: Date.now(),
})
.where(eq(SessionTable.id, input.sessionID))
+15 -2
View File
@@ -57,15 +57,27 @@ export namespace SessionRevert {
if (revert) {
const session = await Session.get(input.sessionID)
revert.snapshot = session.revert?.snapshot ?? (await Snapshot.track())
await Snapshot.revert(patches)
if (revert.snapshot) revert.diff = await Snapshot.diff(revert.snapshot)
// kilocode_change start - compute diffs BEFORE reverting files so the diff
// reflects changes being undone (files on disk still have AI modifications)
const rangeMessages = all.filter((msg) => msg.info.id >= revert!.messageID)
const diffs = await SessionSummary.computeDiff({ messages: rangeMessages })
await Snapshot.revert(patches)
if (revert.snapshot) revert.diff = await Snapshot.diff(revert.snapshot)
// kilocode_change end
await Storage.write(["session_diff", input.sessionID], diffs)
Bus.publish(Session.Event.Diff, {
sessionID: input.sessionID,
diff: diffs,
})
// kilocode_change start - strip full file contents before persisting to DB
const summaryDiffs = diffs.map((d) => ({
file: d.file,
additions: d.additions,
deletions: d.deletions,
status: d.status,
}))
// kilocode_change end
return Session.setRevert({
sessionID: input.sessionID,
revert,
@@ -73,6 +85,7 @@ export namespace SessionRevert {
additions: diffs.reduce((sum, x) => sum + x.additions, 0),
deletions: diffs.reduce((sum, x) => sum + x.deletions, 0),
files: diffs.length,
diffs: summaryDiffs, // kilocode_change
},
})
}
+5 -1
View File
@@ -25,7 +25,11 @@ export const SessionTable = sqliteTable(
summary_additions: integer(),
summary_deletions: integer(),
summary_files: integer(),
summary_diffs: text({ mode: "json" }).$type<Snapshot.FileDiff[]>(),
// kilocode_change start - lightweight diff type (no file contents)
summary_diffs: text({ mode: "json" }).$type<
{ file: string; additions: number; deletions: number; status?: "added" | "deleted" | "modified" }[]
>(),
// kilocode_change end
revert: text({ mode: "json" }).$type<{ messageID: string; partID?: string; snapshot?: string; diff?: string }>(),
permission: text({ mode: "json" }).$type<PermissionNext.Ruleset>(),
...Timestamps,
+12 -2
View File
@@ -833,7 +833,12 @@ export type Session = {
additions: number
deletions: number
files: number
diffs?: Array<FileDiff>
diffs?: Array<{
file: string
additions: number
deletions: number
status?: "added" | "deleted" | "modified"
}>
}
share?: {
url: string
@@ -1749,7 +1754,12 @@ export type GlobalSession = {
additions: number
deletions: number
files: number
diffs?: Array<FileDiff>
diffs?: Array<{
file: string
additions: number
deletions: number
status?: "added" | "deleted" | "modified"
}>
}
share?: {
url: string
+66 -2
View File
@@ -5805,6 +5805,9 @@
},
"id": {
"type": "string"
},
"skipped": {
"type": "boolean"
}
},
"required": [
@@ -5927,6 +5930,9 @@
},
"id": {
"type": "string"
},
"skipped": {
"type": "boolean"
}
},
"required": [
@@ -6106,6 +6112,9 @@
},
"id": {
"type": "string"
},
"skipped": {
"type": "boolean"
}
},
"required": [
@@ -6368,6 +6377,9 @@
},
"id": {
"type": "string"
},
"skipped": {
"type": "boolean"
}
},
"required": [
@@ -12487,7 +12499,31 @@
"diffs": {
"type": "array",
"items": {
"$ref": "#/components/schemas/FileDiff"
"type": "object",
"properties": {
"file": {
"type": "string"
},
"additions": {
"type": "number"
},
"deletions": {
"type": "number"
},
"status": {
"type": "string",
"enum": [
"added",
"deleted",
"modified"
]
}
},
"required": [
"file",
"additions",
"deletions"
]
}
}
},
@@ -13975,6 +14011,10 @@
"description": "@deprecated Use 'share' field instead. Share newly created sessions automatically",
"type": "boolean"
},
"remote_control": {
"description": "Enable remote control of sessions via Kilo Cloud. Equivalent to running /remote on startup.",
"type": "boolean"
},
"autoupdate": {
"description": "Automatically update to the latest version. Set to true to auto-update, false to disable, or 'notify' to show update notifications",
"anyOf": [
@@ -15061,7 +15101,31 @@
"diffs": {
"type": "array",
"items": {
"$ref": "#/components/schemas/FileDiff"
"type": "object",
"properties": {
"file": {
"type": "string"
},
"additions": {
"type": "number"
},
"deletions": {
"type": "number"
},
"status": {
"type": "string",
"enum": [
"added",
"deleted",
"modified"
]
}
},
"required": [
"file",
"additions",
"deletions"
]
}
}
},