From 0da20f21b094614cdb541989ec98b38269598e08 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Wed, 31 Dec 2025 12:42:22 +0900 Subject: [PATCH] feat(session-manager): add project path filtering for session listing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add SESSION_STORAGE constant for session metadata directory - Add getMainSessions() function to retrieve main sessions with filtering: - Sorts sessions by updated time (newest first) - Filters out child sessions (with parentID) - Filters sessions by directory path - Update session_list tool to use new getMainSessions(): - Add project_path parameter (default: current working directory) - Maintains existing date range filtering and limit behavior 🤖 Generated with assistance of OhMyOpenCode --- src/tools/session-manager/constants.ts | 1 + src/tools/session-manager/storage.ts | 45 ++++++++++++++++++++++++-- src/tools/session-manager/tools.ts | 13 +++++--- 3 files changed, 52 insertions(+), 7 deletions(-) diff --git a/src/tools/session-manager/constants.ts b/src/tools/session-manager/constants.ts index ff311ef..5f079a1 100644 --- a/src/tools/session-manager/constants.ts +++ b/src/tools/session-manager/constants.ts @@ -5,6 +5,7 @@ import { getClaudeConfigDir } from "../../shared" export const OPENCODE_STORAGE = getOpenCodeStorageDir() export const MESSAGE_STORAGE = join(OPENCODE_STORAGE, "message") export const PART_STORAGE = join(OPENCODE_STORAGE, "part") +export const SESSION_STORAGE = join(OPENCODE_STORAGE, "session") export const TODO_DIR = join(getClaudeConfigDir(), "todos") export const TRANSCRIPT_DIR = join(getClaudeConfigDir(), "transcripts") export const SESSION_LIST_DESCRIPTION = `List all OpenCode sessions with optional filtering. diff --git a/src/tools/session-manager/storage.ts b/src/tools/session-manager/storage.ts index 9f3cb74..8ed93f0 100644 --- a/src/tools/session-manager/storage.ts +++ b/src/tools/session-manager/storage.ts @@ -1,8 +1,49 @@ import { existsSync, readdirSync } from "node:fs" import { readdir, readFile } from "node:fs/promises" import { join } from "node:path" -import { MESSAGE_STORAGE, PART_STORAGE, TODO_DIR, TRANSCRIPT_DIR } from "./constants" -import type { SessionMessage, SessionInfo, TodoItem } from "./types" +import { MESSAGE_STORAGE, PART_STORAGE, SESSION_STORAGE, TODO_DIR, TRANSCRIPT_DIR } from "./constants" +import type { SessionMessage, SessionInfo, TodoItem, SessionMetadata } from "./types" + +export interface GetMainSessionsOptions { + directory?: string +} + +export async function getMainSessions(options: GetMainSessionsOptions): Promise { + if (!existsSync(SESSION_STORAGE)) return [] + + const sessions: SessionMetadata[] = [] + + try { + const projectDirs = await readdir(SESSION_STORAGE, { withFileTypes: true }) + for (const projectDir of projectDirs) { + if (!projectDir.isDirectory()) continue + + const projectPath = join(SESSION_STORAGE, projectDir.name) + const sessionFiles = await readdir(projectPath) + + for (const file of sessionFiles) { + if (!file.endsWith(".json")) continue + + try { + const content = await readFile(join(projectPath, file), "utf-8") + const meta = JSON.parse(content) as SessionMetadata + + if (meta.parentID) continue + + if (options.directory && meta.directory !== options.directory) continue + + sessions.push(meta) + } catch { + continue + } + } + } + } catch { + return [] + } + + return sessions.sort((a, b) => b.time.updated - a.time.updated) +} export async function getAllSessions(): Promise { if (!existsSync(MESSAGE_STORAGE)) return [] diff --git a/src/tools/session-manager/tools.ts b/src/tools/session-manager/tools.ts index 955e60c..1ef917c 100644 --- a/src/tools/session-manager/tools.ts +++ b/src/tools/session-manager/tools.ts @@ -5,7 +5,7 @@ import { SESSION_SEARCH_DESCRIPTION, SESSION_INFO_DESCRIPTION, } from "./constants" -import { getAllSessions, getSessionInfo, readSessionMessages, readSessionTodos, sessionExists } from "./storage" +import { getAllSessions, getMainSessions, getSessionInfo, readSessionMessages, readSessionTodos, sessionExists } from "./storage" import { filterSessionsByDate, formatSessionInfo, @@ -32,20 +32,23 @@ export const session_list: ToolDefinition = tool({ limit: tool.schema.number().optional().describe("Maximum number of sessions to return"), from_date: tool.schema.string().optional().describe("Filter sessions from this date (ISO 8601 format)"), to_date: tool.schema.string().optional().describe("Filter sessions until this date (ISO 8601 format)"), + project_path: tool.schema.string().optional().describe("Filter sessions by project path (default: current working directory)"), }, execute: async (args: SessionListArgs, _context) => { try { - let sessions = await getAllSessions() + const directory = args.project_path ?? process.cwd() + let sessions = await getMainSessions({ directory }) + let sessionIDs = sessions.map((s) => s.id) if (args.from_date || args.to_date) { - sessions = await filterSessionsByDate(sessions, args.from_date, args.to_date) + sessionIDs = await filterSessionsByDate(sessionIDs, args.from_date, args.to_date) } if (args.limit && args.limit > 0) { - sessions = sessions.slice(0, args.limit) + sessionIDs = sessionIDs.slice(0, args.limit) } - return await formatSessionList(sessions) + return await formatSessionList(sessionIDs) } catch (e) { return `Error: ${e instanceof Error ? e.message : String(e)}` }