mirror of
https://github.com/aljazceru/claude-code-viewer.git
synced 2025-12-28 02:34:21 +01:00
fix: fix bug conversation log syncronization
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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: {
|
||||
|
||||
33
src/server/service/project/id.test.ts
Normal file
33
src/server/service/project/id.test.ts
Normal 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);
|
||||
});
|
||||
});
|
||||
@@ -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,
|
||||
);
|
||||
|
||||
@@ -19,7 +19,8 @@ export class SessionRepository {
|
||||
if (!existsSync(sessionPath)) {
|
||||
const predictSession =
|
||||
predictSessionsDatabase.getPredictSession(sessionId);
|
||||
if (predictSession) {
|
||||
|
||||
if (predictSession !== null) {
|
||||
return {
|
||||
session: predictSession,
|
||||
};
|
||||
|
||||
26
src/server/service/session/id.test.ts
Normal file
26
src/server/service/session/id.test.ts
Normal 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,
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user