feat(session-manager): add project path filtering for session listing
- 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
This commit is contained in:
@@ -5,6 +5,7 @@ import { getClaudeConfigDir } from "../../shared"
|
|||||||
export const OPENCODE_STORAGE = getOpenCodeStorageDir()
|
export const OPENCODE_STORAGE = getOpenCodeStorageDir()
|
||||||
export const MESSAGE_STORAGE = join(OPENCODE_STORAGE, "message")
|
export const MESSAGE_STORAGE = join(OPENCODE_STORAGE, "message")
|
||||||
export const PART_STORAGE = join(OPENCODE_STORAGE, "part")
|
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 TODO_DIR = join(getClaudeConfigDir(), "todos")
|
||||||
export const TRANSCRIPT_DIR = join(getClaudeConfigDir(), "transcripts")
|
export const TRANSCRIPT_DIR = join(getClaudeConfigDir(), "transcripts")
|
||||||
export const SESSION_LIST_DESCRIPTION = `List all OpenCode sessions with optional filtering.
|
export const SESSION_LIST_DESCRIPTION = `List all OpenCode sessions with optional filtering.
|
||||||
|
|||||||
@@ -1,8 +1,49 @@
|
|||||||
import { existsSync, readdirSync } from "node:fs"
|
import { existsSync, readdirSync } from "node:fs"
|
||||||
import { readdir, readFile } from "node:fs/promises"
|
import { readdir, readFile } from "node:fs/promises"
|
||||||
import { join } from "node:path"
|
import { join } from "node:path"
|
||||||
import { MESSAGE_STORAGE, PART_STORAGE, TODO_DIR, TRANSCRIPT_DIR } from "./constants"
|
import { MESSAGE_STORAGE, PART_STORAGE, SESSION_STORAGE, TODO_DIR, TRANSCRIPT_DIR } from "./constants"
|
||||||
import type { SessionMessage, SessionInfo, TodoItem } from "./types"
|
import type { SessionMessage, SessionInfo, TodoItem, SessionMetadata } from "./types"
|
||||||
|
|
||||||
|
export interface GetMainSessionsOptions {
|
||||||
|
directory?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getMainSessions(options: GetMainSessionsOptions): Promise<SessionMetadata[]> {
|
||||||
|
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<string[]> {
|
export async function getAllSessions(): Promise<string[]> {
|
||||||
if (!existsSync(MESSAGE_STORAGE)) return []
|
if (!existsSync(MESSAGE_STORAGE)) return []
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import {
|
|||||||
SESSION_SEARCH_DESCRIPTION,
|
SESSION_SEARCH_DESCRIPTION,
|
||||||
SESSION_INFO_DESCRIPTION,
|
SESSION_INFO_DESCRIPTION,
|
||||||
} from "./constants"
|
} from "./constants"
|
||||||
import { getAllSessions, getSessionInfo, readSessionMessages, readSessionTodos, sessionExists } from "./storage"
|
import { getAllSessions, getMainSessions, getSessionInfo, readSessionMessages, readSessionTodos, sessionExists } from "./storage"
|
||||||
import {
|
import {
|
||||||
filterSessionsByDate,
|
filterSessionsByDate,
|
||||||
formatSessionInfo,
|
formatSessionInfo,
|
||||||
@@ -32,20 +32,23 @@ export const session_list: ToolDefinition = tool({
|
|||||||
limit: tool.schema.number().optional().describe("Maximum number of sessions to return"),
|
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)"),
|
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)"),
|
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) => {
|
execute: async (args: SessionListArgs, _context) => {
|
||||||
try {
|
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) {
|
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) {
|
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) {
|
} catch (e) {
|
||||||
return `Error: ${e instanceof Error ? e.message : String(e)}`
|
return `Error: ${e instanceof Error ? e.message : String(e)}`
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user