OpenVCS SDK for npm-based plugin development.
Install this package in plugin projects, scaffold a starter plugin, and build plugin runtime assets. The SDK also exports a Node-only JSON-RPC runtime layer and shared protocol/types so plugins do not have to hand-roll stdio framing or method dispatch.
npm install --save-dev @openvcs/sdkThis package installs a local CLI command named openvcs.
One-off usage without adding to a project:
npx --package @openvcs/sdk openvcs --helpThis repository is authored in TypeScript under src/ and compiles runtime files
to bin/ and lib/.
Build the SDK:
npm run buildRun tests (builds first):
npm testRun the local CLI through npm scripts:
npm run openvcs -- --help
npm run openvcs -- build --help
npm run openvcs -- init --help
npm run openvcs -- dist --helpInteractive module plugin scaffold:
openvcs init my-pluginThe generated module template includes TypeScript and Node typings (@types/node).
Plugin IDs entered during scaffold must not be ./.. and must not contain path
separators (/ or \\).
Generated module plugins now export a declarative PluginDefinition plus an
OnPluginStart() hook that the SDK-owned bootstrap calls for them:
import type { PluginModuleDefinition } from '@openvcs/sdk/runtime';
export const PluginDefinition: PluginModuleDefinition = {
plugin: {
async 'plugin.init'(_params, context) {
context.host.info('OpenVCS plugin started');
return null;
},
},
};
export function OnPluginStart(): void {}VCS backends can also derive from VcsDelegateBase and attach exact vcs.*
delegates during startup:
import {
VcsDelegateBase,
type PluginRuntimeContext,
type PluginModuleDefinition,
} from '@openvcs/sdk/runtime';
import type { RequestParams, VcsCapabilities } from '@openvcs/sdk/types';
class ExampleVcsDelegates extends VcsDelegateBase<{ cwd: string }> {
override getCaps(
_params: RequestParams,
_context: PluginRuntimeContext,
): VcsCapabilities {
return {
commits: true,
branches: true,
tags: false,
staging: true,
push_pull: true,
fast_forward: true,
};
}
}
export const PluginDefinition: PluginModuleDefinition = {};
export function OnPluginStart(): void {
const vcs = new ExampleVcsDelegates({ cwd: process.cwd() });
PluginDefinition.vcs = vcs.toDelegates();
}Define ordinary prototype methods such as getCaps() and commitIndex() on the
subclass. toDelegates() maps those camelCase methods to the exact host method
names like vcs.get_caps and vcs.commit_index, and only registers methods
that differ from the SDK base class. Use override with the full params/context
signature so TypeScript checks your subclass against the SDK contract. Base
stubs throw through an internal never-returning helper, which is why concrete
plugins should always implement the methods they intend to expose.
The SDK enforces correct method signatures at compile time. Subclasses that
override with the wrong return type or parameter shape produce a TypeScript error.
The SDK test suite includes test/vcs-delegate-base.types.ts which explicitly
verifies that incompatible overrides (e.g. returning string instead of
VcsCapabilities) fail the compiler under @ts-expect-error. Runtime tests
in test/vcs-delegate-base.test.js cover behavior — not signatures.
Runtime and protocol imports are exposed as npm subpaths:
import { VcsDelegateBase, pluginError } from '@openvcs/sdk/runtime';
import type { PluginDelegates, VcsDelegates } from '@openvcs/sdk/types';The runtime handles stdio framing, JSON-RPC request dispatch, host notifications,
default plugin.* handlers, exact-method delegate registration for vcs.*, and
the generated bin/<module.exec> bootstrap created by openvcs build.
Interactive theme plugin scaffold:
openvcs init --theme my-themeIn a generated code plugin folder:
npm run buildThis runs openvcs build, which executes scripts["build:plugin"], expects your
compiled plugin author module at bin/plugin.js, and then generates the SDK-owned
bin/<module.exec> bootstrap that imports ./plugin.js, applies PluginDefinition,
invokes OnPluginStart(), and starts the runtime.
Theme-only plugins can also run npm run build; the command exits successfully
without producing bin/ output.
Generated code plugin scripts use this split by default:
{
"scripts": {
"build:plugin": "tsc -p tsconfig.json",
"build": "openvcs build",
"test": "npm run build"
}
}For code plugins, reserve bin/plugin.js for the compiled author module and point
module.exec at a different bootstrap filename such as openvcs-plugin.js.
Plugin package contents should include:
package.jsonwith anopenvcsobject (required)icon.*(optional, first found by extension priority)bin/(required for code plugins withmodule.exec)entrydirectory (required for UI plugins with top-levelentryfield; the entire directory containing the entry file is bundled)themes/(required for theme plugins)- runtime dependencies installable from
dependencies
Dependency behavior:
- OpenVCS installs runtime dependencies from
dependencieswhen resolving a plugin source. - Keep runtime-only packages out of
devDependencies. - Native Node addons (
*.node) are not portable and should be avoided.
Build a plugin manually:
npx openvcs build --plugin-dir /path/to/pluginShow command help:
npx openvcs --help
npx openvcs build --help
npx openvcs init --helpPublishing is outside the SDK CLI. Use your normal npm workflow once openvcs build
has produced the runtime assets you want to ship.
CI release channels can publish prereleases to npm using dist-tags:
latest: stable releasesbeta: builds from theBetabranchedge: working builds fromDevpush commitsnightly: scheduled builds fromDevwhen there are changes since the last nightly
Examples:
npm install @openvcs/sdk@edge
npm install @openvcs/sdk@beta
npm install @openvcs/sdk@nightlyCopyright © 2025-2026 OpenVCS Contributors. SPDX-License-Identifier: GPL-3.0-or-later