百积木文档
开发指南

开发本地应用

开发 Connector 本地应用,定义清单、服务、内嵌界面、权限、调试、打包和市场发布流程。

本地应用是安装在用户电脑上的 Connector。它适合连接只能在本机访问的数据和程序,例如桌面软件、本地数据库、文件、浏览器、开发工具或硬件设备。

本地应用不进入 Bundle,也不是平台应用。它由百积木客户端安装和管理,在本机启动独立进程,通过 loopback HTTP 向 Bridge Agent 提供方法和事件;Bridge Agent 完成设备授权、远程调用控制和能力上报。

智能体或工作流
  -> 百积木 Relay
  -> 用户已授权的 Bridge Agent
  -> Connector 注册的方法
  -> 127.0.0.1 上的本地服务
  -> 本机数据、程序或设备

开发流程

  1. 确认能力必须在用户电脑上运行,并定义最小权限。
  2. 实现仅监听 loopback 的本地 HTTP 服务。
  3. 编写 service-registration.json,声明可远程调用的方法和事件。
  4. 编写 connector.json,声明运行时、权限、配置、管理操作和可选内嵌界面。
  5. 从本地目录安装,完成启动、健康检查、方法调用和停止测试。
  6. 生成固定版本的 Git 标签或压缩包,计算 SHA-256。
  7. 创建本地应用定义和不可变版本,提交市场审核。
  8. 从市场或固定版本地址重新安装,完成最终验收。

项目结构

推荐使用下面的结构:

example-connector/
├── connector.json
├── service-registration.json
├── README.md
├── ui/
│   ├── index.html
│   ├── app.js
│   └── app.css
├── bin/
│   ├── macos-arm64/
│   │   └── example-connector
│   ├── macos-x86_64/
│   │   └── example-connector
│   └── windows-x86_64/
│       └── example-connector.exe
└── tests/

Node.js 项目也可以在 package.jsonbin 中声明命令;Python 项目可以在 pyproject.toml[project.scripts] 中声明入口。百积木客户端安装 Connector 后会解析这些入口。原生程序优先放在 bin/<平台>-<架构>/,也可以放在包根目录或 bin/

平台目录使用 macos-arm64macos-x86_64windows-x86_64linux-x86_64 等名称。只在应用定义的 platforms 中声明真正构建和测试过的平台。

编写 Connector 清单

新应用使用 schemaVersion: "1.2"。下面是一份包含本地服务、内嵌界面和管理操作的示例:

{
  "schemaVersion": "1.2",
  "id": "com.example.connector.notes",
  "name": "Example Notes Connector",
  "version": "0.1.0",
  "description": "Read notes stored on this computer.",
  "publisher": {
    "name": "Example",
    "homepage": "https://example.com"
  },
  "source": {
    "type": "git",
    "repo": "example/example-notes-connector",
    "revision": "v0.1.0"
  },
  "runtime": {
    "type": "process",
    "command": "example-connector",
    "args": ["start"],
    "startPolicy": "manual",
    "healthCheck": {
      "type": "http",
      "url": "http://127.0.0.1:18120/health",
      "timeoutSecs": 2,
      "expectStatus": 200
    }
  },
  "permissions": [
    {
      "id": "filesystem.notes.read",
      "title": "读取本机笔记",
      "description": "读取用户选择的笔记目录。",
      "platforms": ["macos", "windows", "linux"]
    }
  ],
  "management": {
    "type": "http",
    "baseUrl": "http://127.0.0.1:18120",
    "auth": {
      "type": "connector_token"
    },
    "operations": {
      "runtimeState": {
        "method": "GET",
        "path": "/management/v1/state"
      },
      "chooseNotesDirectory": {
        "method": "POST",
        "path": "/management/v1/choose-directory"
      }
    }
  },
  "ui": {
    "type": "embedded",
    "entry": "ui/index.html",
    "title": "笔记设置",
    "defaultView": true
  },
  "configSchema": {
    "type": "object",
    "properties": {
      "port": {
        "type": "integer",
        "default": 18120,
        "minimum": 1024,
        "maximum": 65535
      }
    },
    "additionalProperties": false
  },
  "remoteCapabilities": [
    {
      "name": "notes.read",
      "risk": "medium",
      "description": "Read notes from the directory selected by the user."
    }
  ],
  "serviceRegistrationFiles": [
    "service-registration.json"
  ]
}

必须满足以下约束:

  • idnameversion 不能为空,id 只能使用安全的路径字符。第三方应用不要使用保留的 com.baijimu.* 命名空间。
  • 至少通过 servicesserviceRegistrationFiles 声明一个服务。
  • runtime.startPolicy 只能是 automaticmanual;权限声明和手动启动策略要求 schema 1.2。
  • management.baseUrl 必须是只包含 origin 的 loopback HTTP 地址,不能包含账号、路径、查询参数或片段。
  • management operation 只支持 GETPOST,路径必须位于 /management/ 下。
  • 内嵌 UI 必须放在独立目录中,入口必须是包内 .html 文件,不能使用绝对路径或 .. 逃逸目录。

注册方法和事件

service-registration.json 定义远端实际可见的服务。方法应使用明确的输入 JSON Schema,不要接收任意命令、任意文件路径或未约束的 URL。

{
  "name": "localNotes",
  "description": "Read notes stored on this computer.",
  "transport": {
    "type": "http",
    "baseUrl": "http://127.0.0.1:18120"
  },
  "healthCheck": {
    "type": "http",
    "path": "/health",
    "httpMethod": "GET",
    "timeoutSecs": 2,
    "expectStatus": 200
  },
  "startCommand": {
    "type": "shell_command",
    "command": ["example-connector", "start"],
    "timeoutSecs": 20
  },
  "stopCommand": {
    "type": "shell_command",
    "command": ["example-connector", "stop"],
    "timeoutSecs": 20
  },
  "methods": [
    {
      "name": "listNotes",
      "description": "List notes visible to the configured local account.",
      "path": "/invoke/listNotes",
      "httpMethod": "POST",
      "timeoutSecs": 10,
      "input_schema": {
        "type": "object",
        "properties": {
          "limit": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100,
            "default": 20
          }
        },
        "additionalProperties": false
      }
    }
  ],
  "events": [
    {
      "name": "noteChanged",
      "description": "Emitted after a local note changes.",
      "enabled": true,
      "payload_schema": {
        "type": "object",
        "required": ["noteId", "occurredAt"],
        "properties": {
          "noteId": {
            "type": "string"
          },
          "occurredAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "additionalProperties": false
      }
    }
  ],
  "replace": true,
  "managed_by": "example-connector"
}

Connector 进程必须只监听 127.0.0.1::1healthCheck 通过后,Bridge Agent 才会把相应服务作为可用能力上报。启动命令运行时,客户端会提供:

  • BAIJIMU_CONNECTOR_DATA_DIR:应用私有数据目录,用于配置、状态和本机管理凭证。
  • BAIJIMU_CONNECTOR_START_POLICY:清单中的 automaticmanual

不要把用户数据、密钥或可变状态写回 Connector 安装目录;同步和升级会替换安装副本。

本机管理接口和内嵌 UI

内嵌页面不能直接调用 Tauri 命令、Relay、文件系统或任意本机 HTTP 地址。页面只能调用 connector.json 中已经声明的 management operation:

const state = await window.baijimuLocalApp.invoke("runtimeState");

await window.baijimuLocalApp.invoke("chooseNotesDirectory", {
  path: "/Users/me/Documents/Notes"
});

Bridge Agent 会读取应用私有目录中的 management-token,并以 Authorization: Bearer ... 调用声明的 loopback management API。Connector 应在首次启动时生成至少 32 个字符的高熵 token,以仅当前用户可读的权限保存;页面代码和 management 响应都不能返回这个 token。

management API 用于本机配置、状态、授权和诊断,不能注册为 Relay 方法。所有来自页面的 payload 仍是不可信输入,Connector 必须进行 schema、路径和权限校验。

本地安装和调试

最终用户优先使用百积木客户端的“应用 > 安装应用 > 自定义安装”。完整安装步骤见安装本地应用

开发期间可以从项目目录安装。CLI 安装会执行本机程序,确认已经审查源代码后再显式接受非市场来源:

bridge-agent connector install /absolute/path/to/example-connector \
  --replace \
  --accept-untrusted

bridge-agent connector show com.example.connector.notes
bridge-agent connector start com.example.connector.notes
bridge-agent connector list

每次安装都会复制项目内容。修改源码后需要重新安装或在百积木客户端中执行同步,原目录变化不会直接修改已安装副本。

至少完成下面的验收:

  1. connector.json 和服务注册文件可以解析。
  2. 安装后命令能从复制后的包目录启动,而不是依赖源码目录。
  3. 进程只监听 loopback,健康检查从不可用变为可用。
  4. 每个方法分别覆盖成功、非法参数、无权限、超时和依赖不可用。
  5. 停止后进程退出,健康检查变为不可用;再次启动不产生重复进程。
  6. 内嵌 UI 只能调用已声明的 management operation。
  7. Connector 重启或升级后,私有数据目录中的配置仍然有效。
  8. Bridge Agent 断线重连后,健康服务、方法和事件可以重新上报。

打包固定版本

正式版本使用语义版本号,例如 0.1.0connector.json、Git 标签、压缩包文件名和市场版本必须一致。

发布包可以直接以 Connector 目录为根,也可以只包含一个顶层目录。包内必须只有一个可识别的 connector.json。不要打包:

  • .git、构建缓存、测试数据和日志。
  • 明文 token、cookie、用户配置或本地数据库。
  • 只适用于开发机的绝对路径。
  • 没有为目标平台构建的二进制。

生成压缩包后计算 SHA-256,并把包上传到不可变的 HTTPS 地址:

shasum -a 256 example-connector-0.1.0.zip

同一个版本号和下载地址不得覆盖。修复后发布新版本,并重新计算校验值。

发布到本地应用市场

先查看当前 CLI 的实际能力:

baijimu --version
baijimu local-app --help
baijimu local-app version create --help
baijimu auth status --verify

创建应用定义时,idconnectorId 都必须稳定且唯一;第三方 connectorId 不能使用 com.baijimu.*。平台只能是 macoswindowslinux,风险等级只能是 lowmediumhigh

baijimu local-app create \
  --id example-notes \
  --connector-id com.example.connector.notes \
  --name "Example Notes Connector" \
  --description "Read notes stored on this computer." \
  --publisher "Example" \
  --risk-level medium \
  --platform macos \
  --platform windows

应用定义与版本是两个资源。创建不可变版本时必须提交语义版本、HTTPS 制品地址、SHA-256 和 manifest;sourceType 只能是 httpsarchive

baijimu local-app version create example-notes \
  --version 0.1.0 \
  --source-type archive \
  --source https://downloads.example.com/example-connector-0.1.0.zip \
  --repo example/example-notes-connector \
  --revision v0.1.0 \
  --checksum 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef \
  --manifest @connector.json \
  --capability notes.read

示例 checksum 只是格式占位,发布时必须替换为实际压缩包的 SHA-256。创建版本后读取应用,确认服务端保存的版本、来源、校验值和 manifest 与发布物一致,再提交审核:

baijimu local-app get example-notes --json
baijimu local-app submit example-notes 0.1.0 --json
baijimu local-app publications --json

提交后状态进入 PENDING_REVIEW。审核通过前不要把版本描述为已发布;只有审核通过并能从市场安装,才算完成交付。

发布后的完整验证

  1. 在一台没有源码目录和开发依赖的设备上,从市场安装目标版本。
  2. 核对下载来源、SHA-256、connectorId 和版本。
  3. 完成系统权限和应用内配置,启动 Connector。
  4. 确认健康检查、方法、事件和内嵌 UI 都可用。
  5. 从已授权工作区发起一次真实调用,并在 Bridge Agent 与 Connector 两侧核对日志。
  6. 安装前一版本,再执行同步或升级,确认配置迁移和回滚说明有效。
  7. 卸载后确认进程、服务注册和安装包已移除,用户明确保留的数据符合产品说明。

常见问题

提示没有声明服务

connector.json 必须包含非空 services,或通过 serviceRegistrationFiles 引用有效的服务注册文件。

安装后找不到启动命令

确认目标平台二进制位于 bin/<平台>-<架构>/,或已在 package.jsonbinpyproject.toml[project.scripts] 中声明。还要确认压缩包里包含构建产物,并且命令具有执行权限。

服务启动了但平台看不到方法

依次检查健康检查、服务名和方法名、HTTP 路径、Bridge Agent 连接状态、设备与工作区授权。健康检查不通过的服务不会作为可用能力上报。

内嵌页面调用失败

确认 operation 名称同时存在于 management.operations 和页面的 window.baijimuLocalApp.invoke() 调用中,management 服务只监听 loopback,并且私有数据目录中存在权限安全的 management-token

本地可用但安装包不可用

通常是启动命令依赖源码目录、开发机 PATH、未打包的动态库或绝对路径。必须在干净设备上从最终压缩包重新安装验证,不能只测试源码目录。

本页内容