fix: fix bug conversation log syncronization

This commit is contained in:
d-kimsuon
2025-10-15 12:59:05 +09:00
parent f34943c9cc
commit 7c05168e4e
12 changed files with 109 additions and 21 deletions

View File

@@ -442,8 +442,19 @@ export const routes = async (app: HonoAppType) => {
) => {
stream.writeSSE("taskChanged", {
aliveTasks: event.aliveTasks,
changed: event.changed,
changed: {
status: event.changed.status,
sessionId: event.changed.sessionId,
projectId: event.changed.projectId,
},
});
if (event.changed.sessionId !== undefined) {
stream.writeSSE("sessionChanged", {
projectId: event.changed.projectId,
sessionId: event.changed.sessionId,
});
}
};
eventBus.on("sessionListChanged", onSessionListChanged);

View File

@@ -1,6 +1,9 @@
import { resolve } from "node:path";
import { ulid } from "ulid";
import type { Config } from "../../config/config";
import { eventBus } from "../events/EventBus";
import { parseCommandXml } from "../parseCommandXml";
import { decodeProjectId } from "../project/id";
import { predictSessionsDatabase } from "../session/PredictSessionsDatabase";
import { ClaudeCodeExecutor } from "./ClaudeCodeExecutor";
import { createMessageGenerator } from "./createMessageGenerator";
@@ -270,7 +273,10 @@ class ClaudeCodeTaskController {
// because it takes time for the Claude Code file to be updated, simulate the message
predictSessionsDatabase.createPredictSession({
id: message.session_id,
jsonlFilePath: message.session_id,
jsonlFilePath: resolve(
decodeProjectId(currentSession.projectId),
`${message.session_id}.jsonl`,
),
conversations: [
{
type: "user",
@@ -289,11 +295,15 @@ class ClaudeCodeTaskController {
},
],
meta: {
firstCommand: null,
firstCommand: parseCommandXml(userMessage),
messageCount: 0,
},
lastModifiedAt: new Date(),
});
eventBus.emit("sessionListChanged", {
projectId: task.projectId,
});
}
if (!resolved) {
@@ -421,12 +431,10 @@ class ClaudeCodeTaskController {
Object.assign(target, task);
}
if (task.status === "paused" || task.status === "running") {
eventBus.emit("taskChanged", {
aliveTasks: this.aliveTasks,
changed: task,
});
}
eventBus.emit("taskChanged", {
aliveTasks: this.aliveTasks,
changed: task,
});
}
}

View File

@@ -1,5 +1,6 @@
import type {
AliveClaudeCodeTask,
ClaudeCodeTask,
PermissionRequest,
} from "../claude-code/types";
@@ -18,7 +19,7 @@ export type InternalEventDeclaration = {
taskChanged: {
aliveTasks: AliveClaudeCodeTask[];
changed: AliveClaudeCodeTask;
changed: ClaudeCodeTask;
};
permissionRequested: {

View File

@@ -0,0 +1,33 @@
import { resolve } from "node:path";
import {
decodeProjectId,
encodeProjectId,
encodeProjectIdFromSessionFilePath,
} from "./id";
const sampleProjectPath =
"/path/to/claude-code-project-dir/projects/sample-project";
const sampleProjectId =
"L3BhdGgvdG8vY2xhdWRlLWNvZGUtcHJvamVjdC1kaXIvcHJvamVjdHMvc2FtcGxlLXByb2plY3Q";
describe("encodeProjectId", () => {
it("should encode project id from project path", () => {
expect(encodeProjectId(sampleProjectPath)).toBe(sampleProjectId);
});
});
describe("decodeProjectId", () => {
it("should decode project absolute path from project id", () => {
expect(decodeProjectId(sampleProjectId)).toBe(sampleProjectPath);
});
});
describe("encodeProjectIdFromSessionFilePath", () => {
it("should encode project id from session file path", () => {
expect(
encodeProjectIdFromSessionFilePath(
resolve(sampleProjectPath, "sample-session-id.jsonl"),
),
).toBe(sampleProjectId);
});
});

View File

@@ -7,8 +7,12 @@ import type { Session, SessionDetail } from "../types";
class PredictSessionsDatabase {
private storage = new Map<string, SessionDetail>();
private get allPredictSessions() {
return Array.from(this.storage.values());
}
public getPredictSessions(projectId: string): Session[] {
return Array.from(this.storage.values()).filter(
return this.allPredictSessions.filter(
({ jsonlFilePath }) =>
encodeProjectIdFromSessionFilePath(jsonlFilePath) === projectId,
);

View File

@@ -19,7 +19,8 @@ export class SessionRepository {
if (!existsSync(sessionPath)) {
const predictSession =
predictSessionsDatabase.getPredictSession(sessionId);
if (predictSession) {
if (predictSession !== null) {
return {
session: predictSession,
};

View File

@@ -0,0 +1,26 @@
import { resolve } from "node:path";
import { decodeSessionId, encodeSessionId } from "./id";
const sampleProjectId =
"L3BhdGgvdG8vY2xhdWRlLWNvZGUtcHJvamVjdC1kaXIvcHJvamVjdHMvc2FtcGxlLXByb2plY3Q";
const sampleProjectPath =
"/path/to/claude-code-project-dir/projects/sample-project";
const sampleSessionId = "1af7fc5e-8455-4414-9ccd-011d40f70b2a";
const sampleSessionFilePath = resolve(
sampleProjectPath,
`${sampleSessionId}.jsonl`,
);
describe("encodeSessionId", () => {
it("should encode session id from jsonl file path", () => {
expect(encodeSessionId(sampleSessionFilePath)).toBe(sampleSessionId);
});
});
describe("decodeSessionId", () => {
it("should decode session file absolute path from project id and session id", () => {
expect(decodeSessionId(sampleProjectId, sampleSessionId)).toBe(
sampleSessionFilePath,
);
});
});