fix(hook-message-injector): use monotonic counter for deterministic message/part IDs

This commit is contained in:
YeonGyu-Kim
2026-02-28 13:30:14 +09:00
parent cc6ab1addc
commit 6e9f27350d
2 changed files with 41 additions and 8 deletions

View File

@@ -4,6 +4,8 @@ import {
findFirstMessageWithAgent,
findNearestMessageWithFieldsFromSDK,
findFirstMessageWithAgentFromSDK,
generateMessageId,
generatePartId,
injectHookMessage,
} from "./injector"
import { isSqliteBackend, resetSqliteBackendCache } from "../../shared/opencode-storage-detection"
@@ -192,6 +194,38 @@ describe("findFirstMessageWithAgentFromSDK", () => {
})
})
describe("generateMessageId", () => {
it("returns deterministic sequential IDs with fixed format", () => {
// given
const format = /^msg_\d{12}$/
// when
const firstId = generateMessageId()
const secondId = generateMessageId()
// then
expect(firstId).toMatch(format)
expect(secondId).toMatch(format)
expect(Number(secondId.slice(4))).toBe(Number(firstId.slice(4)) + 1)
})
})
describe("generatePartId", () => {
it("returns deterministic sequential IDs with fixed format", () => {
// given
const format = /^prt_\d{12}$/
// when
const firstId = generatePartId()
const secondId = generatePartId()
// then
expect(firstId).toMatch(format)
expect(secondId).toMatch(format)
expect(Number(secondId.slice(4))).toBe(Number(firstId.slice(4)) + 1)
})
})
describe("injectHookMessage", () => {
beforeEach(() => {
vi.clearAllMocks()

View File

@@ -29,6 +29,9 @@ interface SDKMessage {
}
}
let messageCounter = 0
let partCounter = 0
function convertSDKMessageToStoredMessage(msg: SDKMessage): StoredMessage | null {
const info = msg.info
if (!info) return null
@@ -204,16 +207,12 @@ export function findFirstMessageWithAgent(messageDir: string): string | null {
return null
}
function generateMessageId(): string {
const timestamp = Date.now().toString(16)
const random = Math.random().toString(36).substring(2, 14)
return `msg_${timestamp}${random}`
export function generateMessageId(): string {
return `msg_${String(++messageCounter).padStart(12, "0")}`
}
function generatePartId(): string {
const timestamp = Date.now().toString(16)
const random = Math.random().toString(36).substring(2, 10)
return `prt_${timestamp}${random}`
export function generatePartId(): string {
return `prt_${String(++partCounter).padStart(12, "0")}`
}
function getOrCreateMessageDir(sessionID: string): string {