opencode-subagent-magazine 1.4.1 → 1.5.0

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-subagent-magazine",
3
- "version": "1.4.1",
3
+ "version": "1.5.0",
4
4
  "description": "OpenCode TUI plugin monitoring sub-agent invocation status in real time",
5
5
  "type": "module",
6
6
  "types": "dist/index.d.ts",
@@ -54,6 +54,7 @@
54
54
  "devDependencies": {
55
55
  "@opencode-ai/plugin": "^1.14.50",
56
56
  "@opencode-ai/sdk": "^1.14.50",
57
+ "@types/node": "^22.0.0",
57
58
  "esbuild": "^0.25.0",
58
59
  "esbuild-plugin-solid": "^0.5.0",
59
60
  "tsx": "^4.22.3",
package/src/_version.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  // auto-generated
2
- export const PLUGIN_VERSION="1.4.1";
2
+ export const PLUGIN_VERSION="1.5.0";
@@ -0,0 +1,134 @@
1
+ import { spawn } from "node:child_process"
2
+ import { platform, release } from "node:os"
3
+
4
+ export type ClipboardMethod =
5
+ | "pbcopy"
6
+ | "osascript"
7
+ | "wl-copy"
8
+ | "xclip"
9
+ | "xsel"
10
+ | "powershell"
11
+ | "osc52"
12
+ | "none"
13
+
14
+ export interface CopyTextResult {
15
+ copied: boolean
16
+ method: ClipboardMethod
17
+ error?: string
18
+ }
19
+
20
+ function runWithInput(command: string, args: string[], input: string): Promise<void> {
21
+ return new Promise((resolve, reject) => {
22
+ const child = spawn(command, args, {
23
+ stdio: ["pipe", "ignore", "ignore"],
24
+ windowsHide: true,
25
+ })
26
+
27
+ child.once("error", reject)
28
+ child.once("close", (code) => {
29
+ if (code === 0) resolve()
30
+ else reject(new Error(`${command} exited with code ${code}`))
31
+ })
32
+
33
+ child.stdin?.end(input)
34
+ })
35
+ }
36
+
37
+ function writeOsc52(text: string): boolean {
38
+ if (!process.stdout.isTTY) return false
39
+
40
+ const payload = Buffer.from(text, "utf8").toString("base64")
41
+ const sequence = `\x1b]52;c;${payload}\x07`
42
+ const wrapped = process.env.TMUX || process.env.STY
43
+ ? `\x1bPtmux;\x1b${sequence}\x1b\\`
44
+ : sequence
45
+
46
+ process.stdout.write(wrapped)
47
+ return true
48
+ }
49
+
50
+ async function tryCommand(
51
+ method: ClipboardMethod,
52
+ command: string,
53
+ args: string[],
54
+ text: string,
55
+ ): Promise<CopyTextResult | undefined> {
56
+ try {
57
+ await runWithInput(command, args, text)
58
+ return { copied: true, method }
59
+ } catch {
60
+ return undefined
61
+ }
62
+ }
63
+
64
+ export async function copyText(text: string): Promise<CopyTextResult> {
65
+ if (!text) return { copied: false, method: "none", error: "empty_text" }
66
+
67
+ const os = platform()
68
+ const isWsl = release().toLowerCase().includes("microsoft")
69
+
70
+ const attempts: Array<() => Promise<CopyTextResult | undefined>> = []
71
+
72
+ if (os === "darwin") {
73
+ attempts.push(() => tryCommand("pbcopy", "pbcopy", [], text))
74
+ attempts.push(() =>
75
+ tryCommand(
76
+ "osascript",
77
+ "osascript",
78
+ ["-e", "set the clipboard to (read (POSIX file \"/dev/stdin\") as text)"],
79
+ text,
80
+ ),
81
+ )
82
+ }
83
+
84
+ if (os === "linux" && isWsl) {
85
+ attempts.push(() =>
86
+ tryCommand(
87
+ "powershell",
88
+ "powershell.exe",
89
+ [
90
+ "-NonInteractive",
91
+ "-NoProfile",
92
+ "-Command",
93
+ "[Console]::InputEncoding=[Text.Encoding]::UTF8; Set-Clipboard ([Console]::In.ReadToEnd())",
94
+ ],
95
+ text,
96
+ ),
97
+ )
98
+ } else if (os === "linux") {
99
+ if (process.env.WAYLAND_DISPLAY) {
100
+ attempts.push(() => tryCommand("wl-copy", "wl-copy", [], text))
101
+ }
102
+ attempts.push(() => tryCommand("xclip", "xclip", ["-selection", "clipboard"], text))
103
+ attempts.push(() => tryCommand("xsel", "xsel", ["--clipboard", "--input"], text))
104
+ }
105
+
106
+ if (os === "win32") {
107
+ attempts.push(() =>
108
+ tryCommand(
109
+ "powershell",
110
+ "powershell.exe",
111
+ [
112
+ "-NonInteractive",
113
+ "-NoProfile",
114
+ "-Command",
115
+ "[Console]::InputEncoding=[Text.Encoding]::UTF8; Set-Clipboard ([Console]::In.ReadToEnd())",
116
+ ],
117
+ text,
118
+ ),
119
+ )
120
+ }
121
+
122
+ for (const attempt of attempts) {
123
+ const result = await attempt()
124
+ if (result) return result
125
+ }
126
+
127
+ try {
128
+ if (writeOsc52(text)) return { copied: true, method: "osc52" }
129
+ } catch {
130
+ // Continue to the explicit failure result.
131
+ }
132
+
133
+ return { copied: false, method: "none", error: "clipboard_unavailable" }
134
+ }