@nofendian17/opencode-relay-plugin 2.0.5 → 2.0.6

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 (3) hide show
  1. package/README.md +9 -5
  2. package/index.ts +52 -24
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -65,7 +65,7 @@ Local file (auto-discovered):
65
65
  | Option | Env fallback | Description |
66
66
  | --- | --- | --- |
67
67
  | `url: string \| string[]` | `RELAY_URL` (comma-separated) | Relay endpoint(s), `http(s)` only. Invalid entries are skipped with a warning log; if none remain valid the plugin disables itself. |
68
- | `debug: boolean` | `RELAY_DEBUG=1` | Verbose per-request logging. When on, log lines are also appended to `/tmp/opencode-relay.log` (plugin `console.log` is not forwarded to opencode logs). Override the path with `RELAY_DEBUG_LOG` (used by tests for isolation). |
68
+ | `debug: boolean` | `RELAY_DEBUG=1` | Verbose per-request logging. **Ini opsi plugin** (`plugins[].options.debug`), **bukan** top-level `debug` di `opencode.jsonc` — top-level `debug` tidak mengaktifkan log plugin ini. Baris penting (`init`, `disabled`, `fallback`) selalu ditulis ke file log; baris verbose per-request hanya saat `debug` on. Override path dengan `RELAY_DEBUG_LOG` (dipakai tests untuk isolasi). |
69
69
 
70
70
  ## Relay protocol (unchanged from v1)
71
71
 
@@ -89,10 +89,11 @@ access logs as secret-bearing.
89
89
 
90
90
  ## Verify
91
91
 
92
- 1. Set `debug: true` + `url` to a local echo server, run a prompt, confirm
92
+ 1. Set plugin option `debug: true` + `url` ke local echo server, run prompt, confirm
93
93
  `x-relay-target` / `x-relay-path` headers arrive.
94
94
  2. Stop the relay → request still succeeds via direct fallback (check
95
- `[relay] relay fallback to direct` in `/tmp/opencode-relay.log`).
95
+ `[relay] relay fallback to direct` in the log file — path is printed in the
96
+ `[relay] init` line as `logFile`).
96
97
  3. Unset `url`/`RELAY_URL` → `[relay] disabled` log, traffic goes direct.
97
98
  4. Confirm scope: a request to `https://opencode.ai/inference/...` must show
98
99
  `via relay` in the log. If the log only shows
@@ -100,8 +101,11 @@ access logs as secret-bearing.
100
101
  `https://opencode.ai/...` URL and zero `via relay` lines, the request never
101
102
  entered the pool — check the origin match in `index.ts`.
102
103
 
103
- Note: the debug file is the shared `/tmp/opencode-relay.log`; concurrent
104
- opencode processes append to the same file.
104
+ Note: the default file is `os.tmpdir()/opencode-relay.log` — on macOS that is
105
+ `$TMPDIR/opencode-relay.log` (e.g. `/var/folders/.../T/`), NOT `/tmp/`.
106
+ Check the `logFile` field in the `[relay] init` line for the exact path.
107
+ Concurrent opencode processes append to the same file. Plugin `console.log`
108
+ is not forwarded to opencode logs, so always check the file, not the TUI.
105
109
 
106
110
  ## V1 vs V2 notes
107
111
 
package/index.ts CHANGED
@@ -1,8 +1,26 @@
1
1
  import { Plugin } from "@opencode/plugin"
2
- import { appendFile } from "node:fs/promises"
2
+ import { appendFileSync } from "node:fs"
3
3
  import { tmpdir } from "node:os"
4
4
  import { join } from "node:path"
5
5
 
6
+ // Bun runtime: node:fs/promises appendFile fails silently. Use sync API.
7
+ function safeAppendFile(path: string, data: string): void {
8
+ try {
9
+ appendFileSync(path, data)
10
+ } catch {
11
+ // Fallback: try Bun.write if available
12
+ try {
13
+ // @ts-ignore - Bun global may not exist in Node
14
+ if (typeof Bun !== "undefined") {
15
+ // @ts-ignore
16
+ Bun.write(path, data, { mode: "append" })
17
+ }
18
+ } catch {
19
+ // All failed - ignore
20
+ }
21
+ }
22
+ }
23
+
6
24
  interface RelayOptions {
7
25
  url?: string | string[]
8
26
  debug?: boolean
@@ -198,15 +216,28 @@ function createRelayFetch(
198
216
  }
199
217
  }
200
218
 
219
+ function parseDebug(value: unknown): boolean | undefined {
220
+ if (value === undefined) return undefined
221
+ if (typeof value === "boolean") return value
222
+ if (typeof value === "number") return value !== 0
223
+ if (typeof value === "string") {
224
+ const v = value.trim().toLowerCase()
225
+ if (["1", "true", "yes", "on", "debug"].includes(v)) return true
226
+ if (["0", "false", "no", "off", ""].includes(v)) return false
227
+ return true
228
+ }
229
+ return Boolean(value)
230
+ }
231
+
201
232
  function parseOptions(options: Record<string, unknown> | undefined): {
202
233
  relays: string[]
203
234
  debug: boolean
204
235
  } {
205
236
  const url = options?.["url"] as string | string[] | undefined
206
- const debugOpt = options?.["debug"] as boolean | undefined
237
+ const envDebug = process.env.RELAY_DEBUG
207
238
  return {
208
239
  relays: normalizeRelays(url),
209
- debug: debugOpt ?? process.env.RELAY_DEBUG === "1",
240
+ debug: parseDebug(options?.["debug"]) ?? parseDebug(envDebug) ?? false,
210
241
  }
211
242
  }
212
243
 
@@ -219,29 +250,26 @@ export default Plugin.define({
219
250
  const debug = parsed.debug
220
251
  const prefix = "[relay]"
221
252
  // console output from v2 plugins is not forwarded to opencode logs,
222
- // so when debug is on, mirror everything to a file as well.
253
+ // so mirror important events to a file unconditionally and verbose
254
+ // per-request lines only when debug is on.
255
+ // NOTE: this is the plugin option `plugins[].options.debug`
256
+ // (or RELAY_DEBUG=1), NOT the top-level opencode `debug` flag.
223
257
  // RELAY_DEBUG_LOG overrides the path (tests use an isolated file so a
224
258
  // live opencode process appending to the default never interferes).
225
- // Async fire-and-forget: logging never breaks requests.
226
- const debugLogFile = process.env.RELAY_DEBUG_LOG ?? DEBUG_LOG
227
- let warnedLogFile = false
228
- const fileLog: Logger | undefined = debug
229
- ? (message, extra) => {
230
- const line =
231
- `${new Date().toISOString()} ${prefix} ${message}` +
232
- (extra ? ` ${JSON.stringify(extra)}` : "") +
233
- "\n"
234
- appendFile(debugLogFile, line).catch((e: unknown) => {
235
- if (!warnedLogFile) {
236
- warnedLogFile = true
237
- console.log(prefix, "debug log write failed", debugLogFile, String(e))
238
- }
239
- })
240
- }
241
- : undefined
259
+ // Default path is os.tmpdir() — on macOS that is NOT /tmp but
260
+ // $TMPDIR (e.g. /var/folders/.../T/opencode-relay.log).
261
+ // Logging never breaks requests.
262
+ const logFile = process.env.RELAY_DEBUG_LOG ?? DEBUG_LOG
263
+ const fileLog: Logger = (message, extra) => {
264
+ const line =
265
+ `${new Date().toISOString()} ${prefix} ${message}` +
266
+ (extra ? ` ${JSON.stringify(extra)}` : "") +
267
+ "\n"
268
+ safeAppendFile(logFile, line)
269
+ }
242
270
  const emit: Logger = (message, extra) => {
243
271
  console.log(prefix, message, extra ? JSON.stringify(extra) : "")
244
- fileLog?.(message, extra)
272
+ fileLog(message, extra)
245
273
  }
246
274
  const log: Logger = (message, extra) => {
247
275
  if (debug) emit(message, extra)
@@ -262,14 +290,14 @@ export default Plugin.define({
262
290
  }
263
291
  }
264
292
 
265
- emit("init", { debug, relayCount: relays.length })
293
+ emit("init", { debug, relayCount: relays.length, logFile })
266
294
 
267
295
  if (relays.length === 0) {
268
296
  emit("disabled: no relays configured (set plugin option `url` or RELAY_URL)", {})
269
297
  return
270
298
  }
271
299
 
272
- log("relay pool loaded", { relays })
300
+ log("relay pool loaded", { relays, logFile })
273
301
 
274
302
  const rawFetch = globalThis.fetch
275
303
  const g = globalThis as Record<string, unknown>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nofendian17/opencode-relay-plugin",
3
- "version": "2.0.5",
3
+ "version": "2.0.6",
4
4
  "description": "Route OpenCode v2 Zen (opencode.ai) traffic through relay endpoint(s) with round-robin, failover, and direct fallback. Other providers are left untouched.",
5
5
  "type": "module",
6
6
  "main": "./index.ts",
@@ -27,7 +27,7 @@
27
27
  },
28
28
  "devDependencies": {
29
29
  "@opencode/plugin": "^2.0.28",
30
- "@types/node": "^26.6.4",
30
+ "@types/node": "^26.6.5",
31
31
  "typescript": "^5.9.3"
32
32
  }
33
33
  }