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

@nimrobo/superconnector

v0.2.1

Published

Agent-agnostic transport for apps to spawn, resume, and stream coding-agent sessions (Claude Code, OpenCode, Codex).

Readme

Superconnector SDK

npm version npm downloads license node

@nimrobo/superconnector — TypeScript SDK for apps that need to spawn, resume, and stream coding-agent sessions from a trusted Node runtime.

Superconnector is beta-ready for integration work. The package is currently 0.1.x, so keep adapter-specific behavior and upstream CLI changes in mind when upgrading.

Install

npm install @nimrobo/superconnector

Requirements:

  • Node.js >=20
  • A backend, CLI, Electron main process, server action, or other trusted Node runtime
  • At least one supported agent CLI installed and authenticated: Claude Code, OpenCode, or Codex

Quick Start

import { createSuperconnector } from '@nimrobo/superconnector';

const sc = createSuperconnector({
  adapter: 'claude-code',
});

for await (const msg of sc.spawn({
  prompt: 'Review this repository and summarize the highest-risk areas.',
  appId: 'my-app',
  permissionMode: 'read',
})) {
  console.log(msg.type, msg.sessionId, msg.content);
}

spawn() and resume() return AsyncIterable<AgentMessage>, which maps naturally to websockets, SSE, job logs, queues, and application stores.

Public API

Main entry point:

import {
  createSuperconnector,
  detectAdapter,
  AdapterNotSetError,
  UnknownSessionError,
  PermissionRequiredError,
  type Adapter,
  type AdapterKind,
  type AgentMessage,
  type ApprovalCallback,
  type ApprovalDecision,
  type ApprovalRequest,
  type ResumeOptions,
  type SessionRecord,
  type SpawnOptions,
  type Superconnector,
} from '@nimrobo/superconnector';

Config entry point:

import {
  globalConfigPath,
  localConfigPath,
  readConfig,
  resolveConfig,
  writeConfig,
  type SuperconnectorConfig,
} from '@nimrobo/superconnector/config';

Adapter entry points:

import { ClaudeCodeAdapter } from '@nimrobo/superconnector/adapters/claude-code';
import { OpenCodeAdapter } from '@nimrobo/superconnector/adapters/opencode';
import { CodexAdapter } from '@nimrobo/superconnector/adapters/codex';

Core types:

type AdapterKind = 'claude-code' | 'opencode' | 'codex';
type PermissionMode = 'read' | 'acceptEdits';

interface SpawnOptions {
  prompt: string;
  appId: string;
  sessionSelector?: string;
  resumeLastCreatedSession?: boolean;
  permissionMode?: PermissionMode;
  onApprovalRequest?: ApprovalCallback;
  approvalTimeoutMs?: number;
  signal?: AbortSignal;
}

interface ResumeOptions {
  prompt: string;
  appId: string;
  sessionId: string;
  sessionSelector?: string;
  permissionMode?: PermissionMode;
  onApprovalRequest?: ApprovalCallback;
  approvalTimeoutMs?: number;
  signal?: AbortSignal;
}

interface AgentMessage {
  type: 'assistant' | 'user' | 'system' | 'result' | 'tool_use' | 'tool_result' | 'superconnector';
  sessionId: string;
  content: unknown;
  raw?: unknown;
}

Creating a Connector

Use an explicit adapter when your app knows which agent runtime it is targeting:

const sc = createSuperconnector({
  adapter: 'codex',
});

Or let Superconnector use config and detection:

const sc = createSuperconnector();

By default the agent runs in process.cwd(). Pass cwd only to narrow execution to the current process directory or one of its descendants:

const sc = createSuperconnector({ cwd: 'packages/app' });

For absolute workspace paths, start the trusted Node process from that workspace root and omit cwd; explicit cwd values outside the process cwd tree are rejected.

Resolution order:

  1. explicit adapter passed to createSuperconnector()
  2. preferredAdapter from local or global config
  3. detection from project markers and available binaries

If no adapter is set or detected, getAdapter(), spawn(), and resume() throw AdapterNotSetError.

Preview the adapter

Consumer apps that need to show or confirm the runtime before starting work should call whichAdapterWillRun() with the same run-shaped options they will pass to spawn() or resume(). The preview does not start an agent and does not update session state.

import type { SpawnOptions } from '@nimrobo/superconnector';

const run = {
  prompt,
  appId: 'my-app',
  sessionSelector: workspaceId,
  resumeLastCreatedSession: true,
} satisfies SpawnOptions;

const preview = sc.whichAdapterWillRun(run);

if (!preview.ready) {
  // show adapter picker or config flow
}

console.log(preview.adapter, preview.action, preview.source);

List adapters and models

To build an adapter or model picker, query availability without starting an agent:

// One entry per built-in adapter, with detection and selection flags.
for (const a of sc.listAdapters()) {
  console.log(a.kind, a.detected, a.selected);
}

// Models for a given adapter kind (independent of the currently selected adapter).
const models = await sc.listModels('claude-code');
console.log(models.map((m) => m.id));

listAdapters() returns AdapterInfo[]detected means the adapter's project markers and binary were found for the current cwd (or an ancestor), and selected marks the adapter this Superconnector will use. listModels(kind) returns AdapterModel[] and takes the adapter kind explicitly, so it never throws AdapterNotSetError.

Sessions

Superconnector records sessions by cwd and appId. Use a stable appId for your app or feature:

const sessions = sc.listSessions({ appId: 'my-app' });

Use sessionSelector when one appId needs separate threads, workspaces, tabs, or user-visible conversations:

const sessions = sc.listSessions({
  appId: 'my-app',
  sessionSelector: workspaceId,
});

Resume an explicit session

const [latest] = sc.listSessions({ appId: 'my-app', sessionSelector: workspaceId });

if (latest) {
  for await (const msg of sc.resume({
    prompt: 'Continue from the previous result.',
    appId: latest.appId,
    sessionSelector: latest.sessionSelector,
    sessionId: latest.sessionId,
    permissionMode: 'read',
  })) {
    publish(msg);
  }
}

resume() validates that the session was recorded for the same cwd, appId, and selector. If not, it throws UnknownSessionError.

Continue the latest matching session

for await (const msg of sc.spawn({
  prompt,
  appId: 'my-app',
  sessionSelector: workspaceId,
  resumeLastCreatedSession: true,
  permissionMode: 'read',
})) {
  publish(msg);
}

resumeLastCreatedSession resumes the most recently recorded session for the same cwd, appId, and sessionSelector. If no matching session exists, it starts a new one. When sessionSelector is omitted, only unscoped sessions are considered.

Permissions and Approvals

Use permissionMode: "read" for planning, review, and analysis flows. Use permissionMode: "acceptEdits" only for workflows where the user expects file edits.

Claude Code supports approval callbacks:

for await (const msg of sc.spawn({
  prompt,
  appId: 'my-app',
  permissionMode: 'acceptEdits',
  approvalTimeoutMs: 60_000,
  onApprovalRequest: async (request) => {
    if (request.cwd !== workspaceRoot) {
      return { decision: 'deny', message: 'Workspace mismatch' };
    }

    const approved = await askUser({
      sessionId: request.sessionId,
      toolName: request.toolName,
      input: request.input,
    });

    return approved ? { decision: 'allow' } : { decision: 'deny', message: 'Denied by user' };
  },
})) {
  publish(msg);
}

Adapter limits:

  • claude-code supports Superconnector approval callbacks through an approval host.
  • opencode does not support programmatic approval callbacks; Superconnector emits an advisory superconnector event if one is provided.
  • codex exec mode rejects Superconnector approval callbacks with AdapterFailedError.

Return deny when the app cannot confidently associate an approval request with the visible user, workspace, or session.

Cancellation

const controller = new AbortController();

const run = (async () => {
  for await (const msg of sc.spawn({
    prompt,
    appId: 'my-app',
    sessionSelector: workspaceId,
    permissionMode: 'read',
    signal: controller.signal,
  })) {
    publish(msg);
  }
})();

controller.abort();
await run;

Wire the AbortSignal to your request lifecycle, job cancellation path, stop button, or process shutdown handler.

Configuration

Config can set a preferred adapter, default permission mode, and per-adapter model ids.

{
  "preferredAdapter": "claude-code",
  "permissionMode": "read",
  "models": {
    "claude-code": "sonnet",
    "opencode": "anthropic/claude-sonnet-4-5",
    "codex": "gpt-5.3-codex"
  }
}

Locations:

  • Global: ~/.superconnector/config.json
  • Local: <cwd>/.superconnector/config.json
  • Registry and session logs: ~/.superconnector
  • Override root for tests or isolated environments: SUPERCONNECTOR_HOME=/tmp/superconnector-home

Local config overrides global config. Explicit constructor options override both.

Use the companion CLI to edit config:

npx @nimrobo/superconnector-cli config

Adapter Behavior

| Adapter | Project marker | Binary | Permission mapping | | ------------- | ------------------------------ | ---------------------------- | -------------------------------------------------------------------------------------- | | claude-code | CLAUDE.md or .claude | claude or CLAUDE_BIN | read maps to Claude plan mode; acceptEdits maps to Claude accept-edits mode. | | opencode | opencode.json or .opencode | opencode or OPENCODE_BIN | read uses default run behavior; acceptEdits adds --dangerously-skip-permissions. | | codex | AGENTS.md or .codex | codex or CODEX_BIN | read maps to read-only sandbox; acceptEdits maps to workspace-write sandbox. |

Each adapter streams normalized AgentMessage objects while keeping the raw adapter message on raw when available. Treat content as adapter-shaped data and normalize it at your app boundary before storing or rendering.

Error Handling

try {
  for await (const msg of stream) {
    publish(msg);
  }
} catch (error) {
  if (error instanceof PermissionRequiredError) {
    publishError({
      code: 'permission_required',
      message: error.message,
      sessionId: error.sessionId,
      resumeCommand: error.resumeCommand,
    });
    return;
  }

  if (error instanceof UnknownSessionError) {
    publishError({ code: 'unknown_session', message: error.message });
    return;
  }

  publishError({
    code: 'agent_failed',
    message: error instanceof Error ? error.message : String(error),
  });
}

Common SDK errors:

  • AdapterNotSetError: no explicit, configured, or detected adapter.
  • UnknownSessionError: attempted to resume a session that is not recorded for the selected scope.
  • AdapterFailedError: underlying adapter process failed.
  • PermissionRequiredError: Claude Code halted on a permission request and provides a manual resume command.

Testing a Consumer App

Prefer a stub adapter for app-level tests:

import type { Adapter, AgentMessage, ResumeOptions, SpawnOptions } from '@nimrobo/superconnector';

class StubAdapter implements Adapter {
  readonly kind = 'claude-code' as const;
  spawnCalls: SpawnOptions[] = [];
  resumeCalls: ResumeOptions[] = [];

  detect(): boolean {
    return true;
  }

  spawn(opts: SpawnOptions): AsyncIterable<AgentMessage> {
    this.spawnCalls.push(opts);
    const sessionId = 'stub-session-1';
    return (async function* () {
      yield { type: 'system', sessionId, content: { started: true } };
      yield { type: 'assistant', sessionId, content: { text: 'Ready' } };
      yield { type: 'result', sessionId, content: { ok: true } };
    })();
  }

  resume(opts: ResumeOptions): AsyncIterable<AgentMessage> {
    this.resumeCalls.push(opts);
    const sessionId = opts.sessionId;
    return (async function* () {
      yield { type: 'assistant', sessionId, content: { text: 'Resumed' } };
      yield { type: 'result', sessionId, content: { ok: true } };
    })();
  }
}

Use a temporary cwd and isolated SUPERCONNECTOR_HOME per test file or case:

import { mkdirSync, mkdtempSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { createSuperconnector } from '@nimrobo/superconnector';

process.env.SUPERCONNECTOR_HOME = mkdtempSync(join(tmpdir(), 'sc-home-'));

const base = mkdtempSync(join(tmpdir(), 'sc-cwd-'));
const cwd = join(base, 'workspace');
mkdirSync(cwd);
process.chdir(base);

const sc = createSuperconnector({ cwd: 'workspace', adapter: new StubAdapter() });

License

MIT