npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@openclient-ios/opencode-plugin

v0.4.2

Published

Connect OpenCode to the OpenClient iOS app for native tools, visuals, and in-app browser automation.

Readme

OpenClient Plugin

Connect OpenCode to the OpenClient iOS app for native tools, declarative visuals, in-app browser automation, and optional OC Notify notifications.

Install

Version 0.4.2 supports OpenCode V1 1.18.29+ and V2. Both hosts load the same package and choose their native entry point automatically: V1 calls server(), while V2 calls setup(). No version-mode option is needed.

OpenCode V2

Add the plugin to opencode.json(c):

{
  "$schema": "https://opencode.ai/config.json",
  "plugins": ["@openclient-ios/[email protected]"]
}

For a managed background service, run opencode service status and set the returned server origin explicitly using the options example below.

OpenCode V1

V1 uses plugin (singular):

{
  "$schema": "https://opencode.ai/config.json",
  "plugin": ["@openclient-ios/[email protected]"]
}

The plugin includes OC Notify. To enable notifications on V1, replace the plugin entry with the options form:

{
  "$schema": "https://opencode.ai/config.json",
  "plugin": [
    ["@openclient-ios/[email protected]", {
      "notifications": {
        "enabled": true,
        "publicOrigin": "https://notify.example.com",
        "port": 4319,
        "dataDir": "/absolute/path/to/notification-state"
      }
    }]
  ]
}

Restart V1 after changing plugin configuration. V2 supports configuration reload; changes to local dependencies may still require opencode service restart.

The OpenClient iOS app discovers the bridge on the connected OpenCode host and advertises the native tools supported by that app build.

For repository development, run npm run clean && npm run build and replace the npm entry with file:///absolute/path/to/OpenClientPlugin/dist on V2, or file:///absolute/path/to/OpenClientPlugin/dist/index.js on V1. Do not also load the old npm entry or the standalone notification adapter. OpenCode must be restarted after changing plugin code or configuration.

Reverse proxies and Tailscale Serve

Bridge discovery matches the advertised OpenCode port to the port in the app's server URL. If a proxy forwards https://host.tailnet.ts.net (port 443) to OpenCode on port 4096, set serverURL to https://host.tailnet.ts.net. This option supports both V1 and V2; V1 support requires plugin 0.4.2 or later.

For V1, add the option to the plugin tuple:

{
  "plugin": [
    ["@openclient-ios/[email protected]", {
      "serverURL": "https://host.tailnet.ts.net"
    }]
  ]
}

Restart OpenCode after updating the plugin configuration. For V2, put the same serverURL in the options object shown below. Use an HTTP(S) origin without credentials, a path, query, or fragment; include any custom external port. The override also supplies the OpenCode origin used by notifications.

The app still reaches the bridge directly on the server hostname at ports 4070...4090 over HTTP/WebSocket, so those ports must be reachable through your trusted network. Proxying the OpenCode port alone does not proxy the bridge. When running multiple servers on one hostname, give each a distinct external port so discovery can distinguish their bridges.

V2 options

V2 uses plugins and an object for package options (rather than v1's plugin and tuple). For example, to configure the server origin and optional notifications:

{
  "$schema": "https://opencode.ai/config.json",
  "plugins": [{
    "package": "@openclient-ios/[email protected]",
    "options": {
      "serverURL": "http://127.0.0.1:4096",
      "notifications": {
        "enabled": true,
        "publicOrigin": "https://notify-v2.example.com",
        "port": 4321,
        "dataDir": "/absolute/path/to/v2-notification-state"
      }
    }
  }]
}

When running multiple servers on one machine, use distinct notification ports, HTTPS origins, and data directories. Bridge ports are selected automatically. V2 does not expose its listening URL to plugins, so the bridge uses the host's serve --port / --port= argument, or OPENCODE_SERVER_PORT. Embedded hosts without these must set the serverURL origin in plugin options. Replace the example port with the actual port from opencode service status; managed services do not necessarily listen on 4096.

V2 tools use native tool-registration permissions, JSON Schema, structured output, and the session's canonical location. Current v2 passes cancellation signals for tool execution; older previews without those signals can only cancel outstanding device requests when the plugin unloads. Notifications normalize v2 forms and events into the shared notification lifecycle.

The first feature is a dual-stack WebSocket bridge that binds the first available port in 4070...4090 on all IPv4 and IPv6 interfaces. It exposes two OpenCode tools:

  • openclient_get_tool_list
  • openclient_execute_tool

The bridge intentionally has no application-layer authentication or encryption. Run it only on a host whose network access is already restricted by a Tailnet, VPN, firewall, or equivalent trusted-network architecture. Do not expose ports 4070...4090 directly to the public internet.

Endpoints:

  • GET /openclient/v1/health
  • POST /openclient/v1/notifications/setup
  • GET /openclient/v1/ws
  • GET /openclient/v1/image/resources/:resourceID/content
  • POST /openclient/v1/video/resources/:resourceID/stream
  • DELETE /openclient/v1/video/resources/:resourceID/stream
  • DELETE /openclient/v1/video/streams/:streamID
  • GET /openclient/v1/video/streams/:streamID/playlist.m3u8
  • GET /openclient/v1/video/streams/:streamID/{init.mp4,segment-NNNNNN.m4s}

Notifications are disabled by default. When enabled, publicOrigin is required and must be a path-free HTTPS origin. The PWA listens only on 127.0.0.1 at port (default 4319). dataDir defaults to $XDG_STATE_HOME/opencode/openclient/notifications or ~/.local/state/opencode/openclient/notifications; configure an absolute path when migrating existing OC Notify state.

For migration, stop the old standalone OC Notify process before starting the plugin so it releases the PWA port and data directory. Use the exact same absolute dataDir in the plugin options and every pairing command; do not rely on npm run pair defaults for an existing prototype .data directory. Perform the final controlled restart only when active OpenCode work can be interrupted.

The native setup endpoint creates a one-use, 10-minute connection-prefill code. It does not itself pair a browser or opt into activity notifications. Current OpenClient builds launch the bundled pairing CLI through an OpenCode PTY and copy one short-lived setup payload. The browser shows installation instructions; the Home Screen PWA's Paste Setup from OpenClient pairs and saves the connection. Notification permission and activity opt-in remain explicit.

For manual diagnostics, generate a pairing code with:

npm exec --package=@openclient-ios/[email protected] -- openclient-notify pair --data-dir /absolute/path/to/notification-state

For the repository prototype state, the explicit command is:

npm exec --package=@openclient-ios/[email protected] -- openclient-notify pair --data-dir /absolute/path/to/NotificationPWA/.data

openclient_visual_image accepts an absolute path to a readable regular JPEG, PNG, or WebP file up to 20 MiB. Tool execution canonicalizes and validates the source, then creates an opaque image resource. The persisted visual payload contains dimensions, bounded file metadata, an opaque content path, and a JPEG preview no larger than 96 px on either side or 32 KiB decoded. It does not contain the original image bytes or source path. A content GET revalidates the source identity and returns the original bytes with the exact image content type, nosniff, and private no-store caching.

openclient_visual_video accepts an absolute path to a readable regular MP4 file. Tool execution creates a dormant opaque resource and persists coded width, height, clockwise rotation (degrees), duration (seconds), and a bounded JPEG cover generated from the first frame. HLS preparation remains lazy and begins only after a playback POST.

Image and video resources use rolling 30-day retention and survive plugin and OpenCode restarts in private 0600 registries under ~/.local/state/opencode/openclient/{image,video}-resources-<port>.json (or the equivalent XDG_STATE_HOME path). Registry and temporary-media directories are forced to mode 0700. Each service retains at most 128 least-recently-used resources. Before content loading or playback, the plugin verifies that the source is still the same regular file by checking its canonical path, device, inode, size, and modification time.

The source path never appears in declarative result metadata or an HTTP route. It is still an argument to openclient_execute_tool, so OpenCode persists the original filePath with the tool invocation in session history and may expose the canonical path in permission details. This capability does not make the input path private from OpenCode itself.

Resource creation runs ffprobe and preview ffmpeg against an identity-validated open file descriptor on supported platforms, never against the user-provided path. Invalid or oversized previews reject resource creation.

Each playback POST starts an independent ffmpeg stream-copy fragmented MP4 HLS lease; dismissing that player deletes only its stream. Active streams and generated HLS media remain in a private temporary directory and are removed at shutdown. Media stays on the bridge HTTP port and is never sent through the WebSocket protocol. Video sources are limited to 20 GiB and playback to three concurrent streams. Image and video tools require ffmpeg and ffprobe in the plugin process PATH.

Development

npm install
npm run check
npm run build

The default export in src/index.ts contains both host entry points. V1 returns its tools/hooks from server; src/v2.ts registers the shared tools and event adapter through the v2 context. Keep host-specific translation at this boundary.

Validate the exact package contents without publishing:

npm run pack:check

Publishers can release the current package version with:

npm run distribute

On the OpenClient release Mac, this command reads the npm token from the openclient-npm-publish service in macOS Keychain and provides it only to the npm publish subprocess. Publishing requires an npm account with write access to the @openclient-ios scope.

Plugin documentation: https://opencode.ai/v2/docs/build/plugins