@seastudio/sdk
v8.2.0
Published
SeaStudio SDK - plugin runtime contracts, host-tool communication, MCP, and artifact tooling
Downloads
3,676
Readme
@seastudio/sdk
SeaStudio public SDK for plugin runtime contracts, MessagePort Plugin Host RPC, genuine MCP contracts, and artifact tooling.
Install
pnpm add @seastudio/sdkPublic Entry Points
| Path | Purpose |
| --- | --- |
| @seastudio/sdk | MCP protocol and client primitives |
| @seastudio/sdk/mcp | Transport-agnostic MCP protocol and client primitives |
| @seastudio/sdk/mcp/core | JSON-RPC/MCP primitives |
| @seastudio/sdk/plugin | Codex-aligned plugin manifest and mention helpers plus SeaStudio host extensions |
| @seastudio/sdk/plugin-host | MessagePort RPC, connection API, host facade, events, and DTOs |
| @seastudio/sdk/plugin-shell | Dedicated mounted plugin terminal lifecycle and stream contracts |
| @seastudio/sdk/plugin-artifact | Plugin artifact validation |
| @seastudio/sdk/desktop-cli | Desktop local CLI socket client |
Authentication Session Contract
Mounted Plugin Views can subscribe to host-owned authentication session state without receiving SeaArt tokens.
import { HostEvents, type AuthSessionChangedParams } from '@seastudio/sdk/plugin-host';
host.on(HostEvents.AUTH_SESSION_CHANGED, (params) => {
const { event, session } = params as AuthSessionChangedParams;
console.log(event, session.status, session.user?.id);
});AuthSessionChangedParams.session contains only status and a minimal user DTO. Access tokens, SDK tokens, cookies, and provider credentials are never part of this public SDK contract.
Cloud-Embedded Plugin Host
Cloud-Embedded Plugins use the additive protocol-1 embed contract. A standalone Web parent listens for connections and supplies the current token from its own authentication store:
import { listenForEmbeddedPlugin } from '@seastudio/sdk/plugin-host';
const embedded = listenForEmbeddedPlugin({
guest: iframe.contentWindow!,
guestOrigin: 'https://plugin.example.com',
bootstrap: () => ({
token: currentToken,
platform: 'web',
locale: 'en-US',
theme: 'system',
capabilities: ['project'],
}),
});
auth.onTokenChanged((token) => embedded.notifyTokenChanged(token));Mounted Desktop plugins use the SeaStudioHost already returned by
connectToSeaStudio. It structurally exposes EmbeddedPluginHostV1; embedded
bootstrap and token notifications share the existing protocol-2 RpcPeer and
do not open a second MessageChannel:
const host = await connectToSeaStudio({
parentOrigin: 'https://desktop.example.com',
});
const bootstrap = await host.bootstrap();
const tokenSubscription = host.onTokenChanged((token) => {
apiClient.setToken(token);
});A standalone Web iframe connects and bootstraps through its protocol-1
transferred MessagePort:
import { connectToEmbeddedPluginHost } from '@seastudio/sdk/plugin-host';
const connection = await connectToEmbeddedPluginHost({
parentOrigin: 'https://app.example.com',
});
const bootstrap = await connection.bootstrap();
const tokenSubscription = connection.onTokenChanged((token) => {
apiClient.setToken(token);
});The SDK keeps no token state. Refresh and sign-out are port notifications, with
sign-out represented by null; closing a port is not sign-out. Every mounted or
standalone reconnect creates a fresh peer and must call bootstrap() to read
current host state. Standalone bootstrap validates source and origin, uses distinct
seastudio:embedded-plugin:* messages, and never requires BroadcastChannel.
Product project repositories and Cloud API gateways remain product-owned.
MCP Tools
@seastudio/sdk/mcp is reserved for genuine MCP and JSON-RPC contracts. MCP clients
require an explicit transport supplied by an stdio or HTTP implementation. Mounted
Plugin Views do not use MCP.
import { MCPClient } from '@seastudio/sdk/mcp';
const client = new MCPClient({ transport: stdioOrHttpTransport });
await client.callTool('independent-server-tool', { input: 'value' });Plugin Host Services
import { connectToSeaStudio, relativePath } from '@seastudio/sdk/plugin-host';
const host = await connectToSeaStudio({
parentOrigin: 'https://desktop.example.com',
tools: {
selection_read: async ({ path }) => ({ path, text: 'selected text' }),
},
});
const [root] = await host.roots.list();
const file = await host.filesystem.read({
root: root.id,
path: relativePath('notes.md'),
encoding: 'utf8',
});File-backed Plugin Views register their document endpoint while the shared RPC peer
is created. The endpoint is ready as soon as connectToSeaStudio resolves, and its
context carries the existing peer cancellation signal:
const host = await connectToSeaStudio({
parentOrigin: 'https://desktop.example.com',
documents: {
async open({ rootId, path }, context) {
const document = await loadDocument(rootId, path, { signal: context?.signal });
if (!document) return { status: 'rejected', code: 'DOCUMENT_NOT_FOUND' };
applyDocument(document);
return { status: 'applied' };
},
},
});Desktop invokes this handler as documents.open through the same RpcPeer, using
requestDocumentOpen for a typed request. rootId is opaque and path is relative;
neither is added to the connect envelope or interpreted as a URL. Both directions
validate an exact request object and an exact applied or rejected result. Rejection
codes are non-empty, Plugin-owned strings with an optional message. The SDK does not own
dirty, recovery, format, save, or conflict semantics. Cancellation and superseded work
stay in RpcPeer/local stale handling and are not document rejection codes.
The plugin sends one seastudio:connect window message (protocol version + sorted
toolNames). Desktop must already be listening (host installs the listener before
iframe paint) and responds with one transferred MessagePort. Residual connect
posts are ignored while that peer is live. All further requests, responses, and
notifications use that port. Use createHostSession for guest-side single-flight
connect and one reconnect after RpcError CLOSED. The session remains lazy and does
not actively reconnect; close() also aborts an in-flight connect wait.
Bootstrap validates the parent window and origin when available. Requests use
explicit methods such as hostService/filesystemRead; they never use MCP
tools/call. Roots are opaque capabilities and every filesystem path is relative
to one. Filesystem and Git results carry revisions for ordering and optimistic
concurrency. There are no V6 aliases, ambient workspace roots, absolute host
filesystem operations, transfer/clipboard helpers, or raw service facade.
pluginContext paths are dedicated inputs for the local process contract.
commandSession remains a PTY compatibility surface for terminal automation; local plugin processes should
use the structured process API described in
Plugin Local Processes.
Chinese integration guide: SeaStudio 插件本地后台进程接入指南.
3DTools native save and system file manager migration:
3DTools 原生保存与系统文件管理器迁移指南.
RpcPeer implements the same wire for Desktop: request { id, method, params? },
response { id, result } or { id, error }, and notification { method, params? }.
Either side may issue requests. Protocol version and toolNames are negotiated only
on the bootstrap window messages, not on the MessagePort itself.
Terminal access is intentionally separate:
import { TerminalClient } from '@seastudio/sdk/plugin-shell';
const terminal = new TerminalClient(host);
terminal.open({ root: root.id, cols: 120, rows: 32 });The plugin-shell contract only supports open, attach, write, resize, and close,
plus sequenced data and exit events. ownerLease rejects stale terminal owners;
sequence orders replayed and live output. It is not a generic terminal service.
Plugin artifacts declare tools on the view that provides them:
{
"seastudio": {
"views": [{
"id": "workspace",
"tools": [{
"name": "selection_read",
"description": "Read the active selection.",
"inputSchema": { "type": "object", "properties": {} }
}]
}]
}
}Desktop invokes these handlers as tools.<name> through the same RPC peer.
Plugins that bundle a local Node companion process should declare its directory
under seastudio.resources and launch it through host.process. Desktop supplies
paths and a host Node process primitive only; the plugin owns health checks,
heartbeats, restart decisions, and shutdown. See
Plugin Local Processes for the complete contract
and migration guide.
Artifact CLI
Build upload-ready ZIP archives without supplying catalog IDs or versions on the command line:
npx seastudio-artifact plugin pack --dir=. --out=plugin.zip
npx seastudio-artifact skill pack --dir=. --out=skill.zipPlugin identity and version come from .codex-plugin/plugin.json. Skill identity and version come
from the name and version fields in SKILL.md frontmatter. Use verify-dir or verify-archive
in place of pack to validate an existing project or ZIP.
The same pack and verify operations are exported from @seastudio/sdk/plugin-artifact
for Node callers. They run in-process and do not spawn seastudio-artifact.
Desktop Development CLI
Sync a local plugin or skill into a running SeaStudio Desktop instance, or remove its development copy:
npx seastudio plugin install --dir=.
npx seastudio plugin remove --dir=.
npx seastudio skill install --dir=.
npx seastudio skill remove --dir=.--dir defaults to the current directory. Plugin sync runs the build script in
frontend/package.json first. When that file declares packageManager, the CLI
runs it through Corepack; otherwise it uses npm run build. Skill sync packs the
skill directory directly. Sync archives are temporary and are deleted only after
Desktop responds.
Desktop must be running. The CLI uses one newline-delimited JSON request and
response over \\.\pipe\seastudio-cli-v1 on Windows or
the OS temporary directory at seastudio-cli-v1.sock on POSIX. This is a local
socket protocol; no HTTP service is involved.
UI Boundary
First-party product styling and primitives live in the separate @seastudio/ui
package. This SDK intentionally has no React, Tailwind, icon, or stylesheet
exports.
Development
pnpm install --frozen-lockfile
pnpm build
pnpm release:packdist/ is build output only. It is not committed; pnpm build (also via prepare) regenerates it. Published packages still ship dist/ inside the npm tarball. Prefer npm versions over git commit pins for consumers.
pnpm release:pack builds the SDK, creates the exact npm tarball, and verifies the public contract exports before a release can publish.
Release Policy
@seastudio/sdk is the public contract consumed by SeaStudio hosts and plugins. The current major is 8.x. Version 8.2 deprecates the per-tool deferLoading manifest field: Desktop owns the convention that every Plugin tool is deferred, so the field is accepted but ignored and no longer participates in the tool contract digest. It will be removed in the next major. Version 8.0 replaced the 7.x Git source / ref / focus and patch-shaped diff contracts with structured GitFileVersion identities and provides no compatibility aliases for those removed contracts. New plugin-facing events, DTOs, tools, or exported types require a semver version bump and a release through GitLab CI. Breaking changes require a major version bump.
Releases are made from protected tags named sdk-v<version>, for example:
git tag -a sdk-v8.2.0 -m "Release @seastudio/sdk 8.2.0"
git push origin sdk-v8.2.0Protected sdk-v* tags automatically run verify:release-artifact and then
publish:npm. The publish job uses the verified tarball plus a protected,
masked NPM_TOKEN CI variable. The token must be an npm granular access token
scoped to @seastudio/sdk publish access and configured to bypass 2FA for CI
publishing.
Do not configure publish:npm as a GitLab manual job or protected environment
deployment. The release gate is the protected sdk-v* tag plus the protected
NPM_TOKEN; adding an environment approval reintroduces the same human-click
path that CI publishing is meant to remove.
Do not publish this package from a personal shell as the normal release path.
The package prepublishOnly hook enforces this: local npm publish/pnpm publish
fails before contacting npm, so it cannot fall through to an interactive 2FA OTP
prompt. Use pnpm release:pack for local artifact verification and GitLab CI for
publishing.
