fix(hook-message-injector): add process-unique prefix to message/part IDs to prevent storage collisions
IDs now include a random 8-hex-char prefix per process (e.g. msg_a1b2c3d4_000001) preventing collisions when counters reset across process restarts.
This commit is contained in:
@@ -197,7 +197,7 @@ describe("findFirstMessageWithAgentFromSDK", () => {
|
|||||||
describe("generateMessageId", () => {
|
describe("generateMessageId", () => {
|
||||||
it("returns deterministic sequential IDs with fixed format", () => {
|
it("returns deterministic sequential IDs with fixed format", () => {
|
||||||
// given
|
// given
|
||||||
const format = /^msg_\d{12}$/
|
const format = /^msg_[0-9a-f]{8}_\d{6}$/
|
||||||
|
|
||||||
// when
|
// when
|
||||||
const firstId = generateMessageId()
|
const firstId = generateMessageId()
|
||||||
@@ -206,14 +206,15 @@ describe("generateMessageId", () => {
|
|||||||
// then
|
// then
|
||||||
expect(firstId).toMatch(format)
|
expect(firstId).toMatch(format)
|
||||||
expect(secondId).toMatch(format)
|
expect(secondId).toMatch(format)
|
||||||
expect(Number(secondId.slice(4))).toBe(Number(firstId.slice(4)) + 1)
|
expect(secondId.split("_")[1]).toBe(firstId.split("_")[1])
|
||||||
|
expect(Number(secondId.split("_")[2])).toBe(Number(firstId.split("_")[2]) + 1)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("generatePartId", () => {
|
describe("generatePartId", () => {
|
||||||
it("returns deterministic sequential IDs with fixed format", () => {
|
it("returns deterministic sequential IDs with fixed format", () => {
|
||||||
// given
|
// given
|
||||||
const format = /^prt_\d{12}$/
|
const format = /^prt_[0-9a-f]{8}_\d{6}$/
|
||||||
|
|
||||||
// when
|
// when
|
||||||
const firstId = generatePartId()
|
const firstId = generatePartId()
|
||||||
@@ -222,7 +223,8 @@ describe("generatePartId", () => {
|
|||||||
// then
|
// then
|
||||||
expect(firstId).toMatch(format)
|
expect(firstId).toMatch(format)
|
||||||
expect(secondId).toMatch(format)
|
expect(secondId).toMatch(format)
|
||||||
expect(Number(secondId.slice(4))).toBe(Number(firstId.slice(4)) + 1)
|
expect(secondId.split("_")[1]).toBe(firstId.split("_")[1])
|
||||||
|
expect(Number(secondId.split("_")[2])).toBe(Number(firstId.split("_")[2]) + 1)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs"
|
import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs"
|
||||||
|
import { randomBytes } from "node:crypto"
|
||||||
import { join } from "node:path"
|
import { join } from "node:path"
|
||||||
import type { PluginInput } from "@opencode-ai/plugin"
|
import type { PluginInput } from "@opencode-ai/plugin"
|
||||||
import { MESSAGE_STORAGE, PART_STORAGE } from "./constants"
|
import { MESSAGE_STORAGE, PART_STORAGE } from "./constants"
|
||||||
@@ -29,6 +30,7 @@ interface SDKMessage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const processPrefix = randomBytes(4).toString("hex")
|
||||||
let messageCounter = 0
|
let messageCounter = 0
|
||||||
let partCounter = 0
|
let partCounter = 0
|
||||||
|
|
||||||
@@ -208,11 +210,11 @@ export function findFirstMessageWithAgent(messageDir: string): string | null {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function generateMessageId(): string {
|
export function generateMessageId(): string {
|
||||||
return `msg_${String(++messageCounter).padStart(12, "0")}`
|
return `msg_${processPrefix}_${String(++messageCounter).padStart(6, "0")}`
|
||||||
}
|
}
|
||||||
|
|
||||||
export function generatePartId(): string {
|
export function generatePartId(): string {
|
||||||
return `prt_${String(++partCounter).padStart(12, "0")}`
|
return `prt_${processPrefix}_${String(++partCounter).padStart(6, "0")}`
|
||||||
}
|
}
|
||||||
|
|
||||||
function getOrCreateMessageDir(sessionID: string): string {
|
function getOrCreateMessageDir(sessionID: string): string {
|
||||||
|
|||||||
Reference in New Issue
Block a user