opencode-nvim-diff-review 0.1.0 → 0.2.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/README.md CHANGED
@@ -85,7 +85,7 @@ Add the plugin to your `opencode.json` configuration:
85
85
 
86
86
  ```json
87
87
  {
88
- "plugin": ["github:talldan/nvim-diff-review-opencode-plugin"]
88
+ "plugin": ["opencode-nvim-diff-review"]
89
89
  }
90
90
  ```
91
91
 
@@ -95,15 +95,29 @@ Restart OpenCode to load the plugin. The `diff_review` tool will be available to
95
95
 
96
96
  ### 3. Neovim RPC socket
97
97
 
98
- The tool communicates with Neovim via its RPC socket. You need to:
98
+ The tool communicates with Neovim via its RPC socket. In most cases, **no configuration is needed** — the tool auto-discovers running Neovim instances.
99
99
 
100
- 1. Start Neovim with a listen address:
101
- ```bash
102
- export NVIM_SOCKET=/tmp/nvim.sock
103
- nvim --listen $NVIM_SOCKET
104
- ```
100
+ #### Auto-discovery (default)
105
101
 
106
- 2. Make sure `NVIM_SOCKET` is set in the environment where OpenCode runs.
102
+ The tool automatically finds Neovim by:
103
+
104
+ 1. Checking the `NVIM_SOCKET` environment variable (if set, always used)
105
+ 2. Scanning for Neovim sockets in standard locations (`$TMPDIR` and `/tmp`)
106
+ 3. Preferring the Neovim instance whose working directory matches the current project
107
+ 4. Falling back to the first live Neovim instance found
108
+
109
+ This means if you just run `nvim` in your project directory, OpenCode will find it automatically.
110
+
111
+ #### Explicit configuration (optional)
112
+
113
+ If auto-discovery doesn't work for your setup (e.g., multiple Neovim instances in the same directory), you can set the socket path explicitly:
114
+
115
+ ```bash
116
+ export NVIM_SOCKET=/tmp/nvim.sock
117
+ nvim --listen $NVIM_SOCKET
118
+ ```
119
+
120
+ Make sure `NVIM_SOCKET` is set in the environment where OpenCode runs.
107
121
 
108
122
  If you use [CMUX](https://cmux.com), you can set this in your workspace configuration so both Neovim and OpenCode share the socket path automatically.
109
123
 
@@ -133,6 +147,7 @@ Key design decisions:
133
147
  - **Wrap-around prevention**: diffview.nvim wraps from the last file to the first (and vice versa) when navigating. The tool detects this by comparing indices before and after navigation, and undoes the wrap if detected.
134
148
  - **Buffer cleanup on close**: diffview.nvim intentionally keeps local file buffers open after closing (so you can continue editing). The plugin tracks which buffers existed before the review and removes any new ones on close — unless they have unsaved edits.
135
149
  - **Small delays after navigation**: 200-500ms sleeps after diffview commands to let the UI update before querying state. Without this, the state query can return stale data.
150
+ - **Socket auto-discovery**: When `NVIM_SOCKET` is not set, the tool scans `$TMPDIR/nvim.$USER/` and `/tmp` for Neovim socket files, verifies each is live, and uses `lsof` to match the Neovim process's working directory against the current project. This allows zero-configuration usage in ad-hoc terminals — just run `nvim` and OpenCode will find it.
136
151
 
137
152
  ### Review workflow instructions
138
153
 
@@ -16,6 +16,77 @@ interface DiffviewState {
16
16
  error?: string
17
17
  }
18
18
 
19
+ /**
20
+ * Discover a Neovim RPC socket when NVIM_SOCKET is not explicitly set.
21
+ *
22
+ * Strategy:
23
+ * 1. Check NVIM_SOCKET env var (always wins)
24
+ * 2. Scan for socket files in known locations
25
+ * 3. Verify each is live by attempting a connection
26
+ * 4. Prefer the Neovim instance whose cwd matches ours (same project)
27
+ * 5. Fall back to the first live socket found
28
+ */
29
+ const discoverNvimSocket = async (): Promise<string | null> => {
30
+ // 1. Explicit env var — skip discovery entirely
31
+ if (process.env.NVIM_SOCKET) return process.env.NVIM_SOCKET
32
+
33
+ // 2. Scan for socket files
34
+ const tmpdir = process.env.TMPDIR || "/tmp"
35
+ const user = process.env.USER || "unknown"
36
+ let socketPaths: string[] = []
37
+
38
+ try {
39
+ const output =
40
+ await Bun.$`find -L ${tmpdir}/nvim.${user} /tmp -maxdepth 4 -type s -name "nvim*" 2>/dev/null`.text()
41
+ socketPaths = output.trim().split("\n").filter(Boolean)
42
+ } catch {}
43
+
44
+ if (socketPaths.length === 0) return null
45
+
46
+ // 3 & 4. Check each socket — prefer cwd match, fall back to first live one
47
+ const ourCwd = process.cwd()
48
+ let fallback: string | null = null
49
+
50
+ for (const socketPath of socketPaths) {
51
+ try {
52
+ // Verify socket is live with a simple expression
53
+ await Bun.$`nvim --headless --server ${socketPath} --remote-expr "1+1"`.text()
54
+
55
+ // Try to get the PID from the socket filename (default sockets: nvim.<pid>.0)
56
+ let pid: string | undefined
57
+ const pidFromName = socketPath.match(/nvim\.(\d+)\.\d+$/)
58
+ if (pidFromName) {
59
+ pid = pidFromName[1]
60
+ } else {
61
+ // For --listen sockets (no PID in filename), find the owning process
62
+ try {
63
+ const lsof = await Bun.$`lsof ${socketPath} 2>/dev/null`.text()
64
+ const pidMatch = lsof.match(/nvim\s+(\d+)/)
65
+ if (pidMatch) pid = pidMatch[1]
66
+ } catch {}
67
+ }
68
+
69
+ // Get the cwd of the Neovim process and compare with ours
70
+ if (pid) {
71
+ try {
72
+ const lsof = await Bun.$`lsof -p ${pid} -Fn 2>/dev/null`.text()
73
+ const cwdMatch = lsof.match(/fcwd\nn(.+)/)
74
+ if (cwdMatch && cwdMatch[1] === ourCwd) {
75
+ return socketPath // Exact cwd match — this is our Neovim
76
+ }
77
+ } catch {}
78
+ }
79
+
80
+ // Remember the first live socket as fallback
81
+ if (!fallback) fallback = socketPath
82
+ } catch {
83
+ // Socket not responsive — stale socket from a crashed Neovim, skip it
84
+ }
85
+ }
86
+
87
+ return fallback
88
+ }
89
+
19
90
  export const DiffReviewPlugin: Plugin = async (ctx) => {
20
91
  return {
21
92
  tool: {
@@ -79,14 +150,16 @@ export const DiffReviewPlugin: Plugin = async (ctx) => {
79
150
  ),
80
151
  },
81
152
  async execute(args, context) {
82
- const socket = process.env.NVIM_SOCKET
153
+ const socket = await discoverNvimSocket()
83
154
  if (!socket) {
84
- return "NVIM_SOCKET environment variable is not set. " +
85
- "Make sure Neovim is running with --listen and NVIM_SOCKET is exported.\n\n" +
155
+ return "Could not find a running Neovim instance.\n\n" +
156
+ "The tool looks for Neovim in this order:\n" +
157
+ "1. NVIM_SOCKET environment variable (if set)\n" +
158
+ "2. Neovim instances whose working directory matches this project\n" +
159
+ "3. Any running Neovim instance\n\n" +
86
160
  "Quick setup:\n" +
87
161
  " export NVIM_SOCKET=/tmp/nvim.sock\n" +
88
- " nvim --listen $NVIM_SOCKET\n\n" +
89
- "If using CMUX, the workspace command sets this automatically."
162
+ " nvim --listen $NVIM_SOCKET"
90
163
  }
91
164
 
92
165
  const nvimExpr = (expr: string) =>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-nvim-diff-review",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Agent-driven guided code review for Neovim + OpenCode",
5
5
  "main": "opencode-plugin/index.ts",
6
6
  "keywords": [