v2: 将 oc-session-all 从 v1 格式转为 v2 Plugin.define 格式
- 使用 import { Plugin } from "@opencode/plugin/tui"
- 使用 Plugin.define({ id, setup(context) }) 格式
- api.* 调用全部替换为 context.*: api.event.on → context.data.on, api.ui.toast → context.ui.toast.show, api.ui.dialog.* → context.ui.dialog.*, api.command.register + api.keymap.registerLayer 合并为 context.keymap.layer({commands, bindings})
- package.json exports 添加 ./tui 入口点,engines.opencode 升级为 >=2.0.0
- 已通过 minimal-v2-test 验证 v2 格式可正确加载
This commit is contained in:
+6
-12
@@ -1,11 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "oc-session-all",
|
"name": "oc-session-all",
|
||||||
"version": "2.0.0",
|
"version": "2.1.0",
|
||||||
"description": "OpenCode TUI plugin: browse and switch to any session across all projects",
|
"description": "OpenCode v2 TUI plugin: browse and switch to any session across all projects",
|
||||||
"main": "tui-plugins/oc-session-all.ts",
|
"main": "tui.js",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"exports": {
|
"exports": {
|
||||||
".": "./tui-plugins/oc-session-all.ts"
|
".": "./tui.js",
|
||||||
|
"./tui": "./tui.js"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
@@ -20,13 +21,6 @@
|
|||||||
"author": "",
|
"author": "",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"opencode": ">=1.18.0"
|
"opencode": ">=2.0.0"
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@opencode-ai/plugin": "latest"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@opentui/solid": "latest",
|
|
||||||
"typescript": "^5.0.0"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
/**
|
/**
|
||||||
* OpenCode TUI Plugin: Show All Sessions
|
* OpenCode v2 TUI Plugin: Show All Sessions
|
||||||
*
|
*
|
||||||
* Registers /sessions-all command to show all sessions
|
* Registers /sessions-all command to show all sessions
|
||||||
* across all projects via a searchable picker dialog.
|
* across all projects via a searchable picker dialog.
|
||||||
* Selecting a session navigates directly to it.
|
* Selecting a session navigates directly to it.
|
||||||
*
|
*
|
||||||
* TUI format: export default { id, tui }
|
|
||||||
*
|
|
||||||
* Also intercepts MCP connection error toasts to keep them quiet.
|
* Also intercepts MCP connection error toasts to keep them quiet.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { Plugin } from "@opencode/plugin/tui"
|
||||||
|
|
||||||
// ── Helpers ────────────────────────────────────────────────────────────
|
// ── Helpers ────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
function formatDateTime(ms) {
|
function formatDateTime(ms) {
|
||||||
@@ -42,9 +42,13 @@ function projectDisplayName(session, projectMap) {
|
|||||||
|
|
||||||
// ── Plugin ─────────────────────────────────────────────────────────────
|
// ── Plugin ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
const tui = async (api) => {
|
export default Plugin.define({
|
||||||
|
id: "oc-session-all",
|
||||||
|
setup(context) {
|
||||||
|
console.log("[oc-session-all] v2 Plugin loaded!")
|
||||||
|
|
||||||
// ─── MCP Error Toast Suppression ─────────────────────────────────────
|
// ─── MCP Error Toast Suppression ─────────────────────────────────────
|
||||||
api.event.on("tui.toast.show", (event) => {
|
context.data.on("tui.toast.show", (event) => {
|
||||||
const props = event.properties;
|
const props = event.properties;
|
||||||
if (
|
if (
|
||||||
props.variant === "error" &&
|
props.variant === "error" &&
|
||||||
@@ -61,27 +65,49 @@ const tui = async (api) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// ─── Session Picker Dialog ────────────────────────────────────────────
|
// ─── Register Command ─────────────────────────────────────────────────
|
||||||
const openPicker = async () => {
|
context.keymap.layer({
|
||||||
if (api.mode.current() !== "base") return;
|
commands: [
|
||||||
|
{
|
||||||
|
title: "All Sessions",
|
||||||
|
value: "sessions.all",
|
||||||
|
description: "Browse and switch to any session across all projects",
|
||||||
|
category: "Session Picker",
|
||||||
|
slash: { name: "sessions-all", aliases: ["resume-all", "continue-all"] },
|
||||||
|
onSelect: () => {
|
||||||
|
void openPicker();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
bindings: [
|
||||||
|
{
|
||||||
|
key: "ctrl+o",
|
||||||
|
desc: "All sessions picker",
|
||||||
|
preventDefault: true,
|
||||||
|
cmd: () => void openPicker(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
// ─── Session Picker Dialog ────────────────────────────────────────────
|
||||||
|
async function openPicker() {
|
||||||
let sessions = [];
|
let sessions = [];
|
||||||
let projects = [];
|
let projects = [];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const [sessionResult, projectResult] = await Promise.all([
|
const [sessionResult, projectResult] = await Promise.all([
|
||||||
api.client.experimental.session.list({
|
context.client.experimental.session.list({
|
||||||
limit: 1000,
|
limit: 1000,
|
||||||
roots: true,
|
roots: true,
|
||||||
directory: "",
|
directory: "",
|
||||||
}),
|
}),
|
||||||
api.client.project.list({}),
|
context.client.project.list({}),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
sessions = sessionResult?.data ?? sessionResult ?? [];
|
sessions = sessionResult?.data ?? sessionResult ?? [];
|
||||||
projects = projectResult?.data ?? projectResult ?? [];
|
projects = projectResult?.data ?? projectResult ?? [];
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
api.ui.toast({
|
context.ui.toast.show({
|
||||||
message: "Failed to load sessions",
|
message: "Failed to load sessions",
|
||||||
variant: "error",
|
variant: "error",
|
||||||
});
|
});
|
||||||
@@ -97,7 +123,7 @@ const tui = async (api) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (visible.length === 0) {
|
if (visible.length === 0) {
|
||||||
api.ui.toast({
|
context.ui.toast.show({
|
||||||
message: "No sessions found",
|
message: "No sessions found",
|
||||||
variant: "warning",
|
variant: "warning",
|
||||||
});
|
});
|
||||||
@@ -136,51 +162,20 @@ const tui = async (api) => {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
api.ui.dialog.setSize("xlarge");
|
context.ui.dialog.setSize("xlarge");
|
||||||
api.ui.dialog.replace(
|
context.ui.dialog.replace(
|
||||||
() =>
|
() =>
|
||||||
api.ui.DialogSelect({
|
context.ui.DialogSelect({
|
||||||
title: "All Sessions",
|
title: "All Sessions",
|
||||||
placeholder: "Search sessions across all projects\u2026",
|
placeholder: "Search sessions across all projects\u2026",
|
||||||
options,
|
options,
|
||||||
onSelect: (option) => {
|
onSelect: (option) => {
|
||||||
api.ui.dialog.clear();
|
context.ui.dialog.clear();
|
||||||
api.route.navigate("session", { sessionID: option.value });
|
context.route.navigate("session", { sessionID: option.value });
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
() => {},
|
() => {},
|
||||||
);
|
);
|
||||||
};
|
|
||||||
|
|
||||||
// ─── Register Command ─────────────────────────────────────────────────
|
|
||||||
if (api.command) {
|
|
||||||
api.command.register(() => [
|
|
||||||
{
|
|
||||||
title: "All Sessions",
|
|
||||||
value: "sessions.all",
|
|
||||||
description: "Browse and switch to any session across all projects",
|
|
||||||
category: "Session Picker",
|
|
||||||
slash: { name: "sessions-all", aliases: ["resume-all", "continue-all"] },
|
|
||||||
onSelect: () => {
|
|
||||||
void openPicker();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─── Keybinding ───────────────────────────────────────────────────────
|
|
||||||
api.keymap.registerLayer({
|
|
||||||
bindings: [
|
|
||||||
{
|
|
||||||
key: "ctrl+o",
|
|
||||||
desc: "All sessions picker",
|
|
||||||
preventDefault: true,
|
|
||||||
cmd: () => void openPicker(),
|
|
||||||
},
|
},
|
||||||
],
|
})
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// ── Export ──────────────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
export default { id: "oc-session-all", tui };
|
|
||||||
|
|||||||
Reference in New Issue
Block a user