Skip to content

Commit 0da20f2

Browse files
committed
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
1 parent 2f1ede0 commit 0da20f2

File tree

3 files changed

+52
-7
lines changed

3 files changed

+52
-7
lines changed

src/tools/session-manager/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { getClaudeConfigDir } from "../../shared"
55
export const OPENCODE_STORAGE = getOpenCodeStorageDir()
66
export const MESSAGE_STORAGE = join(OPENCODE_STORAGE, "message")
77
export const PART_STORAGE = join(OPENCODE_STORAGE, "part")
8+
export const SESSION_STORAGE = join(OPENCODE_STORAGE, "session")
89
export const TODO_DIR = join(getClaudeConfigDir(), "todos")
910
export const TRANSCRIPT_DIR = join(getClaudeConfigDir(), "transcripts")
1011
export const SESSION_LIST_DESCRIPTION = `List all OpenCode sessions with optional filtering.

src/tools/session-manager/storage.ts

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,49 @@
11
import { existsSync, readdirSync } from "node:fs"
22
import { readdir, readFile } from "node:fs/promises"
33
import { join } from "node:path"
4-
import { MESSAGE_STORAGE, PART_STORAGE, TODO_DIR, TRANSCRIPT_DIR } from "./constants"
5-
import type { SessionMessage, SessionInfo, TodoItem } from "./types"
4+
import { MESSAGE_STORAGE, PART_STORAGE, SESSION_STORAGE, TODO_DIR, TRANSCRIPT_DIR } from "./constants"
5+
import type { SessionMessage, SessionInfo, TodoItem, SessionMetadata } from "./types"
6+
7+
export interface GetMainSessionsOptions {
8+
directory?: string
9+
}
10+
11+
export async function getMainSessions(options: GetMainSessionsOptions): Promise<SessionMetadata[]> {
12+
if (!existsSync(SESSION_STORAGE)) return []
13+
14+
const sessions: SessionMetadata[] = []
15+
16+
try {
17+
const projectDirs = await readdir(SESSION_STORAGE, { withFileTypes: true })
18+
for (const projectDir of projectDirs) {
19+
if (!projectDir.isDirectory()) continue
20+
21+
const projectPath = join(SESSION_STORAGE, projectDir.name)
22+
const sessionFiles = await readdir(projectPath)
23+
24+
for (const file of sessionFiles) {
25+
if (!file.endsWith(".json")) continue
26+
27+
try {
28+
const content = await readFile(join(projectPath, file), "utf-8")
29+
const meta = JSON.parse(content) as SessionMetadata
30+
31+
if (meta.parentID) continue
32+
33+
if (options.directory && meta.directory !== options.directory) continue
34+
35+
sessions.push(meta)
36+
} catch {
37+
continue
38+
}
39+
}
40+
}
41+
} catch {
42+
return []
43+
}
44+
45+
return sessions.sort((a, b) => b.time.updated - a.time.updated)
46+
}
647

748
export async function getAllSessions(): Promise<string[]> {
849
if (!existsSync(MESSAGE_STORAGE)) return []

src/tools/session-manager/tools.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
SESSION_SEARCH_DESCRIPTION,
66
SESSION_INFO_DESCRIPTION,
77
} from "./constants"
8-
import { getAllSessions, getSessionInfo, readSessionMessages, readSessionTodos, sessionExists } from "./storage"
8+
import { getAllSessions, getMainSessions, getSessionInfo, readSessionMessages, readSessionTodos, sessionExists } from "./storage"
99
import {
1010
filterSessionsByDate,
1111
formatSessionInfo,
@@ -32,20 +32,23 @@ export const session_list: ToolDefinition = tool({
3232
limit: tool.schema.number().optional().describe("Maximum number of sessions to return"),
3333
from_date: tool.schema.string().optional().describe("Filter sessions from this date (ISO 8601 format)"),
3434
to_date: tool.schema.string().optional().describe("Filter sessions until this date (ISO 8601 format)"),
35+
project_path: tool.schema.string().optional().describe("Filter sessions by project path (default: current working directory)"),
3536
},
3637
execute: async (args: SessionListArgs, _context) => {
3738
try {
38-
let sessions = await getAllSessions()
39+
const directory = args.project_path ?? process.cwd()
40+
let sessions = await getMainSessions({ directory })
41+
let sessionIDs = sessions.map((s) => s.id)
3942

4043
if (args.from_date || args.to_date) {
41-
sessions = await filterSessionsByDate(sessions, args.from_date, args.to_date)
44+
sessionIDs = await filterSessionsByDate(sessionIDs, args.from_date, args.to_date)
4245
}
4346

4447
if (args.limit && args.limit > 0) {
45-
sessions = sessions.slice(0, args.limit)
48+
sessionIDs = sessionIDs.slice(0, args.limit)
4649
}
4750

48-
return await formatSessionList(sessions)
51+
return await formatSessionList(sessionIDs)
4952
} catch (e) {
5053
return `Error: ${e instanceof Error ? e.message : String(e)}`
5154
}

0 commit comments

Comments
 (0)