ocremote 1.3.0 → 1.3.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.
package/lib/rpc.mjs CHANGED
@@ -21,19 +21,24 @@ export class RpcAdapter {
21
21
  }
22
22
 
23
23
  cancel(session, id) {
24
- const controller = this.sessionMap(session).get(id)
25
- if (controller) {
26
- controller.abort()
24
+ const entry = this.sessionMap(session).get(id)
25
+ if (entry) {
26
+ entry.controller.abort()
27
27
  this.log(`rpc ${id} cancelled`)
28
28
  }
29
29
  }
30
30
 
31
+ // The channel dropped. Reads are abandoned, but a mutating request keeps
32
+ // running: aborting it would leave the phone unable to tell whether the
33
+ // server applied it. Better to let it finish on the computer and let the
34
+ // client reconcile by inspecting state after reconnecting.
31
35
  cancelAll(session) {
32
36
  const map = this.active.get(session.id)
33
37
  if (!map) return
34
- for (const controller of map.values()) {
38
+ for (const entry of map.values()) {
39
+ if (entry.mutating) continue
35
40
  try {
36
- controller.abort()
41
+ entry.controller.abort()
37
42
  } catch {}
38
43
  }
39
44
  this.active.delete(session.id)
@@ -53,7 +58,9 @@ export class RpcAdapter {
53
58
  }
54
59
 
55
60
  const controller = new AbortController()
56
- map.set(id, controller)
61
+ const method = (msg.method || 'GET').toUpperCase()
62
+ const mutating = method === 'POST' || method === 'PUT' || method === 'PATCH' || method === 'DELETE'
63
+ map.set(id, { controller, mutating })
57
64
  const stream = msg.stream === true
58
65
  let opened = false
59
66
  try {
@@ -65,7 +72,7 @@ export class RpcAdapter {
65
72
  }
66
73
  }
67
74
  const headers = { authorization: this.authHeader }
68
- const init = { method: msg.method || 'GET', headers, signal: controller.signal }
75
+ const init = { method, headers, signal: controller.signal }
69
76
  if (msg.body) {
70
77
  const body = Buffer.from(String(msg.body), 'base64')
71
78
  if (body.length > MAX_UPLOAD) {
package/oc-remote.mjs CHANGED
@@ -17,7 +17,7 @@ import { b64 } from './lib/crypto.mjs'
17
17
 
18
18
  const require = createRequire(import.meta.url)
19
19
  const NAME = 'oc-remote'
20
- const VERSION = '1.3.0'
20
+ const VERSION = '1.3.2'
21
21
  const LAUNCH_LABEL = 'com.raul.ocremote'
22
22
  const LOG_PATH = path.join(os.homedir(), 'Library', 'Logs', 'oc-remote.log')
23
23
  const STARTED_AT = Date.now()
@@ -26,7 +26,7 @@ const LOOPBACK = '127.0.0.1'
26
26
 
27
27
  let qrcode = null
28
28
  try {
29
- qrcode = require(path.join(HERE, 'vendor', 'qrcode.js'))
29
+ qrcode = require(path.join(HERE, 'vendor', 'qrcode.cjs'))
30
30
  } catch {
31
31
  qrcode = null
32
32
  }
@@ -1552,7 +1552,7 @@ function printPairing() {
1552
1552
  info(`pairing deep link: ${pairLink()}`)
1553
1553
  if (!opts.printQr) return
1554
1554
  if (!qrcode) {
1555
- warn('QR unavailable: companion/vendor/qrcode.js not found')
1555
+ warn('QR unavailable: companion/vendor/qrcode.cjs not found')
1556
1556
  return
1557
1557
  }
1558
1558
  const ascii = buildQr(pairLink()).createASCII(1, 4)
@@ -1613,10 +1613,7 @@ function printBanner(health) {
1613
1613
  info(`opencode: ${opts.opencodeBin} v${health.version} -> http://${LOOPBACK}:${opts.opencodePort} (loopback only)`)
1614
1614
  info(`proxy listening: ${opts.host}:${opts.port}`)
1615
1615
  if (opts.noAuth) warn('AUTH DISABLED: anyone who can reach this port controls opencode')
1616
- for (const line of opts.noAuth
1617
- ? ['pair page: disabled (--no-auth)']
1618
- : [`pair page (loopback): http://${LOOPBACK}:${opts.port}/_ocremote/pair`])
1619
- info(line)
1616
+ if (opts.noAuth) info('pair page: disabled (--no-auth)')
1620
1617
  if (opts.relay) info(`relay: ${opts.relay} (device ${opts.deviceName || os.hostname()})`)
1621
1618
  info('self-check: oc-remote doctor')
1622
1619
  printPairing()
@@ -2237,6 +2234,14 @@ async function main() {
2237
2234
  opts.dir = dir
2238
2235
 
2239
2236
  if (flags.daemon) {
2237
+ if (process.platform !== 'darwin') {
2238
+ const say = (line) => process.stdout.write(`${line}\n`)
2239
+ say('--daemon installs a macOS LaunchAgent.')
2240
+ say('On Linux: create a systemd user unit running `npx ocremote --pair` (systemctl --user enable --now ocremote).')
2241
+ say('On Windows: add a Task Scheduler entry running `npx ocremote --pair` at logon.')
2242
+ say('Either way the foreground mode below works everywhere: npx ocremote --pair')
2243
+ return 1
2244
+ }
2240
2245
  const installer = path.join(HERE, 'install.sh')
2241
2246
  if (!fs.existsSync(installer)) abort(`install.sh not found next to oc-remote.mjs`)
2242
2247
  const args = [installer, '--dir', dir, '--port', String(opts.port)]
@@ -2347,21 +2352,23 @@ async function main() {
2347
2352
  info(`opencode is healthy (v${health.version})`)
2348
2353
 
2349
2354
  server = createProxyServer()
2350
- await new Promise((resolve, reject) => {
2351
- server.once('error', reject)
2352
- server.listen(opts.port, opts.host, () => {
2353
- server.off('error', reject)
2354
- resolve()
2355
+ try {
2356
+ await new Promise((resolve, reject) => {
2357
+ server.once('error', reject)
2358
+ server.listen(opts.port, opts.host, () => {
2359
+ server.off('error', reject)
2360
+ resolve()
2361
+ })
2355
2362
  })
2356
- }).catch((err) => {
2363
+ } catch (err) {
2357
2364
  error(
2358
2365
  err.code === 'EADDRINUSE'
2359
- ? `port ${opts.port} is already in use; pick another with --port`
2366
+ ? `port ${opts.port} is already in use; pick another with --port (is the companion already running?)`
2360
2367
  : `could not listen on ${opts.host}:${opts.port}: ${err.message}`
2361
2368
  )
2362
2369
  if (child && child.exitCode === null) child.kill('SIGKILL')
2363
2370
  return 1
2364
- })
2371
+ }
2365
2372
 
2366
2373
  printBanner(health)
2367
2374
  utilityServer = await createUtilityServer()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ocremote",
3
- "version": "1.3.0",
3
+ "version": "1.3.2",
4
4
  "description": "Control opencode on your computer from the OpenCode Remote iOS app: supervisor, pairing QR, relay and tunnel transports",
5
5
  "type": "module",
6
6
  "bin": {
@@ -15,10 +15,6 @@
15
15
  "engines": {
16
16
  "node": ">=20"
17
17
  },
18
- "os": [
19
- "darwin",
20
- "linux"
21
- ],
22
18
  "keywords": [
23
19
  "opencode",
24
20
  "remote",
File without changes