@grympler/opencode-tmux-handover 1.0.1 → 1.0.2

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/index.ts +85 -12
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@grympler/opencode-tmux-handover",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "OpenCode Desktop plugin for launching tmux with AI assistants (OpenCode, Claude, Copilot) in split panes",
5
5
  "main": "src/index.ts",
6
6
  "type": "module",
package/src/index.ts CHANGED
@@ -1,28 +1,101 @@
1
1
  import type { Plugin } from "@opencode-ai/plugin"
2
2
  import { fileURLToPath } from "url"
3
3
  import { dirname, join } from "path"
4
- import { existsSync } from "fs"
4
+ import { existsSync, unlinkSync, symlinkSync, mkdirSync, lstatSync, readlinkSync } from "fs"
5
5
  import { homedir } from "os"
6
- import { loadConfig } from "./config.js"
6
+ import { loadConfig, type PluginConfig } from "./config.js"
7
7
 
8
8
  const __filename = fileURLToPath(import.meta.url)
9
9
  const __dirname = dirname(__filename)
10
10
 
11
- export const TmuxLauncher: Plugin = async ({ $, directory }) => {
12
- const config = loadConfig()
11
+ const ALL_COMMANDS = ["tmux", "tmux-oc", "tmux-claude", "tmux-copilot"]
12
+
13
+ function isSymlink(path: string): boolean {
14
+ try {
15
+ return lstatSync(path).isSymbolicLink()
16
+ } catch {
17
+ return false
18
+ }
19
+ }
20
+
21
+ function ensureSymlink(src: string, dest: string) {
22
+ if (!existsSync(src)) {
23
+ return
24
+ }
25
+
26
+ if (isSymlink(dest)) {
27
+ try {
28
+ const target = readlinkSync(dest)
29
+ if (target === src) {
30
+ return // Already correct
31
+ }
32
+ } catch {
33
+ // proceed to replace
34
+ }
35
+ }
36
+
37
+ if (existsSync(dest) || isSymlink(dest)) {
38
+ try {
39
+ unlinkSync(dest)
40
+ } catch (err) {
41
+ console.error(`tt-plugin: Failed to remove old link ${dest}:`, err)
42
+ return
43
+ }
44
+ }
13
45
 
14
- // Auto-install check: ensure commands are symlinked
15
- const installCheckPath = join(homedir(), ".config", "opencode", "commands", "tt-configure.md")
16
- if (!existsSync(installCheckPath)) {
46
+ try {
47
+ symlinkSync(src, dest)
48
+ console.log(`tt-plugin: Linked command ${dest}`)
49
+ } catch (err) {
50
+ console.error(`tt-plugin: Failed to link ${dest}:`, err)
51
+ }
52
+ }
53
+
54
+ function removeLink(path: string) {
55
+ if (existsSync(path) || isSymlink(path)) {
17
56
  try {
18
- const installScript = join(__dirname, "..", "install.sh")
19
- // Run install script quietly
20
- await $`bash ${installScript}`.quiet()
21
- console.log("tt-plugin: Auto-installation completed")
57
+ unlinkSync(path)
58
+ console.log(`tt-plugin: Removed disabled command ${path}`)
22
59
  } catch (err) {
23
- console.error("tt-plugin: Auto-install failed:", err)
60
+ console.error(`tt-plugin: Failed to remove ${path}:`, err)
24
61
  }
25
62
  }
63
+ }
64
+
65
+ function syncCommands(config: PluginConfig) {
66
+ const commandsDir = join(homedir(), ".config", "opencode", "commands")
67
+
68
+ if (!existsSync(commandsDir)) {
69
+ mkdirSync(commandsDir, { recursive: true })
70
+ }
71
+
72
+ // 1. Always ensure tt-configure is installed
73
+ const configureLink = join(commandsDir, "tt-configure.md")
74
+ const configureSrc = join(__dirname, "commands", "tt-configure.md")
75
+ ensureSymlink(configureSrc, configureLink)
76
+
77
+ // 2. Sync enabled/disabled commands
78
+ for (const cmd of ALL_COMMANDS) {
79
+ const linkPath = join(commandsDir, `${cmd}.md`)
80
+ const srcPath = join(__dirname, "commands", `${cmd}.md`)
81
+
82
+ if (config.enabledCommands.includes(cmd)) {
83
+ ensureSymlink(srcPath, linkPath)
84
+ } else {
85
+ removeLink(linkPath)
86
+ }
87
+ }
88
+ }
89
+
90
+ export const TmuxLauncher: Plugin = async ({ $, directory }) => {
91
+ const config = loadConfig()
92
+
93
+ // Sync commands based on configuration on startup
94
+ try {
95
+ syncCommands(config)
96
+ } catch (err) {
97
+ console.error("tt-plugin: Command sync failed:", err)
98
+ }
26
99
 
27
100
  return {
28
101
  "command.execute.before": async (input, output) => {