☰
Netcatty 插件开发实战:以 Hello Netcatty 示例掌握插件清单、运行时 SDK 与终端 Provider 机制
2026/10/9 4:09:07 网站建设 项目流程

【免费下载链接】Netcatty

SSH workspace, SFTP, and terminals in one

项目地址:https://gitcode.com/gh_mirrors/net/Netcatty
点击查看免费下载

导读

Netcatty 是集 SSH 工作区、SFTP 与终端于一体的桌面应用,其插件平台为开发者提供了在沙箱化运行时中扩展原生设置、命令面板、终端补全与高亮等能力的安全通道。本文以仓库内可直接运行的官方示例 examples/plugins/hello-netcatty/README.md 为核心,完整讲解插件的构建校验打包流程、netcatty.plugin.json清单的每个字段、definePlugin入口的注册方式,以及终端 completion / decoration / theme 三类 Provider 的底层契约。读完本文,你将能独立完成一个 Netcatty 插件从零到安装验证的全过程,并理解其安全边界与权限模型的设计意图。


一、Hello Netcatty:一个可运行的插件 API 全景示例

hello-netcatty是 Netcatty 仓库为插件 API 提供的内置可运行示例。它体积虽小,却覆盖了插件平台的核心能力面:

  • 原生设置(native settings):通过清单contributes.settings声明一个Greeting设置项,插件运行时经宿主 settings broker 读写;
  • 命令面板贡献(command-palette contributions):注册Examples: Say Hello命令并在命令面板中放置入口;
  • 惰性激活(lazy activation):命令与 Provider 均通过activationEvents声明式激活,插件在真正被调用前不会启动;
  • 本地化(localization):清单中的displayName同时提供en与zh-CN两个语言版本;
  • 终端 Provider(terminal Providers):注册补全、装饰与主题三类 Provider;
  • 运行时 SDK:使用 @netcatty/plugin-sdk 导出的definePlugin、PluginContext等类型化 API。

从根目录执行的构建命令可见,示例插件被纳入仓库统一构建管线:根 package.json 中build:plugin-packages依次执行合约生成、运行时依赖构建,然后通过npm run build --workspace @netcatty/example-hello-plugin调用示例自身的tsc编译。


二、构建、校验、兼容性检查与打包

2.1 构建插件包

仓库根 package.json 提供了聚合构建脚本:

npm run build:plugin-packages

该命令会先生成插件合约与运行时依赖,再构建@netcatty/example-hello-plugin工作区。示例自身的 package.json 中build脚本为tsc -p tsconfig.json,其 tsconfig.json 采用ES2022、NodeNext模块解析与strict模式,输出到dist/目录。

2.2 使用 netcatty-plugin CLI 验证与打包

仓库内置于 packages/plugin-cli/src/cli.ts 的netcatty-plugin命令行工具支持五个子命令:

命令说明
init在指定目录初始化一个新插件项目,需--id <reverse.dns.id>,可选--name
validate校验插件目录或.ncpkg包的清单与结构
compatibility检查插件与指定 Netcatty 版本的兼容性,需--netcatty <version>
build编译插件源码
pack打包为.ncpkg安装包

README 中给出的完整操作序列为:

npm run build:plugin-packages npm exec -- netcatty-plugin validate examples/plugins/hello-netcatty npm exec -- netcatty-plugin compatibility examples/plugins/hello-netcatty --netcatty 0.0.0 npm exec -- netcatty-plugin pack examples/plugins/hello-netcatty --out /tmp/hello-netcatty.ncpkg

各步骤含义如下:

  • validate:对插件目录执行清单语义、路径安全、资源引用等校验(从 cli.ts 的validateTarget调用可知,通过后会输出Valid <kind>: <id>@<version>);
  • compatibility:将插件清单与目标 Netcatty 版本及 API 版本做引擎匹配(checkPluginCompatibility),兼容时输出Compatible: <id>@<version>与启用的特性列表;不兼容则以错误形式列出全部原因并退出码 1;
  • pack:将插件归档为.ncpkg包,输出文件数与 SHA-256 摘要。示例中输出到/tmp/hello-netcatty.ncpkg。

2.3 安装与激活的前置条件

hello-netcatty的 README 明确说明:需要以NETCATTY_PLUGIN_DEV=1环境变量运行 Netcatty,才能打包并安装插件。这与插件平台的开发门禁一致——docs/plugin-platform/isolated-runtime.md 指出,整个插件宿主当前处于0.1.0-internal内部预览阶段,运行时完全隐藏在NETCATTY_PLUGIN_DEV=1之后,目前尚不存在生产环境的插件入口。


三、插件清单逐字段剖析

插件的声明式契约全部位于 netcatty.plugin.json,它通过$schema引用 packages/plugin-contract/schema/plugin-contract.schema.json 定义的规范。

3.1 身份与元信息

{ "$schema": "../../../packages/plugin-contract/schema/plugin-contract.schema.json", "manifestVersion": 1, "id": "com.netcatty.hello", "name": "hello-netcatty", "displayName": { "en": "Hello Netcatty", "zh-CN": "你好,Netcatty" }, "description": "Minimal plugin contract and SDK example.", "version": "0.1.0", "publisher": "netcatty", "license": "GPL-3.0-or-later" }
  • id采用反向 DNS 命名空间,是插件在安装数据库与运行时中的唯一标识;
  • displayName按语言键提供本地化文案,这正是 README 提到的 localization 能力;
  • license声明插件的开源许可。

3.2 引擎约束

"engines": { "netcatty": ">=0.0.0", "api": ">=0.1.0-internal <0.2.0" }

engines.netcatty约束宿主版本,engines.api约束插件 API 版本区间,是compatibility子命令的判定依据。

3.3 入口与激活事件

"main": { "browser": "dist/index.js" }, "activationEvents": [ "onCommand:com.netcatty.hello.sayHello", "onProvider:com.netcatty.hello.completion", "onProvider:com.netcatty.hello.decoration", "onProvider:com.netcatty.hello.theme" ]
  • main.browser指向编译产物dist/index.js,说明本插件采用浏览器运行时(Node 入口可通过main.node声明);
  • activationEvents声明式地列出激活条件:命令被调用时(onCommand:)或 Provider 首次被请求时(onProvider:)才激活插件,实现 README 所说的惰性激活。

3.4 权限声明

"permissions": { "required": [ "commands", "settings.read", "menus", "provider.terminal", "terminal.complete", "terminal.output", "terminal.decorate" ], "optional": [] }

required中的权限在安装即授予,optional则会在首次使用时弹出提示(docs/plugin-platform/terminal-providers.md 中说明必需授权会被复用、可选声明在首次使用时提示,拒绝/取消则不会把终端数据交给运行时)。这里provider.terminal与terminal.*系列权限共同构成终端 Provider 的最小权限集合。

3.5 contributes:设置、命令、菜单与 Provider

"contributes": { "settings": [ { "id": "com.netcatty.hello.greeting", "label": "Greeting", "description": "Text used by the example command.", "control": "text", "scope": "application", "default": "Hello from Netcatty" } ], "commands": [ { "id": "com.netcatty.hello.sayHello", "title": "Say Hello", "category": "Examples" } ], "menus": [ { "command": "com.netcatty.hello.sayHello", "location": "commandPalette", "group": "examples", "order": 10 } ], "providers": [ { "id": "com.netcatty.hello.completion", "label": "Hello completion", "description": "Suggests the example hello command.", "kind": "terminal.completion" }, { "id": "com.netcatty.hello.decoration", "label": "Hello decoration", "description": "Highlights the example greeting in terminal output.", "kind": "terminal.decoration" }, { "id": "com.netcatty.hello.theme", "label": "Hello theme", "description": "Adds a subtle cursor color to the example terminal theme.", "kind": "terminal.theme" } ] }

要点:

  • settings:com.netcatty.hello.greeting为text控件、application作用域,默认值Hello from Netcatty,对应 README 中"在 Settings → Plugins 下修改 Greeting"的入口;
  • commands + menus:Say Hello命令被放置到commandPalette位置,分组examples、排序 10,即 README 中从命令面板执行Examples: Say Hello的来源;
  • providers:三个 Provider 的kind分别对应terminal.completion、terminal.decoration、terminal.theme,id与激活事件中的onProvider:一一对应。

四、插件入口与运行时 SDK 解析

插件入口 src/index.ts 是理解 SDK 用法的核心样本。

4.1 definePlugin 与 activate

import { definePlugin } from "@netcatty/plugin-sdk"; export default definePlugin({ activate(context) { context.logger.info("Hello Netcatty example activated", { pluginId: context.pluginId, }); // ... }, });

definePlugin来自 packages/plugin-sdk/src/index.ts,只是一个类型安全的恒等包装,让插件对象获得完整的类型推导。activate(context)是运行时生命周期入口,context为PluginContext,其中包含:

  • pluginId、netcattyVersion、apiVersion:插件与宿主版本标识;
  • subscriptions:DisposableStore,统一管理注册资源的释放(SDK 中该实现会在插件停用时批量dispose);
  • settings:PluginSettings,提供get/update/onDidChange,即 README 所说的 host settings broker;
  • commands:PluginCommands,registerCommand/executeCommand;
  • providers:PluginProviders,register(providerId, kind, handler);
  • logger:PluginLogger,带结构化字段的debug/info/warn/error。

4.2 注册命令并读取设置

context.subscriptions.add(context.commands.registerCommand( "com.netcatty.hello.sayHello", async () => { const greeting = await context.settings.get<string>("com.netcatty.hello.greeting"); context.logger.info(greeting ?? "Hello from Netcatty"); return { greeting: greeting ?? "Hello from Netcatty" }; }, ));

命令 ID 与清单contributes.commands一致。处理器通过settings.get<string>(...)从宿主设置代理读取Greeting设置——这正是 README 所述"设置经由宿主 settings broker 读取、命令处理器注册在沙箱化插件运行时内部"的机制。返回值为 JSON 值,可被宿主用于 UI 反馈。

4.3 注册终端补全 Provider

context.subscriptions.add(context.providers.register( "com.netcatty.hello.completion", "terminal.completion", ({ payload }) => { const { input } = payload; return input && "netcatty-hello".startsWith(input) ? { items: [{ text: "netcatty-hello", score: 5_000 }] } : { items: [] }; }, ));

补全 Provider 接收TerminalCompletionPayload(packages/plugin-sdk/src/index.ts),其中input是当前提示符输入片段、cursor为光标位置、hostOs标识宿主操作系统、maximum为宿主给出的结果数量上限。返回TerminalCompletionResult,其items为TerminalCompletionItem[],每项含text、可选displayText/description与score排序分。README 中"在 shell 提示符输入netc即可触发该补全 Provider"正是此逻辑:输入前缀与netcatty-hello匹配时返回高优先级建议。

4.4 注册装饰 Provider

context.subscriptions.add(context.providers.register( "com.netcatty.hello.decoration", "terminal.decoration", () => ({ rules: [{ id: "greeting", label: "Netcatty greeting", patterns: ["\\bHello from Netcatty\\b"], color: "#34D399", }], }), ));

装饰 Provider 只返回声明式规则(TerminalDecorationRule:id、label、patterns正则数组与color十六进制色值),绝不涉及 xterm 对象或原始输出流。宿主侧会限制规则数量与字符串长度、校验颜色必须为显式 hex 值、拒绝不支持的表达式,并用线性时间 RE2JS 引擎编译执行(详见 docs/plugin-platform/terminal-providers.md)。装饰结果在 Provider 扇出后还会被再次限流:最多 16 条活动规则、32 个总模式,每段文本最多匹配前 4096 个字符、每次终端写入最多保留 256 个插件匹配。README 中"在终端打印Hello from Netcatty以触发装饰高亮"即为验证该规则的实操步骤。

4.5 注册主题 Provider

context.subscriptions.add(context.providers.register( "com.netcatty.hello.theme", "terminal.theme", () => ({ colors: { cursor: "#34D399" } }), ));

主题 Provider 接收当前宿主完整调色板(TerminalThemePayload.currentTheme),返回有界的部分调色板(TerminalThemeResult.colors,键为TerminalThemeColorName联合类型,如background/foreground/cursor/selection与 16 色)。多个主题 Provider 按确定性优先级顺序合并,每色取第一个值,宿主颜色对缺省值保持权威。


五、终端 Provider 的底层契约与安全边界

5.1 一次调用会得到什么

从 docs/plugin-platform/terminal-providers.md 可以确认,普通终端 Provider 每次调用收到的都是不可变的会话快照(session:会话/主机/工作区 ID、协议、连接状态、cwd、标题、shell 类型、尺寸与备用屏幕状态),加上该 Provider 类型的专用负载。SDK 中所有 Provider 类型均有精确的负载/结果映射(OrdinaryTerminalProviderPayloadByKind/ResultByKind/OperationByKind,见 packages/plugin-sdk/src/index.ts),涵盖 completion、decoration、link、hover、matcher、semantic、prompt、background、theme 共九种普通 Provider 类型。

5.2 不会得到什么

README 特别强调:两类 Provider 都不会收到原始 xterm 对象,也不会收到敏感的终端输入/输出流。这与平台设计一致——普通 Provider 路径刻意省略命令文本、密码/提示内容、原始终端输出、xterm 对象、后端句柄与 terminal-worker 端口。只有在provider.terminal与terminal.intercept.input/terminal.intercept.output双权限下,高级工具运行时才能走独立的 MessagePort 快速通道处理原始字节拦截,且该通道还有 4ms 输入 / 50ms 输出截止、256 KiB 排队窗口与熔断机制等约束。此外,宿主标记为敏感/不回显的输入(如密码提示状态期间的每个字符)会在缓冲区创建前绕过该通道,插件无法接触凭据。

5.3 截止时间与并发控制

  • 普通终端 Provider 请求默认 1.5 秒截止;自动补全使用更短的 750ms 运行时截止加上 800ms 渲染器端到端等待上限(覆盖惰性激活与首次授权);
  • 同一会话、同一 Provider 类型同时只允许一个活动请求,新请求会取消并抑制旧结果;
  • 一次扇出最多调用前 32 个按确定性顺序排列的 Provider;单个渲染器最多保留 64 个活动终端请求;
  • 控制面 JSON 预算为 1 MiB,每个终端 Provider 的负载与结果额外限制为 128 KiB。

六、安装后的端到端验证

README 给出的验证路径非常具体,安装完成后按序执行即可:

  1. 修改 Greeting 设置:进入Settings → Plugins,将Greeting改为自定义文案。该设置经宿主 settings broker 持久化,插件通过context.settings.get("com.netcatty.hello.greeting")读取;
  2. 执行命令:打开命令面板运行Examples: Say Hello。命令处理器注册在沙箱化插件运行时内,日志中会输出当前 Greeting 值(缺省回退为Hello from Netcatty);
  3. 验证补全:在任意 shell 提示符输入netc,应看到补全建议netcatty-hello(对应"netcatty-hello".startsWith(input)的匹配逻辑);
  4. 验证装饰:在终端打印Hello from Netcatty,该文本会被声明式规则\bHello from Netcatty\b以#34D399绿色高亮;
  5. 验证主题:可观察到终端光标颜色变为#34D399。

以上每一步都对应 README 描述的功能面,且与源码一一印证。


七、隔离运行时:插件为什么安全

README 将命令处理器所在的运行时称为"沙箱化插件运行时",其具体保障在 docs/plugin-platform/isolated-runtime.md 中有完整描述:

  • 普通浏览器运行时:每个插件获得一个隐藏BrowserWindow、独立内存会话与不可猜测的协议权限,启用 Chromium OS 沙箱、nodeIntegration=false、contextIsolation=true,无 DevTools/弹窗/导航/下载/网络权限,会话强制离线;preload 只负责传递一个宿主创建的 MessagePort,不暴露 Electron、Node 或应用内部 IPC;
  • RPC 与流:插件与宿主通过 MessagePort 上的 JSON-RPC 通信,所有入站包先通过深度/节点预算、字节预算与 JSON Schema 校验;控制消息限制 1 MiB,更大负载走带字节信用机制的流;
  • 生命周期:激活有 5 秒截止;正常停止先请求plugin.deactivate(2 秒截止)再关闭端口;5 分钟内 3 次失败会隔离插件,隔离状态跨重启保留;
  • 数据库:插件安装目录userData/plugins/由 SQLite 管理,包从不直接解压进活动目录,而是经暂存目录、校验快照后以事务方式发布。

正因如此,"Providers 不会收到原始 xterm 对象或敏感终端输入输出流"不仅是一条 API 约定,更是由运行时隔离与权限边界共同保证的安全属性。


八、从示例出发的进阶路径

若想深入,仓库提供了成套的插件平台文档,可直接与示例对照阅读:

  • docs/plugin-platform/contract-and-sdk.md:清单、合约与 SDK 的整体关系;
  • docs/plugin-platform/isolated-runtime.md:隔离运行时、安装事务、数据库所有权与生命周期;
  • docs/plugin-platform/terminal-providers.md:九种普通终端 Provider 的负载/结果形状与宿主适配器细节;
  • docs/plugin-platform/security-and-permissions.md:权限模型与凭据保护;
  • docs/plugin-platform/runtime-extension-boundaries.md:运行时扩展边界。

此外,netcatty-plugin init <directory> --id <reverse.dns.id> [--name <display name>](见 packages/plugin-cli/src/cli.ts)可用于生成自己的插件脚手架,再以hello-netcatty为模板逐步替换:先增加更多activationEvents与contributes条目,再尝试 link / hover / matcher / semantic 等其余 Provider 类型,最后按validate → compatibility → pack流程交付.ncpkg安装包。

结语

hello-netcatty虽名为 Hello World,却完整覆盖了 Netcatty 插件平台从清单声明、惰性激活、权限授予、SDK 注册到隔离运行时的全部关键环节。以它为起点,配合netcatty-pluginCLI 与插件平台文档,即可在 Netcatty 中安全地构建属于自己的终端能力扩展——补全、高亮、主题乃至未来的连接与同步 Provider,都建立在这套声明式清单与受限运行时的基础之上。

【免费下载链接】Netcatty

SSH workspace, SFTP, and terminals in one

项目地址:https://gitcode.com/gh_mirrors/net/Netcatty
点击查看免费下载
上一篇:推荐开源项目:Theia Sticky Sidebar - 永不消失的侧边栏
下一篇:多视角深度学习革命:MVSNet & R-MVSNet完整指南 🚀

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询