mcpField
P
paseo-plugin

paseo-plugin

github.com/getpaseo开发22.3k1.4k 次安装今天更新
代码仓库

关于 paseo-plugin

paseo-plugin 是用于构建和管理 Paseo 插件的技能,可扩展应用与守护进程。它指导开发者添加界面、RPC 处理程序和生命周期钩子,并遵循兼容性要求。

主要功能

  1. 01添加屏幕、面板和命令
  2. 02注册时间线与附件功能
  3. 03实现守护进程端插件 RPC
  4. 04接入 Agent 和工作区生命周期
  5. 05搭建并检查插件结构

适用场景

  1. 01构建工作区面板或自定义屏幕
  2. 02添加斜杠命令或时间线渲染器
  3. 03连接应用界面与插件专属守护进程行为
  4. 04通过生命周期钩子配置 Agent 启动

MCP 相关

该技能介绍如何通过创建与启动钩子配置 MCP 服务。它并未将 paseo-plugin 本身描述为 MCP 服务。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/getpaseo/paseo --skill paseo-plugin

安装后在 Claude Code 中输入/paseo-plugin确认已加载。

详细介绍

Paseo 插件

直接构建或管理所需的插件。使用当前公开文档检查契约变更;如果网络不可用,则继续依据此技能操作。

用户的请求: $ARGUMENTS

检查当前文档

首先获取 https://paseo.sh/llms.txt。在修改插件前,从该索引中选择并获取当前的插件 Markdown 页面:

如果已部署的文档与此技能不一致,请以已部署的文档为准。不要让用户自行阅读文档,而要直接完成工作。

在 Paseo 仓库中,使用 public-docs/plugins/reference.md 查阅此检出版本的 API,包括尚未发布的变更。使用 docs/plugins.md 查阅维护者指南。完整契约应放在公开文档中;此技能用于索引参考资料和示例。

插件可以提供的功能

选择与请求相符的功能。每一行都列出注册项、适用场景,以及完整契约所在的位置。大多数插件会组合多种功能:例如,调用 RPC 的斜杠命令会追加一条时间线记录,再由渲染器绘制出来。

贡献内容注册方式适用场景参考
屏幕和侧边栏项addScreen + addSidebarHeaderItem/addSidebarFooterItem插件 UI 的完整屏幕,或可打开屏幕或弹出层的侧边栏页眉或页脚行reference.md → 屏幕和侧边栏项
工作区面板addWorkspacePanel位于 Agent、终端、文件和差异旁边标签页中的 UI;在 Explorer 中使用 locations: ["explorer"]reference.md → 工作区面板
文件面板addFilePanel通过文件句柄在文件标签页中查看或编辑匹配的文件reference.md → 文件面板;plugin-examples/pdf-panel、plugin-examples/markdown-panel
Command Center 项addCommandCenterItem可通过 ⌘K 访问的全局、工作区或 Agent 操作reference.md → Command Center 项
客户端斜杠命令addSlashCommand在编辑器中输入 /command args,运行插件代码而非向 Agent 提示reference.md → 斜杠命令
编辑器胶囊addComposerPill编辑器轨道栏中 Tasks 和 Subagents 旁边的每个 Agent 专属按钮reference.md → 编辑器胶囊
时间线转换器addTimelineTransformer + addTimelineRenderer替换、展开或隐藏内置时间线项,包括其流式传输期间reference.md → 时间线项;plugin-examples/timeline-items、plugin-examples/inline-thinking
时间线行paseo.agents.ref(id).timeline.append(...)从服务端处理程序将插件拥有的行推送到 Agent 时间线,并在之后更新reference.md → 从守护进程追加时间线行
附件来源client.addAttachmentSource + server.handle让用户将可搜索的外部资源(例如问题)附加到提示词reference.md → 添加编辑器附件来源;plugin-examples/linear
主题addThemeSettings → Appearance 下的浅色或深色调色板reference.md → 提供主题;plugin-examples/catppuccin
插件 RPCdefineRpc + server.handle + useRpc非常规 Paseo 操作的守护进程端任务:供应商 API、凭据、本地文件reference.md → 添加插件专属后端行为
生命周期事件server.on观察 Agent/工作区生命周期、检查已结束的轮次并响应权限请求生命周期钩子
创建和启动钩子server.before在操作前更改 Agent 配置、提供方选项、MCP 服务、环境或工作区隔离Before 钩子
Paseo SDKusePaseo() / handler { paseo }常规 Paseo 操作:工作区、Agent、提供方、配置reference.md → 使用 Paseo SDK
生命周期任务示例
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
记录全部 11 个钩子lifecycle-logger
后续操作、权限、环境、提供方切换、工作树lifecycle-actions
注入 MCP 服务并更改 Codex 沙盒/审批选项agent-configuration

创建项目

请使用守护进程所在机器上的绝对路径。init 会写入文件,但不会安装软件包。

paseo plugin init /absolute/path/to/my-plugin
cd /absolute/path/to/my-plugin
npm install

生成的项目包含:

my-plugin/
  paseo-plugin.json
  OVERVIEW.md
  package.json
  tsconfig.json
  index.client.tsx
  index.server.ts
  client/greeting.tsx
  server/greeting.ts
  shared/greeting.ts

清单提供默认安装 ID 和支持的 Paseo 版本:

{ "id": "my-plugin", "requirements": { "paseo": ">=0.8.0" } }

创建或编辑插件时,请确保 requirements.paseo 正确无误。init 使用 >=,后跟 CLI 版本。采用较新的 API 时,请提高最低版本要求;若后续 Paseo 版本不兼容,请添加上限。使用 npm semver 范围,并在面向 beta 版本时明确包含 beta 版本。缺少 requirements 表示 <0.8.0;添加 >=0.8.0 之前,请先完成 0.8 条目迁移。请使用守护进程和运行客户端贡献的应用验证兼容性。 参见requirements。

每个运行时都有各自可选的入口。插件必须至少有一个入口。两个入口都接受 .ts 或 .tsx;入口导入组件时请使用 .tsx。

路径运行时
index.client.tsx 和 client/应用
index.server.ts 和 server/守护进程子进程
shared/两者

不要在插件根目录中放置其他代码模块。

客户端导入 server/、服务端导入 client/,以及客户端代码可触达的所有 node: 导入,都会导致编译错误。相对导入插件根目录中的其他代码文件也会导致编译错误;请将其移至 client/、server/ 或 shared/。共享模块包含 Zod 契约和纯值;它们不会导入 Node 或 React Native 运行时 API。

在每个入口中默认导出一个贡献函数,并返回清理函数:

// index.client.tsx
import type { PluginClientContext } from "@getpaseo/plugin/client";

export default function contribute(client: PluginClientContext) {
  // Register components and client callbacks here.
  return () => {};
}
// index.server.ts
import type { PluginServerContext } from "@getpaseo/plugin/server";

export default function contribute(server: PluginServerContext) {
  // Register daemon-side RPC handlers here.
  return () => {};
}

清理操作可以是异步的。请用它清理插件代码创建的计时器、监视器、套接字、订阅及其他资源。每个客户端 add* 方法都会返回一个幂等移除函数。插件停止时,Paseo 会先调用入口清理函数,移除仍然存在的注册项,拒绝待处理的 RPC,关闭插件会话,并停止子进程。

添加工作区面板

工作区面板与 Agent、终端、文件和差异视图并列。插件可在桌面端和移动端运行,Paseo 也支持多种主题。每个 Text 都必须从 theme.colors 获取颜色。请使用 layout.compact 控制内边距和堆叠方式。未设置样式的文本为黑色,在深色主题下会显示异常。

import {
  type PluginClientContext,
  type PluginWorkspacePanelProps,
  useWorkspace,
} from "@getpaseo/plugin/client";
import { useMemo } from "react";
import { Text, View } from "react-native";

function Overview({ theme, layout, workspaceId }: PluginWorkspacePanelProps) {
  const name = useWorkspace(workspaceId, (workspace) => workspace.name);
  const styles = useMemo(
    () => ({
      screen: {
        flex: 1,
        padding: layout.compact ? 16 : 24,
        gap: layout.compact ? 8 : 12,
        backgroundColor: theme.colors.surface0,
      },
      title: { color: theme.colors.foreground, fontSize: layout.compact ? 20 : 24 },
    }),
    [theme, layout.compact],
  );
  return (
    <View style={styles.screen}>
      <Text style={styles.title}>{name}</Text>
    </View>
  );
}

export default function contribute(client: PluginClientContext) {
  client.addWorkspacePanel({
    id: "overview",
    title: "Workspace overview",
    icon: "PanelsTopLeft",
    context: "workspace",
    Component: Overview,
  });
  client.addCommandCenterItem({
    id: "open-overview",
    title: "Open workspace overview",
    icon: "PanelsTopLeft",
    context: "workspace",
    onSelect({ openPanel }) {
      openPanel("overview");
    },
  });
  return () => {};
}

请使用 useWorkspace(id, selector) 和 useAgent(id, selector)。必须提供选择器, 其结果使用浅比较。切勿选择整个快照,也不要添加 RPC 来发现当前工作区或 Agent。 命令回调会接收所选宿主的 paseo、类型化的 rpc(contract, input)、openScreen({ screenId, params? }) 和上下文相关的 openPanel(id) 能力。

添加屏幕和侧边栏项

插件屏幕使用 React Native 基本组件,可在桌面端、浏览器、iOS 和 Android 上运行。侧边栏项位于页眉或页脚,是一个组件:从 @getpaseo/plugin/client/ui 渲染一个或多个 SidebarRow,并在各组之间插入 SidebarSeparator,然后从中调用 openScreen 或 openPopover。屏幕的 title 是字符串或一个根据其 params 生成字符串的函数;屏幕组件会收到打开屏幕时传入的 params。使用 theme.colors 设置文字颜色,使用 layout.compact 设置内边距。

import type {
  PluginClientContext,
  PluginScreenProps,
  PluginSidebarItemProps,
} from "@getpaseo/plugin/client";
import { SidebarRow } from "@getpaseo/plugin/client/ui";
import { useMemo, useState } from "react";
import { Pressable, Text, View } from "react-native";

function Counter({ theme, layout }: PluginScreenProps) {
  const [count, setCount] = useState(0);
  const styles = useMemo(
    () => ({
      screen: {
        flex: 1,
        padding: layout.compact ? 16 : 24,
        gap: 16,
        backgroundColor: theme.colors.surface0,
      },
      count: { color: theme.colors.foreground, fontSize: layout.compact ? 36 : 48 },
      button: { padding: 14, borderRadius: 10, backgroundColor: theme.colors.accent },
      buttonText: { color: theme.colors.accentForeground, textAlign: "center" as const },
    }),
    [theme, layout.compact],
  );
  return (
    <View style={styles.screen}>
      <Text style={styles.count}>{count}</Text>
      <Pressable
        accessibilityRole="button"
        accessibilityLabel={`Increment counter, currently ${count}`}
        onPress={() => setCount((value) => value + 1)}
        style={styles.button}
      >
        <Text style={styles.buttonText}>Count me in</Text>
      </Pressable>
    </View>
  );
}

function CounterItem({ currentScreen, openScreen }: PluginSidebarItemProps) {
  return (
    <SidebarRow
      icon="ListPlus"
      active={currentScreen?.screenId === "main"}
      onPress={() => openScreen({ screenId: "main" })}
    />
  );
}

export default function contribute(client: PluginClientContext) {
  client.addScreen({ id: "main", title: "Counter", Component: Counter });
  client.addSidebarHeaderItem({ id: "main", title: "Counter", Component: CounterItem });
  return () => {};
}

图标可以是 Lucide 图标名称、内联 SVG({ svg })或组件;请参阅图标。每个屏幕和面板上的 theme 都是类型化的 PluginTheme。主要文字使用 theme.colors.foreground;标签使用 theme.colors.foregroundMuted;根视图使用 theme.colors.surface0。在移动设备和窄窗口中,layout.compact 为 true。Paseo 负责路由、页眉、主机选择器、关闭操作、错误边界,以及每个安装实例各自的查询客户端。

编写导入语句前,先将每个模块归类为 shared、client 或 server。遵循 SDK 导入边界,包括传递依赖和类型依赖。根目录仅允许 shared 模块;钩子和客户端上下文属于 @getpaseo/plugin/client,服务端上下文属于 /server,主机 UI 属于 /client/ui。 在本地安装依赖以进行类型检查;Paseo 会提供主机运行时模块。JSX 使用自动运行时。不要在插件代码中导入 /client/host。

支持移动设备

报告插件已完成前:

  • 仅使用 React Native 基本组件:View、Text、Pressable、ScrollView 和 TextInput。
  • 不要使用 HTML 元素、className、CSS 字符串或 onClick。
  • 不要在 tsconfig.json 中加入 "DOM",也不要使用 /// <reference lib="dom" />。仅在 client/web.ts 中使用 DOM 全局变量,并且只声明该模块实际使用的变量;每个导出都必须以 Platform.OS === "web" 为条件,并提供原生替代实现或空操作。
  • 从 theme.colors 获取颜色。
  • 检查紧凑布局。

在 client/ 上运行此检查:

rg -n "document\.|window\.|localStorage|navigator\.|<[a-z]+[ >]|className=|onClick=" client/

在 client/web.ts 之外发现匹配项即为错误。

选择正确的 API

常规 Paseo 操作使用现有的 Paseo SDK。仅在处理插件专属的后端行为时使用插件 RPC。

在界面中调用 Paseo

usePaseo() 会借用当前选定主机的连接。不要在界面中创建另一个客户端。它是插件在每个界面中唯一的客户端:在清理时释放订阅;其余部分会在插件拆卸时结束。

import { usePaseo } from "@getpaseo/plugin/client";

function PullRequestAction() {
  const paseo = usePaseo();

  async function createReviewWorkspace() {
    const workspace = await paseo.workspaces.create({
      title: "Review PR 42",
      source: {
        kind: "worktree",
        cwd: "/absolute/path/to/repository",
        action: "checkout",
        checkoutSource: { kind: "change_request", forge: "github", number: 42 },
      },
    });
    await workspace.agents.create({
      config: { provider: "codex/gpt-5.5" },
      prompt: "Review PR #42.",
    });
  }

  // Wire createReviewWorkspace to a Pressable.
  return null;
}

该 API 涵盖工作区、Agent、提供商和守护进程配置。由于连接由 Paseo 管理,因此不包含连接生命周期相关功能。方法详情请参阅最新的 SDK 参考。

添加守护进程端行为

在 shared/ 中定义一个 Zod 契约,在 index.server.ts 中注册其子进程处理程序, 并在客户端代码中使用 useRpc() 调用它:

// shared/greeting.ts
import { defineRpc } from "@getpaseo/plugin";
import { z } from "zod";

const greeting = defineRpc({
  name: "greeting.create",
  input: z.object({ name: z.string() }),
  output: z.object({ message: z.string() }),
});
// server/greeting.ts
import type { RpcInput } from "@getpaseo/plugin";
import { greeting } from "../shared/greeting";

export async function createGreeting({ name }: RpcInput<typeof greeting>) {
  return { message: `Hello, ${name}!` };
}
// index.server.ts
import type { PluginServerContext } from "@getpaseo/plugin/server";
import { createGreeting } from "./server/greeting";
import { greeting } from "./shared/greeting";

export default function contribute(server: PluginServerContext) {
  server.handle(greeting, createGreeting);
  return () => {};
}
// client/greeting.tsx
import { useRpc } from "@getpaseo/plugin/client";
import { greeting } from "../shared/greeting";

function Greeting() {
  const createGreeting = useRpc(greeting);
  // Use createGreeting({ name: "Ada" }) in a query, mutation, or event.
  return null;
}

输入和输出都会在两端进行验证。后端处理程序会收到同一个 PaseoApi,形式为 { paseo };其基于 IPC 的守护进程会话与子进程的生命周期完全相同。后端代码可以使用 Node API 和已安装的依赖项。凭据、文件系统访问、shell 命令和供应商 API 调用应放在处理程序中,而不是客户端界面中。

使用 TanStack Query 管理异步请求状态、缓存和变更。

调试守护进程端的行为

后端贡献可以使用常规的 Node 日志记录。console.log() 会写入插件的 stdout; console.error() 会写入 stderr。Paseo 会捕获这两个流,且不会干扰插件 IPC。

安装、重新加载、RPC 失败或子进程崩溃后,查看近期输出:

paseo plugin logs my-plugin
paseo plugin logs my-plugin --json
paseo plugin logs my-plugin --host <url>

也可以在 Settings → Plugins → Logs 中查看相同的日志尾部。内容包括初始化、处理程序、 清理和最终崩溃输出。重新加载、禁用和进程失败时会保留日志尾部。移除插件会清除日志;重启守护进程会清除内存中的日志尾部。结构化副本也会写入守护进程日志。切勿记录凭据或其他机密信息。

添加撰写器附件来源

在 shared/ 中定义搜索 RPC 和声明式来源,在服务端处理,并在客户端注册:

// shared/issues.ts
import { defineAttachmentSource, defineRpc } from "@getpaseo/plugin";
import { z } from "zod";

const searchIssues = defineRpc({
  name: "issues.search",
  input: z.object({ query: z.string() }),
  output: z.object({
    items: z.array(
      z.object({
        id: z.string(),
        identifier: z.string(),
        title: z.string(),
        subtitle: z.string().optional(),
        url: z.string().url(),
        text: z.string(),
        resourceType: z.string(),
      }),
    ),
  }),
});

const issues = defineAttachmentSource({
  id: "issues",
  title: "Acme issue",
  icon: "CircleDot",
  pickerTitle: "Attach Acme issue",
  searchPlaceholder: "Search by identifier or title",
  search: searchIssues,
});
// index.server.ts
import type { PluginServerContext } from "@getpaseo/plugin/server";
import { searchIssues } from "./shared/issues";

export default function contribute(server: PluginServerContext) {
  server.handle(searchIssues, ({ query }) => searchAcmeIssues(query));
  return () => {};
}
// index.client.tsx
import type { PluginClientContext } from "@getpaseo/plugin/client";
import { issues } from "./shared/issues";

export default function contribute(client: PluginClientContext) {
  client.addAttachmentSource(issues);
  return () => {};
}

返回完整的文本快照。撰写器菜单、选择器、标签、草稿和提交均由 Paseo 管理。凭据和供应商调用留在守护进程处理程序中。

添加客户端斜杠命令

用户提交 /name args 时,斜杠命令会在应用中运行插件代码。不会向 Agent 发送任何内容。args 是命令名称之后经过修剪的原始文本;请在插件中解析。

client.addSlashCommand({
  name: "review",
  description: "Run the review bot",
  argumentHint: "[scope]",
  context: "agent", // or "workspace" so drafts get it too
  async onSubmit({ args, agent, rpc, openPanel }) {
    await rpc(startReview, { agentId: agent.id, scope: args });
    openPanel("review");
  },
});

回调接收的上下文与匹配的 Command Center 项目相同,另加 args。自动补全行、清空输入和错误提示均由 Paseo 管理;请将待处理的界面放在标签或面板中。优先级依次为内置客户端命令、插件命令、供应商命令;低优先级的冲突命令会被丢弃。撰写器含有附件时不会运行命令。服务端不存在斜杠命令。

添加撰写器标签

标签是撰写器轨道栏中每个 Agent 各自的按钮,位于 Tasks 和 Subagents 旁边。通过客户端入口的生命周期添加和移除标签。PluginClientContext 上提供了 addComposerPill。

import type { PluginButtonRegistration, PluginClientContext } from "@getpaseo/plugin/client";

export function contributeClient(client: PluginClientContext) {
  const pills = new Map<string, PluginButtonRegistration>();
  const lifetime = new AbortController();
  const register = (agent: { id: string; workspaceId?: string | null }) => {
    if (lifetime.signal.aborted || !agent.workspaceId) return;
    const agentId = agent.id;
    const workspaceId = agent.workspaceId;
    pills.get(agentId)?.remove();
    pills.set(
      agentId,
      client.addComposerPill({
        id: "review",
        workspaceId,
        agentId,
        button: {
          title: "Open review",
          icon: "Scan",
          label: "Review",
          behavior: {
            kind: "action",
            onPress() {
              client.openPanel("review", { workspaceId, agentId });
            },
          },
        },
      }),
    );
  };
  const removeAll = () => {
    for (const pill of pills.values()) pill.remove();
    pills.clear();
  };
  // An owned list subscription delivers existing agents, then updates, and a fresh snapshot after a reconnect.
  void client.paseo.agents
    .list({ subscribe: {}, signal: lifetime.signal })
    .then(({ subscription }) => {
      subscription.subscribe({
        snapshot: ({ entries }) => {
          removeAll();
          for (const { agent } of entries) register(agent);
        },
        update: (message) => {
          if (message.type !== "agent_update") return;
          const update = message.payload;
          if (update.kind === "upsert") return register(update.agent);
          pills.get(update.agentId)?.remove();
          pills.delete(update.agentId);
        },
      });
      return undefined;
    })
    .catch((error) => {
      if (!lifetime.signal.aborted) console.error("Agent observation failed", error);
    });
  return () => {
    lifetime.abort();
    removeAll();
  };
}

从 index.client.tsx 调用 contributeClient(client),或将其主体移入该入口。button 描述符用于设置图标、标签和行为;可按下的按钮、外观、待处理状态、错误报告和位置均由 Paseo 管理。addComposerPill 会返回一个包含 update() 和 remove() 的注册对象。remove() 可重复调用;插件、客户端入口或主机连接关闭时,Paseo 会移除所有标签。

转换和渲染时间线项目

时间线转换器和渲染器是客户端贡献。转换器选择一个内置的 AgentTimelineItem.type,检查该项目,并返回零个或多个带版本的插件项目。undefined 会保留源项目,items 会替换源项目,[] 会移除源项目。渲染器在使用其 Zod 架构验证 data 后,绘制一个 kind 和 version。

client.addTimelineTransformer({
  id: "inline-thinking",
  query: { itemType: "reasoning" },
  transform: ({ item, phase }) => ({
    items: [
      { type: "plugin", kind: "inline-thinking", version: 1, data: { text: item.text, phase } },
    ],
  }),
});
client.addTimelineRenderer({
  kind: "inline-thinking",
  version: 1,
  schema: z.object({ text: z.string(), phase: z.enum(["streaming", "complete"]) }),
  Component: InlineThinking,
});

构建渲染模型时会运行转换器,包括获取历史记录时和每次实时更新时,因此对于正在加载的思考内容或正在运行的工具调用,phase 为 "streaming"。身份来自源项目,因此流式项目会保留其已挂载的组件;如果一个源项目拆分为多个项目,请设置输出 id。转换器必须同步且具确定性,data 必须是 JSON;抛出异常的转换器会被记录并跳过。对于节奏化显示的助手文本,请从 @getpaseo/plugin/client/ui 渲染 <StreamedText text={text} phase={phase} />;使用其 style 属性自定义文本外观。plugin-examples/inline-thinking 会将思考行替换为行内文本;plugin-examples/timeline-items 会将待办工具调用替换为任务卡片。

从守护进程追加时间线行

服务器处理程序可以将插件拥有的行推送到任意 Agent 时间线中。同一渲染器注册项会负责绘制它。

server.handle(publishReview, async ({ agentId, verdict }, { paseo }) => {
  await paseo.agents.ref(agentId).timeline.append({
    type: "plugin",
    id: "review",
    kind: "review-result",
    version: 1,
    data: { verdict },
  });
  return {};
});

守护进程会根据插件会话为 pluginId 添加标记,因此只有插件代码可以调用此功能。使用相同的 id 再次追加时,会实时替换之前的行,也会在重新获取时替换,这是插件更新行的方式。序列化后的 data 上限为 64 KiB,超过此限制会被拒绝。行保存在守护进程的内存时间线中,在滚动、重新获取和重新连接后仍会保留,但守护进程重启后不会保留。缺少对应插件的行会显示为不可用占位内容。主机通过 server_info.features.pluginTimelineItems 声明支持此功能。

贡献主题

addTheme 接受小型浅色或深色调色板;Paseo 会将其扩展为完整的令牌集。所有颜色都必须是十六进制字符串。

client.addTheme({
  id: "mocha",
  name: "Catppuccin Mocha",
  appearance: "dark",
  colors: {
    background: "#1e1e2e",
    foreground: "#cdd6f4",
    raised: "#313244",
    control: "#45475a",
    border: "#45475a",
    accent: "#cba6f7",
    mutedForeground: "#a6adc8",
    ring: "#6c7086",
  },
});

主题会显示在 Settings → Appearance 中。不支持 addTheme 的旧版客户端无法处理该条目,并会报告 client.addTheme is not a function;请更新客户端。参见 plugin-examples/catppuccin。

主机与信任

插件按守护进程安装,属于受信任的非沙箱代码。后端代码可以访问守护进程所在机器上的文件、进程、凭据和网络服务。客户端贡献代码在 Paseo 应用内运行。请勿安装用户未授权的插件,也不要安装未经检查源代码的插件。

安装前检查全局开关

确定目标守护进程,并检查其 config.json 中的根级 pluginsEnabled 值。对于本地守护进程,paseo daemon status --json 会报告其 home;配置文件路径为 <home>/config.json。如果字段缺失,则视为 false。不要根据插件的 disabled 状态推断全局值,因为单个插件也可以单独禁用。

如果 pluginsEnabled 已经是 true,则继续操作,无需询问用户是否启用。

如果该值为 false 或字段缺失,请停止操作,并在编辑或启用任何内容前征得用户明确许可。请求中须包含以下警告:

插件是受信任的非沙箱代码。后端插件代码可以访问你的守护进程所在机器,包括文件、进程、凭据和网络服务。客户端插件代码在 Paseo 应用内运行。我可以在此守护进程上启用插件吗?

用户同意后,执行以下操作:

  1. 保留 config.json 的其余内容,并将根级 pluginsEnabled 字段设为 true。
  2. 针对该守护进程运行 paseo reload --json。
  3. 确认 appliedPaths 中包含 pluginsEnabled;若 appliedPaths 为空,只有在重新读取文件并确认实时插件目录已启用后才可接受。
  4. 运行 paseo plugin ls,并确认安装后目标插件状态变为 running。

如果用户要求关闭全局开关,请将 pluginsEnabled 设为 false,运行 paseo reload --json,并确认已配置的插件状态显示为 disabled。

如果目标是远程守护进程,请勿编辑本地配置。请在守护进程所在机器上进行编辑,或让用户使用 Settings → Plugins → Enable plugins。paseo reload --host <url> 会重新加载远程守护进程自己的配置文件,但不会编辑该文件。

当多个已连接主机上存在相同的屏幕或侧边栏项目时,Paseo 只显示一次。屏幕标题栏中有主机选择器;侧边栏项目使用当前显示屏幕所属的主机,否则使用该插件某个屏幕中上次选定的主机。选定的主机负责提供资源包、SDK 调用、RPC 和查询缓存。选定主机离线时,不会切换到其他主机。附件来源始终限定在编写器所属的主机范围内。

发布列表条目

在 paseo-plugin.json 旁边编写 OVERVIEW.md,用于展示 Paseo 中的插件页面。 它能帮助用户决定是否安装插件;该页面顶部已经提供安装命令。README 面向 GitHub 用户, 包含安装说明、技术细节和徽章。篇幅过长的 AI 生成 README 会让用户不得不先读完这些内容, 才能了解插件的用途。

要在注册表中列出插件,必须提供 OVERVIEW.md。在固定的提交版本中,将它与 paseo-plugin.json 一起提交到源代码仓库。注册表会相对于清单文件解析其位置;对于单体仓库, 则在 pluginPath 下解析。还要将它包含在已发布的 npm 包中;脚手架的 files 列表已包含此文件。 发布前,请将脚手架中的指导性注释替换为有用的信息。

仓库中的概述优先于注册表中的临时替代文件。如果固定的提交中没有 OVERVIEW.md,在线验证就会失败; 唯一例外是未更改的导入记录,且注册表仓库中已包含 plugins/<owner>/<slug>.md。每次提升版本号都必须提供 仓库概述,并在同一个 PR 中移除临时替代文件。未提供仓库概述的版本更新会导致验证失败。README 不能替代概述。

作者编写的概述和注册表临时替代文件遵循相同的内容要求,并按以下顺序组织。 仅在有帮助时使用标题;篇幅根据复杂程度而定。主题只需一段文字。

  1. 首先用通俗的语言说明插件是什么以及它的用途。
  2. 仅在工作原理不明显时,说明它如何工作。
  3. 必要时说明设置方法:设置项、账户、令牌、提供商、外部工具或其他 插件。注明适用的守护进程版本和操作系统要求。可以提供设置指南,但不能提供安装说明。
  4. 说明值得了解的功能和设置、各选项的作用、插件读取或发送哪些内容以及发送到哪里、权限和已知限制。

使用句首字母大写的标题格式和客观直白的语言,不要使用 em dash。省略安装命令、 徽章、更新日志、贡献或许可章节、营销内容和未经支持的声明。 避免加入没有意义的实现细节,例如空的清理函数、主题令牌字段目录, 或不存在的功能列表。只保留有助于用户选择插件的内容。

如果你的插件是未更改的导入记录,可以提议用作者编写的概述替换注册表临时替代文件。 不要在自己的 OVERVIEW.md 中添加导入致谢。

参见你的列表页面。

类型检查与管理

编辑插件时,在安装或重新加载前对其源代码进行类型检查:

npm run typecheck
paseo plugin install /absolute/path/to/plugin
paseo plugin install /absolute/path/to/plugin --id another-runtime-id
paseo plugin install npm:@acme/paseo-review
paseo plugin install npm:@acme/[email protected]
paseo plugin install github:owner/repository
paseo plugin install github:owner/repository --ref main
paseo plugin update my-plugin
paseo plugin ls
paseo plugin reload my-plugin
paseo plugin logs my-plugin
paseo plugin disable my-plugin
paseo plugin enable my-plugin
paseo plugin remove my-plugin

对于 npm,请确保 npm 位于守护进程的 PATH 中;使用该主机的注册表配置和凭据。安装选择器只会选择一次内容; 不会固定更新版本。install 和 add 是别名。请遵循 Paseo 发布指南,了解 Paseo 的软件包内容和 准备要求;标准 npm 发布命令仍然适用。

管理非 CLI 默认目标的守护进程时,请使用 --host <url>。必须安装或生成内容的 Git 源代码,应在 paseo-plugin.json 中将 build 声明为 argv 数组列表;Paseo 会在安装和更新时不经 shell 直接运行这些命令, 如果有任何命令失败,就会保留旧版本。修改插件源代码后,必须运行 paseo plugin reload;更改全局开关的配置后, 必须运行 paseo reload。插件重新加载失败后会保持失败状态;查看 paseo plugin ls 获取加载错误, 查看 paseo plugin logs <id> 获取子进程输出,然后修复源代码、进行类型检查并再次重新加载。remove 会保留本地源代码目录,并删除由 Paseo 管理的 Git/npm 安装。

不要为了加载源代码更改而重启守护进程。重启可能会终止正在执行工作的 Agent。

对于旧式混合条目,请按独立运行时条目迁移指南逐步操作。

验证结果

完成更改后:

  1. 运行 npm run typecheck。
  2. 安装或重新加载确切的运行时 ID。
  3. 运行 paseo plugin ls,确认状态为 running 且没有错误。
  4. 在目标宿主中确认贡献内容。按 ⌘K(macOS)或 Ctrl+K(Windows/Linux)打开命令中心。在编辑器中输入 / 可查看斜杠命令。对于时间线相关工作,运行一个会生成源条目的 Agent 轮次,并在其流式输出期间观察,而不只是等它完成。对于 UI 相关工作,检查宽屏桌面窗口和紧凑型/移动客户端,并切换主题,确认文本仍使用 foreground / foregroundMuted。
  5. 测试更改后的操作或 RPC,包括其错误状态。

常见故障:

  • 侧边栏条目缺失:宿主错误、插件状态不是 running、该条目在“设置”>“侧边栏”中被隐藏,或其组件抛出异常(使用未知 Lucide 名称或不安全 SVG 的 SidebarRow 会抛出异常)。
  • 客户端模块不可用:客户端捆绑包只能使用上文列出的宿主提供模块。
  • RPC 被拒绝:输入或输出未通过 Zod 架构验证,或处理程序抛出异常。查看 paseo plugin logs <id> 获取处理程序输出。
  • 插件退出或重新加载失败:查看 paseo plugin ls 获取状态,并查看 paseo plugin logs <id> 获取初始化、清理或崩溃输出。
  • UI 未更新:编辑了源文件,但没有运行 paseo plugin reload <id>。
  • 时间线条目显示“Plugin timeline item unavailable”:未为该 kind 和 version 注册渲染器、渲染器架构拒绝了 data,或插件未在该宿主上运行。
  • 转换器不起作用:query.itemType 与源类型不匹配、转换返回了 undefined,或转换抛出异常并被跳过;检查应用控制台中的 [Plugins] Timeline transformer failed。
  • 未提供斜杠命令:名称与内置命令或其他插件的命令冲突、草稿的上下文为 agent,或编辑器中有附件。
  • 追加被拒绝:调用方不是插件会话、data 超过 64 KiB,或宿主版本早于 features.pluginTimelineItems。

评论

支持 Markdown