初始化插件:oc-session-all - 显示所有会话记录,绕过目录过滤

This commit is contained in:
ypshidifu
2026-09-20 23:35:05 +08:00
commit 02f3ded256
3 changed files with 273 additions and 0 deletions
+96
View File
@@ -0,0 +1,96 @@
# oc-session-all
OpenCode 插件:在任意目录下显示所有会话记录,绕过目录过滤限制。
## 功能
- 拦截 `/session` 命令,显示所有项目的会话记录,而不仅仅是当前目录的
- 提供 `/sessions-all` 命令作为替代方案
- 按更新时间倒序显示会话列表
## 安装
### 方法 1:全局安装(推荐)
1. 将 `src/index.ts` 复制到全局插件目录:
```bash
# Windows
mkdir -p %USERPROFILE%\.config\opencode\plugins
copy src\index.ts %USERPROFILE%\.config\opencode\plugins\oc-session-all.ts
# Linux/macOS
mkdir -p ~/.config/opencode/plugins
cp src/index.ts ~/.config/opencode/plugins/oc-session-all.ts
```
2. 重启 OpenCode
### 方法 2:项目级安装
1. 将 `src/index.ts` 复制到项目目录:
```bash
mkdir -p .opencode/plugins
cp src/index.ts .opencode/plugins/oc-session-all.ts
```
2. 重启 OpenCode
## 使用方法
### 方法 1:拦截 /session 命令
插件会自动拦截 `/session` 命令,显示所有会话记录。
### 方法 2:使用新命令
运行 `/sessions-all` 命令来显示所有会话记录。
## 输出示例
```
=== All Sessions (across all projects) ===
ID: ses_12af0b69cffeAMR3VcfAdp94Hi
Title: OpenCode WSL 迁移
Directory: C:/Users/ypshidifu
Created: 2026/9/20 10:00:00
Updated: 2026/9/20 15:30:00
---
ID: ses_12aeb915effez1zEjjIqf6yl1c
Title: Session 2
Directory: D:/桌面/源码/mc_plugn/windowmsgbot
Created: 2026/9/20 09:00:00
Updated: 2026/9/20 14:00:00
---
Total: 68 sessions
```
## 工作原理
插件通过两种方式获取所有会话:
1. **OpenCode Client API**:尝试使用 OpenCode 的客户端 API 获取会话列表
2. **数据库直接查询**:如果 API 不可用,直接查询 SQLite 数据库
## 配置
插件无需额外配置,安装后即可使用。
## 故障排除
如果插件不工作:
1. 确保插件文件已正确放置在插件目录
2. 重启 OpenCode
3. 检查控制台日志是否有错误信息
4. 确保 SQLite3 命令行工具可用(用于数据库查询回退方案)
## 依赖
- OpenCode 1.18.11 或更新版本
- SQLite3 命令行工具(可选,用于数据库查询回退方案)
## 许可证
MIT
+20
View File
@@ -0,0 +1,20 @@
{
"name": "oc-session-all",
"version": "1.0.0",
"description": "OpenCode plugin to show all sessions regardless of current directory",
"main": "src/index.ts",
"type": "module",
"scripts": {
"build": "tsc",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": ["opencode", "plugin", "session"],
"author": "",
"license": "MIT",
"dependencies": {
"@opencode-ai/plugin": "latest"
},
"devDependencies": {
"typescript": "^5.0.0"
}
}
+157
View File
@@ -0,0 +1,157 @@
/**
* OpenCode Plugin: Show All Sessions
*
* This plugin provides /sessions-all command to show all sessions
* regardless of the current working directory.
*/
import { tool } from "@opencode-ai/plugin";
import { exec } from "child_process";
import { promisify } from "util";
import { join } from "path";
import { existsSync } from "fs";
const execAsync = promisify(exec);
interface Session {
id: string;
project_id: string;
directory: string;
title: string | null;
time_created: number;
time_updated: number;
cost: number;
}
/**
* Get the path to the opencode database
*/
function getDbPath(): string {
const homeDir = process.env.HOME || process.env.USERPROFILE || "";
// Windows path
const winPath = join(homeDir, "AppData", "Roaming", "opencode", "opencode.db");
if (existsSync(winPath)) return winPath;
// Linux/macOS path
const unixPath = join(homeDir, ".local", "share", "opencode", "opencode.db");
if (existsSync(unixPath)) return unixPath;
// Fallback to Windows AppData
return winPath;
}
/**
* Query all sessions from the database
*/
async function getAllSessionsFromDb(): Promise<Session[]> {
try {
const dbPath = getDbPath();
console.log(`[oc-session-all] Database path: ${dbPath}`);
const query = `
SELECT id, project_id, directory, title, time_created, time_updated, cost
FROM session_v2
ORDER BY time_updated DESC;
`;
const { stdout } = await execAsync(`sqlite3 "${dbPath}" "${query}"`);
if (!stdout.trim()) {
return [];
}
const sessions: Session[] = [];
const lines = stdout.trim().split("\n");
for (const line of lines) {
const parts = line.split("|");
if (parts.length >= 7) {
sessions.push({
id: parts[0],
project_id: parts[1],
directory: parts[2],
title: parts[3] || null,
time_created: parseInt(parts[4]) || 0,
time_updated: parseInt(parts[5]) || 0,
cost: parseFloat(parts[6]) || 0,
});
}
}
return sessions;
} catch (error) {
console.error("[oc-session-all] Failed to query database:", error);
return [];
}
}
/**
* Format a timestamp to local string
*/
function formatTime(timestamp: number): string {
if (!timestamp) return "Unknown";
return new Date(timestamp * 1000).toLocaleString("zh-CN");
}
/**
* Format cost to display string
*/
function formatCost(cost: number): string {
if (!cost) return "Free";
return `$${cost.toFixed(4)}`;
}
export const OcSessionAll = async ({ project, client, $ }: any) => {
console.log("[oc-session-all] Plugin loaded");
return {
tool: {
"sessions-all": tool({
description: "显示所有项目的会话记录,绕过目录过滤限制。Show all sessions from all projects.",
args: {},
async execute() {
const sessions = await getAllSessionsFromDb();
if (!sessions || sessions.length === 0) {
return "没有找到任何会话记录。No sessions found.";
}
let output = "=== 所有会话记录 (All Sessions) ===\n\n";
// Group sessions by project
const byProject = new Map<string, Session[]>();
for (const session of sessions) {
const key = session.project_id || "unknown";
if (!byProject.has(key)) {
byProject.set(key, []);
}
byProject.get(key)!.push(session);
}
// Display sessions
let index = 1;
for (const session of sessions) {
const created = formatTime(session.time_created);
const updated = formatTime(session.time_updated);
const cost = formatCost(session.cost);
output += `${index}. ${session.title || "Untitled"}\n`;
output += ` ID: ${session.id}\n`;
output += ` 目录: ${session.directory}\n`;
output += ` 创建: ${created} | 更新: ${updated}\n`;
output += ` 费用: ${cost}\n\n`;
index++;
}
output += `共 ${sessions.length} 个会话`;
return output;
}
})
}
};
};
export default OcSessionAll;