op-session-id 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +31 -0
- package/src/index.ts +115 -0
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json.schemastore.org/package.json",
|
|
3
|
+
"name": "op-session-id",
|
|
4
|
+
"version": "0.1.1",
|
|
5
|
+
"description": "opencode TUI plugin: /id copies the current session ID; prints it again when opencode exits.",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./src/index.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": "./src/index.ts",
|
|
10
|
+
"./tui": "./src/index.ts"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"src/index.ts"
|
|
14
|
+
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"typecheck": "tsc --noEmit",
|
|
17
|
+
"test": "bun test",
|
|
18
|
+
"dev": "bun run scripts/dev-sandbox.ts"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"opencode",
|
|
22
|
+
"opencode-plugin",
|
|
23
|
+
"session-id"
|
|
24
|
+
],
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@opencode-ai/plugin": "^1.17.0",
|
|
28
|
+
"@types/bun": "^1.1.0",
|
|
29
|
+
"typescript": "^5"
|
|
30
|
+
}
|
|
31
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { spawn } from "node:child_process"
|
|
2
|
+
import { platform } from "node:os"
|
|
3
|
+
import type { TuiPluginApi, TuiPluginModule } from "@opencode-ai/plugin/tui"
|
|
4
|
+
|
|
5
|
+
// Mirrors packages/tui/src/clipboard.ts writeOsc52: terminal-native clipboard
|
|
6
|
+
// that also works over ssh; tmux/screen need the DCS passthrough wrapper.
|
|
7
|
+
function writeOsc52(text: string) {
|
|
8
|
+
if (!process.stdout.isTTY) return
|
|
9
|
+
const sequence = `\x1b]52;c;${Buffer.from(text).toString("base64")}\x07`
|
|
10
|
+
try {
|
|
11
|
+
process.stdout.write(process.env.TMUX || process.env.STY ? `\x1bPtmux;\x1b${sequence}\x1b\\` : sequence)
|
|
12
|
+
} catch {
|
|
13
|
+
// Plugin command handlers run inside TUI dispatch; never throw from here.
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function copy(text: string) {
|
|
18
|
+
// Clipboard writes only make sense from an interactive terminal; this also
|
|
19
|
+
// keeps hook-level tests from clobbering the real clipboard.
|
|
20
|
+
if (!process.stdout.isTTY) return
|
|
21
|
+
writeOsc52(text)
|
|
22
|
+
if (platform() !== "darwin") return
|
|
23
|
+
try {
|
|
24
|
+
const child = spawn("pbcopy", { stdio: ["pipe", "ignore", "ignore"] })
|
|
25
|
+
child.on("error", () => {})
|
|
26
|
+
child.stdin.end(text)
|
|
27
|
+
} catch {}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function routeSessionID(api: TuiPluginApi) {
|
|
31
|
+
const route = api.route.current
|
|
32
|
+
const sessionID = route.name === "session" ? route.params?.sessionID : undefined
|
|
33
|
+
return typeof sessionID === "string" ? sessionID : undefined
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function readSessionID(properties: unknown) {
|
|
37
|
+
const record = properties && typeof properties === "object" ? (properties as Record<string, unknown>) : undefined
|
|
38
|
+
const sessionID = record?.sessionID ?? record?.sessionId ?? record?.session_id
|
|
39
|
+
return typeof sessionID === "string" ? sessionID : undefined
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export async function installSessionIdPlugin(api: TuiPluginApi): Promise<void> {
|
|
43
|
+
let activeSessionID: string | undefined
|
|
44
|
+
const setActiveSession = (sessionID?: string) => {
|
|
45
|
+
if (sessionID) activeSessionID = sessionID
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const current = () => routeSessionID(api) ?? activeSessionID
|
|
49
|
+
|
|
50
|
+
const showSessionID = () => {
|
|
51
|
+
const sessionID = current()
|
|
52
|
+
if (!sessionID) {
|
|
53
|
+
api.ui.toast({ message: "No session selected yet.", variant: "error" })
|
|
54
|
+
return
|
|
55
|
+
}
|
|
56
|
+
copy(sessionID)
|
|
57
|
+
api.ui.toast({ title: "Session ID", message: `${sessionID} (copied)`, variant: "success", duration: 8000 })
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (typeof api.keymap?.registerLayer === "function") {
|
|
61
|
+
api.keymap.registerLayer({
|
|
62
|
+
commands: [
|
|
63
|
+
{
|
|
64
|
+
namespace: "palette",
|
|
65
|
+
name: "session-id",
|
|
66
|
+
title: "Copy session ID",
|
|
67
|
+
desc: "Show the current session ID and copy it to the clipboard",
|
|
68
|
+
category: "Session",
|
|
69
|
+
slashName: "id",
|
|
70
|
+
run() {
|
|
71
|
+
showSessionID()
|
|
72
|
+
return true
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
],
|
|
76
|
+
})
|
|
77
|
+
} else {
|
|
78
|
+
api.command?.register(() => [
|
|
79
|
+
{
|
|
80
|
+
title: "Copy session ID",
|
|
81
|
+
value: "session-id",
|
|
82
|
+
description: "Show the current session ID and copy it to the clipboard",
|
|
83
|
+
category: "Session",
|
|
84
|
+
slash: { name: "id" },
|
|
85
|
+
onSelect: showSessionID,
|
|
86
|
+
},
|
|
87
|
+
])
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
api.event.on("tui.session.select", (event) => setActiveSession(event.properties.sessionID))
|
|
91
|
+
api.event.on("session.created", (event) => setActiveSession(event.properties.sessionID))
|
|
92
|
+
api.event.on("session.updated", (event) => setActiveSession(event.properties.sessionID))
|
|
93
|
+
api.event.on("session.status", (event) => setActiveSession(readSessionID(event.properties)))
|
|
94
|
+
|
|
95
|
+
// Best-effort: print the last session ID to the normal screen after the TUI
|
|
96
|
+
// tears down, so it is visible in scrollback once opencode closes.
|
|
97
|
+
const printOnExit = () => {
|
|
98
|
+
const sessionID = current()
|
|
99
|
+
if (!sessionID) return
|
|
100
|
+
try {
|
|
101
|
+
process.stderr.write(`\nopencode session: ${sessionID}\nresume: opencode --session ${sessionID}\n`)
|
|
102
|
+
} catch {}
|
|
103
|
+
}
|
|
104
|
+
process.on("exit", printOnExit)
|
|
105
|
+
api.lifecycle.onDispose(() => {
|
|
106
|
+
process.removeListener("exit", printOnExit)
|
|
107
|
+
})
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const plugin: TuiPluginModule = {
|
|
111
|
+
id: "opencode-session-id",
|
|
112
|
+
tui: installSessionIdPlugin,
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export default plugin
|