MCPcopy
hub / github.com/codeaashu/claude-code / removeMessageByUuid

Method removeMessageByUuid

src/utils/sessionStorage.ts:871–951  ·  view source on GitHub ↗

* Remove a message from the transcript by UUID. * Used for tombstoning orphaned messages from failed streaming attempts. * * The target is almost always the most recently appended entry, so we * read only the tail, locate the line, and splice it out with a * positional write + truncat

(targetUuid: UUID)

Source from the content-addressed store, hash-verified

869 * positional write + truncate instead of rewriting the whole file.
870 */
871 async removeMessageByUuid(targetUuid: UUID): Promise<void> {
872 return this.trackWrite(async () => {
873 if (this.sessionFile === null) return
874 try {
875 let fileSize = 0
876 const fh = await fsOpen(this.sessionFile, 'r+')
877 try {
878 const { size } = await fh.stat()
879 fileSize = size
880 if (size === 0) return
881
882 const chunkLen = Math.min(size, LITE_READ_BUF_SIZE)
883 const tailStart = size - chunkLen
884 const buf = Buffer.allocUnsafe(chunkLen)
885 const { bytesRead } = await fh.read(buf, 0, chunkLen, tailStart)
886 const tail = buf.subarray(0, bytesRead)
887
888 // Entries are serialized via JSON.stringify (no key-value
889 // whitespace). Search for the full `"uuid":"..."` pattern, not
890 // just the bare UUID, so we do not match the same value sitting
891 // in `parentUuid` of a child entry. UUIDs are pure ASCII so a
892 // byte-level search is correct.
893 const needle = `"uuid":"${targetUuid}"`
894 const matchIdx = tail.lastIndexOf(needle)
895
896 if (matchIdx >= 0) {
897 // 0x0a never appears inside a UTF-8 multi-byte sequence, so
898 // byte-scanning for line boundaries is safe even if the chunk
899 // starts mid-character.
900 const prevNl = tail.lastIndexOf(0x0a, matchIdx)
901 // If the preceding newline is outside our chunk and we did not
902 // read from the start of the file, the line is longer than the
903 // window - fall through to the slow path.
904 if (prevNl >= 0 || tailStart === 0) {
905 const lineStart = prevNl + 1 // 0 when prevNl === -1
906 const nextNl = tail.indexOf(0x0a, matchIdx + needle.length)
907 const lineEnd = nextNl >= 0 ? nextNl + 1 : bytesRead
908
909 const absLineStart = tailStart + lineStart
910 const afterLen = bytesRead - lineEnd
911 // Truncate first, then re-append the trailing lines. In the
912 // common case (target is the last entry) afterLen is 0 and
913 // this is a single ftruncate.
914 await fh.truncate(absLineStart)
915 if (afterLen > 0) {
916 await fh.write(tail, lineEnd, afterLen, absLineStart)
917 }
918 return
919 }
920 }
921 } finally {
922 await fh.close()
923 }
924
925 // Slow path: target was not in the last 64KB. Rare - requires many
926 // large entries to have landed between the write and the tombstone.
927 if (fileSize > MAX_TOMBSTONE_REWRITE_BYTES) {
928 logForDebugging(

Callers 1

removeTranscriptMessageFunction · 0.80

Calls 8

trackWriteMethod · 0.95
logForDebuggingFunction · 0.85
formatFileSizeFunction · 0.85
readFileFunction · 0.85
jsonParseFunction · 0.85
readMethod · 0.65
writeMethod · 0.45
closeMethod · 0.45

Tested by

no test coverage detected