refactor: move directories

This commit is contained in:
d-kimsuon
2025-10-17 20:18:28 +09:00
parent a5d81568bb
commit c745824dbe
78 changed files with 189 additions and 305 deletions

View File

@@ -1,6 +1,6 @@
import { homedir } from "node:os"; import { homedir } from "node:os";
import { resolve } from "node:path"; import { resolve } from "node:path";
import { encodeProjectId } from "../src/server/service/project/id"; import { encodeProjectId } from "../src/server/core/project/functions/id";
// biome-ignore lint/complexity/useLiteralKeys: env var // biome-ignore lint/complexity/useLiteralKeys: env var
export const globalClaudeDirectoryPath = process.env["GLOBAL_CLAUDE_DIR"] export const globalClaudeDirectoryPath = process.env["GLOBAL_CLAUDE_DIR"]

View File

@@ -1,19 +1,19 @@
import { NodeContext } from "@effect/platform-node"; import { NodeContext } from "@effect/platform-node";
import { Effect } from "effect"; import { Effect } from "effect";
import { handle } from "hono/vercel"; import { handle } from "hono/vercel";
import { ClaudeCodeLifeCycleService } from "../../../server/core/claude-code/services/ClaudeCodeLifeCycleService";
import { ClaudeCodePermissionService } from "../../../server/core/claude-code/services/ClaudeCodePermissionService";
import { ClaudeCodeSessionProcessService } from "../../../server/core/claude-code/services/ClaudeCodeSessionProcessService";
import { EventBus } from "../../../server/core/events/services/EventBus";
import { FileWatcherService } from "../../../server/core/events/services/fileWatcher";
import { ProjectRepository } from "../../../server/core/project/infrastructure/ProjectRepository";
import { ProjectMetaService } from "../../../server/core/project/services/ProjectMetaService";
import { SessionRepository } from "../../../server/core/session/infrastructure/SessionRepository";
import { VirtualConversationDatabase } from "../../../server/core/session/infrastructure/VirtualConversationDatabase";
import { SessionMetaService } from "../../../server/core/session/services/SessionMetaService";
import { honoApp } from "../../../server/hono/app"; import { honoApp } from "../../../server/hono/app";
import { InitializeService } from "../../../server/hono/initialize"; import { InitializeService } from "../../../server/hono/initialize";
import { routes } from "../../../server/hono/route"; import { routes } from "../../../server/hono/route";
import { ClaudeCodeLifeCycleService } from "../../../server/service/claude-code/ClaudeCodeLifeCycleService";
import { ClaudeCodePermissionService } from "../../../server/service/claude-code/ClaudeCodePermissionService";
import { ClaudeCodeSessionProcessService } from "../../../server/service/claude-code/ClaudeCodeSessionProcessService";
import { EventBus } from "../../../server/service/events/EventBus";
import { FileWatcherService } from "../../../server/service/events/fileWatcher";
import { ProjectMetaService } from "../../../server/service/project/ProjectMetaService";
import { ProjectRepository } from "../../../server/service/project/ProjectRepository";
import { SessionMetaService } from "../../../server/service/session/SessionMetaService";
import { SessionRepository } from "../../../server/service/session/SessionRepository";
import { VirtualConversationDatabase } from "../../../server/service/session/VirtualConversationDatabase";
const program = routes(honoApp); const program = routes(honoApp);

View File

@@ -6,7 +6,7 @@ import {
import { useCallback } from "react"; import { useCallback } from "react";
import { honoClient } from "../../lib/api/client"; import { honoClient } from "../../lib/api/client";
import { configQuery } from "../../lib/api/queries"; import { configQuery } from "../../lib/api/queries";
import type { Config } from "../../server/config/config"; import type { Config } from "../../server/lib/config/config";
export const useConfig = () => { export const useConfig = () => {
const queryClient = useQueryClient(); const queryClient = useQueryClient();

View File

@@ -1,4 +1,4 @@
import type { ParsedCommand } from "../../../../server/service/parseCommandXml"; import type { ParsedCommand } from "../../../../server/core/claude-code/functions/parseCommandXml";
export const firstCommandToTitle = (firstCommand: ParsedCommand) => { export const firstCommandToTitle = (firstCommand: ParsedCommand) => {
switch (firstCommand.kind) { switch (firstCommand.kind) {

View File

@@ -10,7 +10,7 @@ import {
} from "@/components/ui/collapsible"; } from "@/components/ui/collapsible";
import type { Conversation } from "@/lib/conversation-schema"; import type { Conversation } from "@/lib/conversation-schema";
import type { ToolResultContent } from "@/lib/conversation-schema/content/ToolResultContentSchema"; import type { ToolResultContent } from "@/lib/conversation-schema/content/ToolResultContentSchema";
import type { ErrorJsonl } from "../../../../../../../server/service/types"; import type { ErrorJsonl } from "../../../../../../../server/core/types";
import { useSidechain } from "../../hooks/useSidechain"; import { useSidechain } from "../../hooks/useSidechain";
import { ConversationItem } from "./ConversationItem"; import { ConversationItem } from "./ConversationItem";

View File

@@ -3,7 +3,7 @@ import type { FC } from "react";
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { parseCommandXml } from "../../../../../../../server/service/parseCommandXml"; import { parseCommandXml } from "../../../../../../../server/core/claude-code/functions/parseCommandXml";
import { MarkdownContent } from "../../../../../../components/MarkdownContent"; import { MarkdownContent } from "../../../../../../components/MarkdownContent";
export const UserTextContent: FC<{ text: string; id?: string }> = ({ export const UserTextContent: FC<{ text: string; id?: string }> = ({

View File

@@ -7,7 +7,7 @@ import type { FC } from "react";
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import type { Session } from "../../../../../../../server/service/types"; import type { Session } from "../../../../../../../server/core/types";
import { NewChatModal } from "../../../../components/newChat/NewChatModal"; import { NewChatModal } from "../../../../components/newChat/NewChatModal";
import { firstCommandToTitle } from "../../../../services/firstCommandToTitle"; import { firstCommandToTitle } from "../../../../services/firstCommandToTitle";
import { sessionProcessesAtom } from "../../store/sessionProcessesAtom"; import { sessionProcessesAtom } from "../../store/sessionProcessesAtom";

View File

@@ -1,5 +1,5 @@
import type { DirectoryListingResult } from "../../server/service/directory-browser/getDirectoryListing"; import type { DirectoryListingResult } from "../../server/core/directory-browser/functions/getDirectoryListing";
import type { FileCompletionResult } from "../../server/service/file-completion/getFileCompletion"; import type { FileCompletionResult } from "../../server/core/file-completion/functions/getFileCompletion";
import { honoClient } from "./client"; import { honoClient } from "./client";
export const projectListQuery = { export const projectListQuery = {

View File

@@ -7,7 +7,7 @@ describe("computeClaudeProjectFilePath", () => {
beforeEach(async () => { beforeEach(async () => {
vi.resetModules(); vi.resetModules();
vi.doMock("../../lib/env", () => ({ vi.doMock("../../../lib/env", () => ({
env: { env: {
get: (key: string) => { get: (key: string) => {
if (key === "GLOBAL_CLAUDE_DIR") { if (key === "GLOBAL_CLAUDE_DIR") {

View File

@@ -1,5 +1,5 @@
import path from "node:path"; import path from "node:path";
import { claudeProjectsDirPath } from "../paths"; import { claudeProjectsDirPath } from "../../../lib/config/paths";
export function computeClaudeProjectFilePath(projectPath: string): string { export function computeClaudeProjectFilePath(projectPath: string): string {
return path.join( return path.join(

View File

@@ -1,5 +1,5 @@
import type { SDKMessage, SDKUserMessage } from "@anthropic-ai/claude-code"; import type { SDKMessage, SDKUserMessage } from "@anthropic-ai/claude-code";
import { controllablePromise } from "../../../lib/controllablePromise"; import { controllablePromise } from "../../../../lib/controllablePromise";
export type OnMessage = (message: SDKMessage) => void | Promise<void>; export type OnMessage = (message: SDKMessage) => void | Promise<void>;

View File

@@ -1,6 +1,6 @@
import { describe, expect, it } from "vitest"; import { describe, expect, it } from "vitest";
import type { ErrorJsonl } from "../../types";
import { parseJsonl } from "./parseJsonl"; import { parseJsonl } from "./parseJsonl";
import type { ErrorJsonl } from "./types";
describe("parseJsonl", () => { describe("parseJsonl", () => {
describe("正常系: 有効なJSONLをパースできる", () => { describe("正常系: 有効なJSONLをパースできる", () => {

View File

@@ -1,5 +1,5 @@
import { ConversationSchema } from "../../lib/conversation-schema"; import { ConversationSchema } from "../../../../lib/conversation-schema";
import type { ErrorJsonl } from "./types"; import type { ErrorJsonl } from "../../types";
export const parseJsonl = (content: string) => { export const parseJsonl = (content: string) => {
const lines = content const lines = content

View File

@@ -1,7 +1,7 @@
import { Effect } from "effect"; import { Effect } from "effect";
import type { UserEntry } from "../../../../lib/conversation-schema/entry/UserEntrySchema"; import type { UserEntry } from "../../../../lib/conversation-schema/entry/UserEntrySchema";
import * as ClaudeCode from "../ClaudeCode"; import type { InitMessageContext } from "../types";
import type { InitMessageContext } from "../createMessageGenerator"; import * as ClaudeCode from "./ClaudeCode";
import type * as CCTask from "./ClaudeCodeTask"; import type * as CCTask from "./ClaudeCodeTask";
import * as ClaudeCodeVersion from "./ClaudeCodeVersion"; import * as ClaudeCodeVersion from "./ClaudeCodeVersion";

View File

@@ -1,8 +1,8 @@
import { query as originalQuery } from "@anthropic-ai/claude-code"; import { query as originalQuery } from "@anthropic-ai/claude-code";
import { Command, Path } from "@effect/platform"; import { Command, Path } from "@effect/platform";
import { Effect } from "effect"; import { Effect } from "effect";
import { env } from "../../lib/env"; import { env } from "../../../lib/env";
import * as ClaudeCodeVersion from "./models/ClaudeCodeVersion"; import * as ClaudeCodeVersion from "./ClaudeCodeVersion";
type CCQuery = typeof originalQuery; type CCQuery = typeof originalQuery;
type CCQueryPrompt = Parameters<CCQuery>[0]["prompt"]; type CCQueryPrompt = Parameters<CCQuery>[0]["prompt"];

View File

@@ -3,18 +3,18 @@ import type { FileSystem, Path } from "@effect/platform";
import type { CommandExecutor } from "@effect/platform/CommandExecutor"; import type { CommandExecutor } from "@effect/platform/CommandExecutor";
import { Context, Effect, Layer, Runtime } from "effect"; import { Context, Effect, Layer, Runtime } from "effect";
import { ulid } from "ulid"; import { ulid } from "ulid";
import { controllablePromise } from "../../../lib/controllablePromise"; import { controllablePromise } from "../../../../lib/controllablePromise";
import type { Config } from "../../config/config"; import type { Config } from "../../../lib/config/config";
import type { InferEffect } from "../../lib/effect/types"; import type { InferEffect } from "../../../lib/effect/types";
import { EventBus } from "../events/EventBus"; import { EventBus } from "../../events/services/EventBus";
import type { SessionMetaService } from "../session/SessionMetaService"; import { SessionRepository } from "../../session/infrastructure/SessionRepository";
import { SessionRepository } from "../session/SessionRepository"; import { VirtualConversationDatabase } from "../../session/infrastructure/VirtualConversationDatabase";
import { VirtualConversationDatabase } from "../session/VirtualConversationDatabase"; import type { SessionMetaService } from "../../session/services/SessionMetaService";
import * as ClaudeCode from "./ClaudeCode"; import { createMessageGenerator } from "../functions/createMessageGenerator";
import * as CCSessionProcess from "../models/CCSessionProcess";
import * as ClaudeCode from "../models/ClaudeCode";
import { ClaudeCodePermissionService } from "./ClaudeCodePermissionService"; import { ClaudeCodePermissionService } from "./ClaudeCodePermissionService";
import { ClaudeCodeSessionProcessService } from "./ClaudeCodeSessionProcessService"; import { ClaudeCodeSessionProcessService } from "./ClaudeCodeSessionProcessService";
import { createMessageGenerator } from "./MessageGenerator";
import * as CCSessionProcess from "./models/CCSessionProcess";
export type MessageGenerator = () => AsyncGenerator< export type MessageGenerator = () => AsyncGenerator<
SDKUserMessage, SDKUserMessage,

View File

@@ -4,11 +4,11 @@ import { ulid } from "ulid";
import type { import type {
PermissionRequest, PermissionRequest,
PermissionResponse, PermissionResponse,
} from "../../../types/permissions"; } from "../../../../types/permissions";
import type { Config } from "../../config/config"; import type { Config } from "../../../lib/config/config";
import type { InferEffect } from "../../lib/effect/types"; import type { InferEffect } from "../../../lib/effect/types";
import { EventBus } from "../events/EventBus"; import { EventBus } from "../../events/services/EventBus";
import * as ClaudeCode from "./ClaudeCode"; import * as ClaudeCode from "../models/ClaudeCode";
const LayerImpl = Effect.gen(function* () { const LayerImpl = Effect.gen(function* () {
const pendingPermissionRequestsRef = yield* Ref.make< const pendingPermissionRequestsRef = yield* Ref.make<

View File

@@ -4,12 +4,12 @@ import type {
} from "@anthropic-ai/claude-code"; } from "@anthropic-ai/claude-code";
import { Effect, Layer } from "effect"; import { Effect, Layer } from "effect";
import { describe, expect, it } from "vitest"; import { describe, expect, it } from "vitest";
import { EventBus } from "../events/EventBus"; import { EventBus } from "../../events/services/EventBus";
import type { InternalEventDeclaration } from "../events/InternalEventDeclaration"; import type { InternalEventDeclaration } from "../../events/types/InternalEventDeclaration";
import type * as CCSessionProcess from "../models/CCSessionProcess";
import type * as CCTask from "../models/ClaudeCodeTask";
import type { InitMessageContext } from "../types";
import { ClaudeCodeSessionProcessService } from "./ClaudeCodeSessionProcessService"; import { ClaudeCodeSessionProcessService } from "./ClaudeCodeSessionProcessService";
import type { InitMessageContext } from "./createMessageGenerator";
import type * as CCSessionProcess from "./models/CCSessionProcess";
import type * as CCTask from "./models/ClaudeCodeTask";
// Helper function to create mock session process definition // Helper function to create mock session process definition
const createMockSessionProcessDef = ( const createMockSessionProcessDef = (

View File

@@ -1,10 +1,10 @@
import type { SDKResultMessage } from "@anthropic-ai/claude-code"; import type { SDKResultMessage } from "@anthropic-ai/claude-code";
import { Context, Data, Effect, Layer, Ref } from "effect"; import { Context, Data, Effect, Layer, Ref } from "effect";
import type { InferEffect } from "../../lib/effect/types"; import type { InferEffect } from "../../../lib/effect/types";
import { EventBus } from "../events/EventBus"; import { EventBus } from "../../events/services/EventBus";
import type { InitMessageContext } from "./createMessageGenerator"; import * as CCSessionProcess from "../models/CCSessionProcess";
import * as CCSessionProcess from "./models/CCSessionProcess"; import type * as CCTask from "../models/ClaudeCodeTask";
import type * as CCTask from "./models/ClaudeCodeTask"; import type { InitMessageContext } from "../types";
class SessionProcessNotFoundError extends Data.TaggedError( class SessionProcessNotFoundError extends Data.TaggedError(
"SessionProcessNotFoundError", "SessionProcessNotFoundError",

View File

@@ -0,0 +1,5 @@
import type { SDKSystemMessage } from "@anthropic-ai/claude-code";
export type InitMessageContext = {
initMessage: SDKSystemMessage;
};

View File

@@ -1,7 +1,7 @@
import { Effect } from "effect"; import { Effect } from "effect";
import type { SSEStreamingApi } from "hono/streaming"; import type { SSEStreamingApi } from "hono/streaming";
import { describe, expect, it, vi } from "vitest"; import { describe, expect, it, vi } from "vitest";
import type { PermissionRequest } from "../../../types/permissions"; import type { PermissionRequest } from "../../../../types/permissions";
import { TypeSafeSSE } from "./typeSafeSSE"; import { TypeSafeSSE } from "./typeSafeSSE";
describe("typeSafeSSE", () => { describe("typeSafeSSE", () => {
@@ -153,7 +153,7 @@ describe("typeSafeSSE", () => {
const program = Effect.gen(function* () { const program = Effect.gen(function* () {
const typeSafeSSE = yield* TypeSafeSSE; const typeSafeSSE = yield* TypeSafeSSE;
yield* typeSafeSSE.writeSSE("permission_requested", { yield* typeSafeSSE.writeSSE("permissionRequested", {
permissionRequest: mockPermissionRequest, permissionRequest: mockPermissionRequest,
}); });
@@ -170,10 +170,10 @@ describe("typeSafeSSE", () => {
if (!item) { if (!item) {
throw new Error("item is undefined"); throw new Error("item is undefined");
} }
expect(item.event).toBe("permission_requested"); expect(item.event).toBe("permissionRequested");
const data = JSON.parse(item.data); const data = JSON.parse(item.data);
expect(data.kind).toBe("permission_requested"); expect(data.kind).toBe("permissionRequested");
expect(data.permissionRequest.id).toBe("permission-1"); expect(data.permissionRequest.id).toBe("permission-1");
expect(data.timestamp).toBeDefined(); expect(data.timestamp).toBeDefined();
}); });

View File

@@ -1,7 +1,7 @@
import { Context, Effect, Layer } from "effect"; import { Context, Effect, Layer } from "effect";
import type { SSEStreamingApi } from "hono/streaming"; import type { SSEStreamingApi } from "hono/streaming";
import { ulid } from "ulid"; import { ulid } from "ulid";
import type { SSEEventDeclaration } from "../../../types/sse"; import type { SSEEventDeclaration } from "../../../../types/sse";
interface TypeSafeSSEService { interface TypeSafeSSEService {
readonly writeSSE: <EventName extends keyof SSEEventDeclaration>( readonly writeSSE: <EventName extends keyof SSEEventDeclaration>(

View File

@@ -1,10 +1,10 @@
import { Effect } from "effect"; import { Effect } from "effect";
import { describe, expect, it } from "vitest"; import { describe, expect, it } from "vitest";
import type { PermissionRequest } from "../../../types/permissions"; import type { PermissionRequest } from "../../../../types/permissions";
import type { PublicSessionProcess } from "../../../types/session-process"; import type { PublicSessionProcess } from "../../../../types/session-process";
import type { CCSessionProcessState } from "../claude-code/models/CCSessionProcess"; import type { CCSessionProcessState } from "../../claude-code/models/CCSessionProcess";
import type { InternalEventDeclaration } from "../types/InternalEventDeclaration";
import { EventBus } from "./EventBus"; import { EventBus } from "./EventBus";
import type { InternalEventDeclaration } from "./InternalEventDeclaration";
describe("EventBus", () => { describe("EventBus", () => {
describe("basic event processing", () => { describe("basic event processing", () => {

View File

@@ -1,5 +1,5 @@
import { Context, Effect, Layer } from "effect"; import { Context, Effect, Layer } from "effect";
import type { InternalEventDeclaration } from "./InternalEventDeclaration"; import type { InternalEventDeclaration } from "../types/InternalEventDeclaration";
type Listener<T> = (data: T) => void | Promise<void>; type Listener<T> = (data: T) => void | Promise<void>;

View File

@@ -1,8 +1,8 @@
import { Effect } from "effect"; import { Effect } from "effect";
import { describe, expect, it } from "vitest"; import { describe, expect, it } from "vitest";
import type { InternalEventDeclaration } from "../types/InternalEventDeclaration";
import { EventBus } from "./EventBus"; import { EventBus } from "./EventBus";
import { FileWatcherService } from "./fileWatcher"; import { FileWatcherService } from "./fileWatcher";
import type { InternalEventDeclaration } from "./InternalEventDeclaration";
describe("FileWatcherService", () => { describe("FileWatcherService", () => {
describe("startWatching", () => { describe("startWatching", () => {

View File

@@ -2,8 +2,8 @@ import { type FSWatcher, watch } from "node:fs";
import { join } from "node:path"; import { join } from "node:path";
import { Context, Effect, Layer, Ref } from "effect"; import { Context, Effect, Layer, Ref } from "effect";
import z from "zod"; import z from "zod";
import { claudeProjectsDirPath } from "../paths"; import { claudeProjectsDirPath } from "../../../lib/config/paths";
import { encodeProjectIdFromSessionFilePath } from "../project/id"; import { encodeProjectIdFromSessionFilePath } from "../../project/functions/id";
import { EventBus } from "./EventBus"; import { EventBus } from "./EventBus";
const fileRegExp = /(?<projectId>.*?)\/(?<sessionId>.*?)\.jsonl/; const fileRegExp = /(?<projectId>.*?)\/(?<sessionId>.*?)\.jsonl/;

View File

@@ -1,6 +1,6 @@
import type { PermissionRequest } from "../../../types/permissions"; import type { PermissionRequest } from "../../../../types/permissions";
import type { PublicSessionProcess } from "../../../types/session-process"; import type { PublicSessionProcess } from "../../../../types/session-process";
import type * as CCSessionProcess from "../claude-code/models/CCSessionProcess"; import type * as CCSessionProcess from "../../claude-code/models/CCSessionProcess";
export type InternalEventDeclaration = { export type InternalEventDeclaration = {
// biome-ignore lint/complexity/noBannedTypes: correct type // biome-ignore lint/complexity/noBannedTypes: correct type

View File

@@ -1,5 +1,5 @@
import type { GitBranch, GitResult } from "./types"; import { executeGitCommand, parseLines } from "../functions/utils";
import { executeGitCommand, parseLines } from "./utils"; import type { GitBranch, GitResult } from "../types";
/** /**
* Get all branches (local and remote) in the repository * Get all branches (local and remote) in the repository

View File

@@ -1,5 +1,5 @@
import type { GitCommit, GitResult } from "./types"; import { executeGitCommand, parseLines } from "../functions/utils";
import { executeGitCommand, parseLines } from "./utils"; import type { GitCommit, GitResult } from "../types";
/** /**
* Get the last 20 commits from the current branch * Get the last 20 commits from the current branch

View File

@@ -4,6 +4,11 @@ import parseGitDiff, {
type AnyChunk, type AnyChunk,
type AnyFileChange, type AnyFileChange,
} from "parse-git-diff"; } from "parse-git-diff";
import {
executeGitCommand,
parseLines,
stripAnsiColors,
} from "../functions/utils";
import type { import type {
GitComparisonResult, GitComparisonResult,
GitDiff, GitDiff,
@@ -11,8 +16,7 @@ import type {
GitDiffHunk, GitDiffHunk,
GitDiffLine, GitDiffLine,
GitResult, GitResult,
} from "./types"; } from "../types";
import { executeGitCommand, parseLines, stripAnsiColors } from "./utils";
/** /**
* Convert parse-git-diff file change to GitDiffFile * Convert parse-git-diff file change to GitDiffFile

View File

@@ -1,10 +1,10 @@
import type { GitDiffFile, GitResult, GitStatus } from "./types";
import { import {
executeGitCommand, executeGitCommand,
getFileStatus, getFileStatus,
parseLines, parseLines,
parseStatusLine, parseStatusLine,
} from "./utils"; } from "../functions/utils";
import type { GitDiffFile, GitResult, GitStatus } from "../types";
/** /**
* Get git status information including staged, unstaged, and untracked files * Get git status information including staged, unstaged, and untracked files

View File

@@ -3,7 +3,7 @@ import { existsSync } from "node:fs";
import { resolve } from "node:path"; import { resolve } from "node:path";
import { promisify } from "node:util"; import { promisify } from "node:util";
import type { GitError, GitResult } from "./types"; import type { GitError, GitResult } from "../types";
const execFileAsync = promisify(execFile); const execFileAsync = promisify(execFile);

View File

@@ -1,5 +1,5 @@
import { execSync } from "node:child_process"; import { execSync } from "node:child_process";
import { decodeProjectId } from "../project/id"; import { decodeProjectId } from "../../project/functions/id";
export interface McpServer { export interface McpServer {
name: string; name: string;

View File

@@ -1,9 +1,9 @@
import { FileSystem, Path } from "@effect/platform"; import { FileSystem, Path } from "@effect/platform";
import { SystemError } from "@effect/platform/Error"; import { SystemError } from "@effect/platform/Error";
import { Effect, Layer, Option } from "effect"; import { Effect, Layer, Option } from "effect";
import { PersistentService } from "../../lib/storage/FileCacheStorage/PersistantService"; import { PersistentService } from "../../../lib/storage/FileCacheStorage/PersistentService";
import type { ProjectMeta } from "../types"; import type { ProjectMeta } from "../../types";
import { ProjectMetaService } from "./ProjectMetaService"; import { ProjectMetaService } from "../services/ProjectMetaService";
import { ProjectRepository } from "./ProjectRepository"; import { ProjectRepository } from "./ProjectRepository";
/** /**

View File

@@ -1,11 +1,11 @@
import { resolve } from "node:path"; import { resolve } from "node:path";
import { FileSystem } from "@effect/platform"; import { FileSystem } from "@effect/platform";
import { Context, Effect, Layer, Option } from "effect"; import { Context, Effect, Layer, Option } from "effect";
import type { InferEffect } from "../../lib/effect/types"; import { claudeProjectsDirPath } from "../../../lib/config/paths";
import { claudeProjectsDirPath } from "../paths"; import type { InferEffect } from "../../../lib/effect/types";
import type { Project } from "../types"; import type { Project } from "../../types";
import { decodeProjectId, encodeProjectId } from "./id"; import { decodeProjectId, encodeProjectId } from "../functions/id";
import { ProjectMetaService } from "./ProjectMetaService"; import { ProjectMetaService } from "../services/ProjectMetaService";
const LayerImpl = Effect.gen(function* () { const LayerImpl = Effect.gen(function* () {
const fs = yield* FileSystem.FileSystem; const fs = yield* FileSystem.FileSystem;

View File

@@ -0,0 +1,7 @@
import { z } from "zod";
export const projectMetaSchema = z.object({
projectName: z.string().nullable(),
projectPath: z.string().nullable(),
sessionCount: z.number(),
});

View File

@@ -1,7 +1,7 @@
import { FileSystem, Path } from "@effect/platform"; import { FileSystem, Path } from "@effect/platform";
import { Effect, Layer, Option } from "effect"; import { Effect, Layer, Option } from "effect";
import { PersistentService } from "../../lib/storage/FileCacheStorage/PersistantService"; import { PersistentService } from "../../../lib/storage/FileCacheStorage/PersistentService";
import { ProjectMetaService } from "./ProjectMetaService"; import { ProjectMetaService } from "../services/ProjectMetaService";
/** /**
* Helper function to create a FileSystem mock layer * Helper function to create a FileSystem mock layer

View File

@@ -5,11 +5,11 @@ import { z } from "zod";
import { import {
FileCacheStorage, FileCacheStorage,
makeFileCacheStorageLayer, makeFileCacheStorageLayer,
} from "../../lib/storage/FileCacheStorage"; } from "../../../lib/storage/FileCacheStorage";
import { PersistentService } from "../../lib/storage/FileCacheStorage/PersistantService"; import { PersistentService } from "../../../lib/storage/FileCacheStorage/PersistentService";
import { parseJsonl } from "../parseJsonl"; import { parseJsonl } from "../../claude-code/functions/parseJsonl";
import type { ProjectMeta } from "../types"; import type { ProjectMeta } from "../../types";
import { decodeProjectId } from "./id"; import { decodeProjectId } from "../functions/id";
const ProjectPathSchema = z.string().nullable(); const ProjectPathSchema = z.string().nullable();

View File

@@ -1,5 +1,5 @@
import { basename, extname, resolve } from "node:path"; import { basename, extname, resolve } from "node:path";
import { decodeProjectId } from "../project/id"; import { decodeProjectId } from "../../project/functions/id";
export const encodeSessionId = (jsonlFilePath: string) => { export const encodeSessionId = (jsonlFilePath: string) => {
return basename(jsonlFilePath, extname(jsonlFilePath)); return basename(jsonlFilePath, extname(jsonlFilePath));

View File

@@ -1,13 +1,13 @@
import { FileSystem, Path } from "@effect/platform"; import { FileSystem, Path } from "@effect/platform";
import { SystemError } from "@effect/platform/Error"; import { SystemError } from "@effect/platform/Error";
import { Effect, Layer, Option } from "effect"; import { Effect, Layer, Option } from "effect";
import type { Conversation } from "../../../lib/conversation-schema"; import type { Conversation } from "../../../../lib/conversation-schema";
import { PersistentService } from "../../lib/storage/FileCacheStorage/PersistantService"; import { PersistentService } from "../../../lib/storage/FileCacheStorage/PersistentService";
import { decodeProjectId } from "../project/id"; import { decodeProjectId } from "../../project/functions/id";
import type { ErrorJsonl, SessionDetail, SessionMeta } from "../types"; import type { ErrorJsonl, SessionDetail, SessionMeta } from "../../types";
import { SessionMetaService } from "./SessionMetaService"; import { SessionRepository } from "../infrastructure/SessionRepository";
import { SessionRepository } from "./SessionRepository"; import { VirtualConversationDatabase } from "../infrastructure/VirtualConversationDatabase";
import { VirtualConversationDatabase } from "./VirtualConversationDatabase"; import { SessionMetaService } from "../services/SessionMetaService";
/** /**
* Helper function to create a FileSystem mock layer * Helper function to create a FileSystem mock layer

View File

@@ -1,13 +1,13 @@
import { resolve } from "node:path"; import { resolve } from "node:path";
import { FileSystem } from "@effect/platform"; import { FileSystem } from "@effect/platform";
import { Context, Effect, Layer, Option } from "effect"; import { Context, Effect, Layer, Option } from "effect";
import { parseCommandXml } from "../parseCommandXml"; import { parseCommandXml } from "../../claude-code/functions/parseCommandXml";
import { parseJsonl } from "../parseJsonl"; import { parseJsonl } from "../../claude-code/functions/parseJsonl";
import { decodeProjectId } from "../project/id"; import { decodeProjectId } from "../../project/functions/id";
import type { Session, SessionDetail } from "../types"; import type { Session, SessionDetail } from "../../types";
import { decodeSessionId, encodeSessionId } from "./id"; import { decodeSessionId, encodeSessionId } from "../functions/id";
import { SessionMetaService } from "./SessionMetaService"; import { VirtualConversationDatabase } from "../infrastructure/VirtualConversationDatabase";
import { VirtualConversationDatabase } from "./VirtualConversationDatabase"; import { SessionMetaService } from "../services/SessionMetaService";
const getSession = (projectId: string, sessionId: string) => const getSession = (projectId: string, sessionId: string) =>
Effect.gen(function* () { Effect.gen(function* () {

View File

@@ -1,6 +1,6 @@
import { Effect } from "effect"; import { Effect } from "effect";
import type { Conversation } from "../../../lib/conversation-schema"; import type { Conversation } from "../../../../lib/conversation-schema";
import type { ErrorJsonl } from "../types"; import type { ErrorJsonl } from "../../types";
import { VirtualConversationDatabase } from "./VirtualConversationDatabase"; import { VirtualConversationDatabase } from "./VirtualConversationDatabase";
describe("VirtualConversationDatabase", () => { describe("VirtualConversationDatabase", () => {

View File

@@ -1,6 +1,6 @@
import { Context, Effect, Layer, Ref } from "effect"; import { Context, Effect, Layer, Ref } from "effect";
import type { Conversation } from "../../../lib/conversation-schema"; import type { Conversation } from "../../../../lib/conversation-schema";
import type { ErrorJsonl } from "../types"; import type { ErrorJsonl } from "../../types";
/** /**
* For interactively experience, handle sessions not already persisted to the filesystem. * For interactively experience, handle sessions not already persisted to the filesystem.

View File

@@ -0,0 +1,7 @@
import { z } from "zod";
import { parsedCommandSchema } from "../claude-code/functions/parseCommandXml";
export const sessionMetaSchema = z.object({
messageCount: z.number(),
firstCommand: parsedCommandSchema.nullable(),
});

View File

@@ -1,7 +1,7 @@
import { FileSystem, Path } from "@effect/platform"; import { FileSystem, Path } from "@effect/platform";
import { Effect, Layer } from "effect"; import { Effect, Layer } from "effect";
import { PersistentService } from "../../lib/storage/FileCacheStorage/PersistantService"; import { PersistentService } from "../../../lib/storage/FileCacheStorage/PersistentService";
import { SessionMetaService } from "./SessionMetaService"; import { SessionMetaService } from "../services/SessionMetaService";
/** /**
* Helper function to create a FileSystem mock layer * Helper function to create a FileSystem mock layer

View File

@@ -3,16 +3,16 @@ import { Context, Effect, Layer, Ref } from "effect";
import { import {
FileCacheStorage, FileCacheStorage,
makeFileCacheStorageLayer, makeFileCacheStorageLayer,
} from "../../lib/storage/FileCacheStorage"; } from "../../../lib/storage/FileCacheStorage";
import { PersistentService } from "../../lib/storage/FileCacheStorage/PersistantService"; import { PersistentService } from "../../../lib/storage/FileCacheStorage/PersistentService";
import { import {
type ParsedCommand, type ParsedCommand,
parseCommandXml, parseCommandXml,
parsedCommandSchema, parsedCommandSchema,
} from "../parseCommandXml"; } from "../../claude-code/functions/parseCommandXml";
import { parseJsonl } from "../parseJsonl"; import { parseJsonl } from "../../claude-code/functions/parseJsonl";
import type { SessionMeta } from "../types"; import type { SessionMeta } from "../../types";
import { decodeSessionId } from "./id"; import { decodeSessionId } from "../functions/id";
const ignoreCommands = [ const ignoreCommands = [
"/clear", "/clear",

View File

@@ -1,6 +1,7 @@
import type { z } from "zod"; import type { z } from "zod";
import type { Conversation } from "../../lib/conversation-schema"; import type { Conversation } from "../../lib/conversation-schema";
import type { projectMetaSchema, sessionMetaSchema } from "./schema"; import type { projectMetaSchema } from "./project/schema";
import type { sessionMetaSchema } from "./session/schema";
export type Project = { export type Project = {
id: string; id: string;

View File

@@ -1,5 +1,5 @@
import { Hono } from "hono"; import { Hono } from "hono";
import type { Config } from "../config/config"; import type { Config } from "../lib/config/config";
export type HonoContext = { export type HonoContext = {
Variables: { Variables: {

View File

@@ -1,13 +1,13 @@
import { Effect, Layer, Ref } from "effect"; import { Effect, Layer, Ref } from "effect";
import { describe, expect, it, vi } from "vitest"; import { describe, expect, it, vi } from "vitest";
import { EventBus } from "../service/events/EventBus"; import { EventBus } from "../core/events/services/EventBus";
import { FileWatcherService } from "../service/events/fileWatcher"; import { FileWatcherService } from "../core/events/services/fileWatcher";
import type { InternalEventDeclaration } from "../service/events/InternalEventDeclaration"; import type { InternalEventDeclaration } from "../core/events/types/InternalEventDeclaration";
import { ProjectMetaService } from "../service/project/ProjectMetaService"; import { ProjectRepository } from "../core/project/infrastructure/ProjectRepository";
import { ProjectRepository } from "../service/project/ProjectRepository"; import { ProjectMetaService } from "../core/project/services/ProjectMetaService";
import { SessionMetaService } from "../service/session/SessionMetaService"; import { SessionRepository } from "../core/session/infrastructure/SessionRepository";
import { SessionRepository } from "../service/session/SessionRepository"; import { VirtualConversationDatabase } from "../core/session/infrastructure/VirtualConversationDatabase";
import { VirtualConversationDatabase } from "../service/session/VirtualConversationDatabase"; import { SessionMetaService } from "../core/session/services/SessionMetaService";
import { InitializeService } from "./initialize"; import { InitializeService } from "./initialize";
describe("InitializeService", () => { describe("InitializeService", () => {

View File

@@ -1,12 +1,12 @@
import { Context, Effect, Layer, Ref, Schedule } from "effect"; import { Context, Effect, Layer, Ref, Schedule } from "effect";
import { EventBus } from "../service/events/EventBus"; import { EventBus } from "../core/events/services/EventBus";
import { FileWatcherService } from "../service/events/fileWatcher"; import { FileWatcherService } from "../core/events/services/fileWatcher";
import type { InternalEventDeclaration } from "../service/events/InternalEventDeclaration"; import type { InternalEventDeclaration } from "../core/events/types/InternalEventDeclaration";
import { ProjectMetaService } from "../service/project/ProjectMetaService"; import { ProjectRepository } from "../core/project/infrastructure/ProjectRepository";
import { ProjectRepository } from "../service/project/ProjectRepository"; import { ProjectMetaService } from "../core/project/services/ProjectMetaService";
import { SessionMetaService } from "../service/session/SessionMetaService"; import { SessionRepository } from "../core/session/infrastructure/SessionRepository";
import { SessionRepository } from "../service/session/SessionRepository"; import { VirtualConversationDatabase } from "../core/session/infrastructure/VirtualConversationDatabase";
import { VirtualConversationDatabase } from "../service/session/VirtualConversationDatabase"; import { SessionMetaService } from "../core/session/services/SessionMetaService";
interface InitializeServiceInterface { interface InitializeServiceInterface {
readonly startInitialization: () => Effect.Effect<void>; readonly startInitialization: () => Effect.Effect<void>;

View File

@@ -1,6 +1,6 @@
import { getCookie, setCookie } from "hono/cookie"; import { getCookie, setCookie } from "hono/cookie";
import { createMiddleware } from "hono/factory"; import { createMiddleware } from "hono/factory";
import { configSchema } from "../../config/config"; import { configSchema } from "../../lib/config/config";
import type { HonoContext } from "../app"; import type { HonoContext } from "../app";
export const configMiddleware = createMiddleware<HonoContext>( export const configMiddleware = createMiddleware<HonoContext>(

View File

@@ -9,28 +9,28 @@ import { streamSSE } from "hono/streaming";
import prexit from "prexit"; import prexit from "prexit";
import { z } from "zod"; import { z } from "zod";
import type { PublicSessionProcess } from "../../types/session-process"; import type { PublicSessionProcess } from "../../types/session-process";
import { configSchema } from "../config/config"; import { computeClaudeProjectFilePath } from "../core/claude-code/functions/computeClaudeProjectFilePath";
import { ClaudeCodeLifeCycleService } from "../core/claude-code/services/ClaudeCodeLifeCycleService";
import { ClaudeCodePermissionService } from "../core/claude-code/services/ClaudeCodePermissionService";
import { getDirectoryListing } from "../core/directory-browser/functions/getDirectoryListing";
import { adaptInternalEventToSSE } from "../core/events/functions/adaptInternalEventToSSE";
import { TypeSafeSSE } from "../core/events/functions/typeSafeSSE";
import { EventBus } from "../core/events/services/EventBus";
import type { InternalEventDeclaration } from "../core/events/types/InternalEventDeclaration";
import { getFileCompletion } from "../core/file-completion/functions/getFileCompletion";
import { getBranches } from "../core/git/functions/getBranches";
import { getCommits } from "../core/git/functions/getCommits";
import { getDiff } from "../core/git/functions/getDiff";
import { getMcpList } from "../core/mcp/functions/getMcpList";
import { encodeProjectId } from "../core/project/functions/id";
import { ProjectRepository } from "../core/project/infrastructure/ProjectRepository";
import type { ProjectMetaService } from "../core/project/services/ProjectMetaService";
import { SessionRepository } from "../core/session/infrastructure/SessionRepository";
import type { VirtualConversationDatabase } from "../core/session/infrastructure/VirtualConversationDatabase";
import type { SessionMetaService } from "../core/session/services/SessionMetaService";
import { configSchema } from "../lib/config/config";
import { claudeCommandsDirPath } from "../lib/config/paths";
import { env } from "../lib/env"; import { env } from "../lib/env";
import { ClaudeCodeLifeCycleService } from "../service/claude-code/ClaudeCodeLifeCycleService";
import { ClaudeCodePermissionService } from "../service/claude-code/ClaudeCodePermissionService";
import { computeClaudeProjectFilePath } from "../service/claude-code/computeClaudeProjectFilePath";
import { getDirectoryListing } from "../service/directory-browser/getDirectoryListing";
import { adaptInternalEventToSSE } from "../service/events/adaptInternalEventToSSE";
import { EventBus } from "../service/events/EventBus";
import type { InternalEventDeclaration } from "../service/events/InternalEventDeclaration";
import { TypeSafeSSE } from "../service/events/typeSafeSSE";
import { getFileCompletion } from "../service/file-completion/getFileCompletion";
import { getBranches } from "../service/git/getBranches";
import { getCommits } from "../service/git/getCommits";
import { getDiff } from "../service/git/getDiff";
import { getMcpList } from "../service/mcp/getMcpList";
import { claudeCommandsDirPath } from "../service/paths";
import { encodeProjectId } from "../service/project/id";
import type { ProjectMetaService } from "../service/project/ProjectMetaService";
import { ProjectRepository } from "../service/project/ProjectRepository";
import type { SessionMetaService } from "../service/session/SessionMetaService";
import { SessionRepository } from "../service/session/SessionRepository";
import type { VirtualConversationDatabase } from "../service/session/VirtualConversationDatabase";
import type { HonoAppType } from "./app"; import type { HonoAppType } from "./app";
import { InitializeService } from "./initialize"; import { InitializeService } from "./initialize";
import { configMiddleware } from "./middleware/config.middleware"; import { configMiddleware } from "./middleware/config.middleware";

View File

@@ -1,6 +1,6 @@
import { homedir } from "node:os"; import { homedir } from "node:os";
import { resolve } from "node:path"; import { resolve } from "node:path";
import { env } from "../lib/env"; import { env } from "../env";
const GLOBAL_CLAUDE_DIR = env.get("GLOBAL_CLAUDE_DIR"); const GLOBAL_CLAUDE_DIR = env.get("GLOBAL_CLAUDE_DIR");

View File

@@ -2,7 +2,7 @@ import { resolve } from "node:path";
import { FileSystem } from "@effect/platform"; import { FileSystem } from "@effect/platform";
import { Context, Effect, Layer } from "effect"; import { Context, Effect, Layer } from "effect";
import { z } from "zod"; import { z } from "zod";
import { claudeCodeViewerCacheDirPath } from "../../../service/paths"; import { claudeCodeViewerCacheDirPath } from "../../config/paths";
const saveSchema = z.array(z.tuple([z.string(), z.unknown()])); const saveSchema = z.array(z.tuple([z.string(), z.unknown()]));

View File

@@ -2,7 +2,7 @@ import { FileSystem } from "@effect/platform";
import { Effect, Layer, Ref } from "effect"; import { Effect, Layer, Ref } from "effect";
import { z } from "zod"; import { z } from "zod";
import { FileCacheStorage, makeFileCacheStorageLayer } from "./index"; import { FileCacheStorage, makeFileCacheStorageLayer } from "./index";
import { PersistentService } from "./PersistantService"; import { PersistentService } from "./PersistentService";
// Schema for testing // Schema for testing
const UserSchema = z.object({ const UserSchema = z.object({

View File

@@ -1,7 +1,7 @@
import type { FileSystem } from "@effect/platform"; import type { FileSystem } from "@effect/platform";
import { Context, Effect, Layer, Ref, Runtime } from "effect"; import { Context, Effect, Layer, Ref, Runtime } from "effect";
import type { z } from "zod"; import type { z } from "zod";
import { PersistentService } from "./PersistantService"; import { PersistentService } from "./PersistentService";
export interface FileCacheStorageService<T> { export interface FileCacheStorageService<T> {
readonly get: (key: string) => Effect.Effect<T | undefined>; readonly get: (key: string) => Effect.Effect<T | undefined>;

View File

@@ -1,95 +0,0 @@
import type {
SDKMessage,
SDKSystemMessage,
SDKUserMessage,
} from "@anthropic-ai/claude-code";
export type OnMessage = (message: SDKMessage) => void | Promise<void>;
export type MessageGenerator = () => AsyncGenerator<
SDKUserMessage,
void,
unknown
>;
const createPromise = <T>() => {
let promiseResolve: ((value: T) => void) | undefined;
let promiseReject: ((reason?: unknown) => void) | undefined;
const promise = new Promise<T>((resolve, reject) => {
promiseResolve = resolve;
promiseReject = reject;
});
if (!promiseResolve || !promiseReject) {
throw new Error("Illegal state: Promise not created");
}
return {
promise,
resolve: promiseResolve,
reject: promiseReject,
} as const;
};
export type InitMessageContext = {
initMessage: SDKSystemMessage;
};
export const createMessageGenerator = (
firstMessage: string,
): {
generateMessages: MessageGenerator;
setNextMessage: (message: string) => void;
setInitMessagePromise: () => void;
resolveInitMessage: (context: InitMessageContext) => void;
awaitInitMessage: (ctx: InitMessageContext) => Promise<void>;
} => {
let sendMessagePromise = createPromise<string>();
let receivedInitMessagePromise = createPromise<InitMessageContext>();
const createMessage = (message: string): SDKUserMessage => {
return {
type: "user",
message: {
role: "user",
content: message,
},
} as SDKUserMessage;
};
async function* generateMessages(): ReturnType<MessageGenerator> {
yield createMessage(firstMessage);
while (true) {
const message = await sendMessagePromise.promise;
sendMessagePromise = createPromise<string>();
yield createMessage(message);
}
}
const setNextMessage = (message: string) => {
sendMessagePromise.resolve(message);
};
const setInitMessagePromise = () => {
receivedInitMessagePromise = createPromise<InitMessageContext>();
};
const resolveInitMessage = (context: InitMessageContext) => {
receivedInitMessagePromise.resolve(context);
};
const awaitInitMessage = async () => {
await receivedInitMessagePromise.promise;
};
return {
generateMessages,
setNextMessage,
setInitMessagePromise,
resolveInitMessage,
awaitInitMessage,
};
};

View File

@@ -1,32 +0,0 @@
// Git service utilities for claude-code-viewer
// Provides comprehensive Git operations including branch management, diff generation, and status checking
export * from "./getBranches";
// Re-export main functions for convenience
export { branchExists, getBranches, getCurrentBranch } from "./getBranches";
export * from "./getCommits";
export { getCommits } from "./getCommits";
export * from "./getDiff";
export { compareBranches, getDiff } from "./getDiff";
export * from "./getStatus";
export {
getStatus,
getUncommittedChanges,
isWorkingDirectoryClean,
} from "./getStatus";
// Types re-export for convenience
export type {
GitBranch,
GitCommit,
GitComparisonResult,
GitDiff,
GitDiffFile,
GitDiffHunk,
GitDiffLine,
GitError,
GitResult,
GitStatus,
} from "./types";
export * from "./types";
export * from "./utils";
export { executeGitCommand, isGitRepository } from "./utils";

View File

@@ -1,13 +0,0 @@
import { z } from "zod";
import { parsedCommandSchema } from "./parseCommandXml";
export const projectMetaSchema = z.object({
projectName: z.string().nullable(),
projectPath: z.string().nullable(),
sessionCount: z.number(),
});
export const sessionMetaSchema = z.object({
messageCount: z.number(),
firstCommand: parsedCommandSchema.nullable(),
});