Desktop Console 脚本开发指南
本文面向在 Serpent Desktop 的“自动化脚本”Console 中编写实际脚本的开发者。脚本是一次性、受控的 JavaScript/TypeScript 批处理;它通过注入的 serpent 领域 API 调用 Automation Command Gateway,不是 Node 程序,也不是通用命令行。
API 版本:AUTOMATION_API_VERSION = 1。本文以当前 Console 实际注入的 src/scripting/serpent-guest-api.ts、Registry 和 E2E 行为为准。逐项签名见 脚本 API 参考;编辑器类型提示见 docs/internal/skills/serpent-automation/automation-api.d.ts。类型声明由 Registry 生成/校验,但个别 Registry 命令尚未投影到 Console,见“实现差异”。
先跑起来
打开资源库后,从“更多工具”→“自动化脚本”打开 Console。未打开资源库时,创建资源库面板不提供脚本入口。需要在无库状态下创建资源库或导入导出库时,应使用设置中配置好的 MCP 全局命令;library.create 返回 libraryId 后,后续库级调用仍需显式传入该 ID,Serpent 不会把它隐式写入 MCP 会话。
Console 运行的是脚本正文,最简单的入口是顶层 return:
const page = await serpent.assets.search({ query: 'tag:抽象', limit: 50 });
return { count: page.items.length, total: page.total };
脚本执行一次就是一个 Automation Execution。每次运行都是新的沙箱:上一次运行定义的函数、变量和 Promise 不会保留。需要辅助函数时,把函数和调用放在同一次运行中。
支持 .serpent.js 和 .serpent.ts。TypeScript 在受控运行时内转译为 ES2022;这是脚本正文,不是 ES module。不要写 import、export、动态 import()、eval、Function 或 globalThis。保存脚本只是保存源文本,不会把它变成插件,也不会获得额外权限。
可用全局与库绑定
脚本只应依赖以下环境:
serpent:唯一的 Serpent 领域对象。其命名空间和方法见 API 参考。- 标准 ES2022 语言能力:变量、条件、循环、函数、对象、数组、
Promise、JSON、日期和数学等;具体可用性仍受隔离运行时限制。 console.log(value)、console.info(value)、console.warn(value)、console.error(value):写入本次运行的脚本输出,输出受总量限制。
没有 require、Node 内置模块、任意文件系统、网络、Shell、SQLite、环境变量、原始 IPC 或任意 UI/DOM。脚本不能读取脚本文件自身,也不能通过 serpent 取得资源库或链接文件夹的绝对路径。assets.copyFilePaths() 是受控例外:由 Main 把选定路径写入系统剪贴板,脚本只收到数量。
serpent 的调用会经过 Gateway 的 Registry、能力检查、输入/结果 Schema、执行日志和资源库范围检查。脚本不能传入 executionId、能力、授权、资源库路径或伪造计划证明;这些由宿主绑定。
JS 与 TS 的写法
const page = await serpent.assets.search({ query: 'name:rain', limit: 20 });
return page.items.map((asset) => asset.id);
const page = await serpent.assets.search({ query: 'name:rain', limit: 20 });
const ids: string[] = page.items.map((asset) => asset.id);
return { ids, hasMore: page.hasMore };
不要从脚本 import 类型。把 automation-api.d.ts 加到编辑器的类型根目录,或在脚本编辑器外用它做补全;运行时仍只接受注入的 serpent。
推荐工作流:读、核对、最小写入
- 先用
search/list查询并分页,确认目标 ID 和数量。 - 读取需要写入的当前状态;元数据写入保存
entityVersion,文件内容写入保存currentRevisionId。 - 用最小批量执行写入,检查
updatedCount、movedCount、skippedCount或逐项skipped。 - 文件类操作完成后在 Console 中使用“撤销自动化操作”复核;一次 execution 的可撤回 mutation 会由 Worker 组成一个 history group,宿主只消费一个 Worker 历史回执,脚本不能自行重放文件操作。
- 对关键结果重新查询,或读取
library.changeSequence()验证资源库已发生预期变化。
const page = await serpent.assets.search({ query: 'name:reference', limit: 200, offset: 0 });
const result = page.items.length === 0
? { updatedCount: 0, skipped: [] }
: await serpent.assets.setRating(page.items.map((asset) => asset.id), 4);
return { matched: page.total, ...result };
分页、大结果和输出
列表/搜索接口返回统一页面:{ items, total, offset, limit, hasMore }。默认页大小是 50,单次最大 200;offset 是零基偏移。不要假设一次调用能读完整资源库,也不要把 total 当作当前页长度。
async function allSearch(query: string | null) {
const items = [];
for (let offset = 0; ; ) {
const page = await serpent.assets.search({ query, limit: 200, offset });
items.push(...page.items);
if (!page.hasMore || page.items.length === 0) return items;
offset += page.items.length;
}
}
Console 的脚本源最多 64 KiB;脚本输出逐行收集,单行最多 16 KiB,总输出默认约 1 MiB,最终返回值也计入输出预算。输出超限会以 OUTPUT_LIMIT 失败。不要 console.log 整个资源库或把大文件内容直接返回;asset.readContent() 还会受 maxBytes 和内容预算限制。
搜索语法
serpent.assets.search({ query }) 使用与工具栏相同的文本搜索语法;query 可为字符串或 null。null 表示当前资源库的非回收站资产。支持空格 AND、| OR、- 排除、引号短语和字段限定;字段别名包括 name/filename、tag/tags、desc/description、source/url/link/source_url、author、path/folder/folder_path、meta/metadata/metadata_text。搜索是包含匹配,例如 rain 可能命中 rainbow,要更严格请使用更长 token 或多字段组合。
当前 Console 还接受 Registry 的结构化搜索对象,由宿主归一化;若没有明确需要,优先用字符串查询。搜索仍只返回分页资产摘要和可选摘要,不返回磁盘路径。