# openmeego

飞书项目登录、多账号切换、录制与执行的 CLI，同时也提供可编程的 SDK（`OpenMeego`）。

## SDK 用法

SDK 入口是包的默认导出（见 `package.json` 的 `exports`），主要用于把 CLI 的业务能力以可组合的 API 形式复用到脚本、测试或其他 Node.js 程序里。

当前 SDK 覆盖范围：

- `auth`：登录（二维码 + 可选工作区选择）、列出用户、切换用户、删除用户
- `command`：抓包录制、保存/列出/删除命令、安装远程命令、运行命令并产出 `outputVariables`

示例：登录

```ts
import os from "node:os";
import { OpenMeego } from "openmeego";

const client = new OpenMeego({ homeDir: os.homedir() });

await client.auth.login({
  domain: "https://project.example.com",
  onQrCode: (qrUrl) => {
    // SDK 只回调二维码内容；渲染/展示由调用方决定。
    console.log("Scan QR:", qrUrl);
  }
});
```

示例：用户管理

```ts
import os from "node:os";
import { OpenMeego } from "openmeego";

const client = new OpenMeego({ homeDir: os.homedir() });
const users = await client.auth.listUsers();

// selector 支持：authId / meegoUserKey / 最近登录顺序的数字下标（与 CLI 一致）
await client.auth.switchUser("0");

// 删除用户需要 authId
await client.auth.deleteUser(users[0]!.authId);
```

示例：录制抓包

```ts
import os from "node:os";
import { OpenMeego } from "openmeego";

const client = new OpenMeego({ homeDir: os.homedir() });

const capture = await client.command.capture({
  startUrl: "https://project.example.com/mock/ai-nodes",
  intent: "查询 AI 节点列表并输出在线/待上线统计"
});

console.log(capture.capturedRequests);
```

外部 agent 根据抓包结果生成 `RecordedCommand` 后，再调用 SDK 保存：

```ts
await client.command.save("ai-nodes", {
  createdAt: new Date().toISOString(),
  description: "查询 AI 节点统计",
  name: "ai-nodes",
  steps: [{ method: "GET", pathTemplate: "/mock/api/ai-nodes" }],
  variables: []
});

const result = await client.command.run("ai-nodes", {
  variables: {
    // 录制时标记为 input 的变量需要在这里补齐
  }
});

console.log(result.outputVariables);
```

命令只保存相对接口路径。执行时使用当前登录用户对应的项目域名，不读取命令文件里的项目域名。

命令变量如果是对象或数组，应在 `command.json` 的变量上写入 `jsonSchema`。第三方调用方可以在执行前读取 schema；openmeego 不再生成旁路的 `.types.ts` 契约文件：

```json
{
  "name": "filters",
  "description": "筛选条件",
  "type": "input",
  "jsonSchema": {
    "type": "object",
    "required": ["status"],
    "properties": {
      "status": {
        "type": "array",
        "items": { "type": "string" }
      }
    }
  }
}
```

说明：SDK 当前聚焦登录、抓包录制和命令执行能力，不提供独立的对话式 agent 会话封装。

## 环境

- Node.js
- pnpm
- Playwright Chromium

## 安装依赖

```bash
pnpm install
```

## 开发和构建

开发模式直接运行：

```bash
pnpm dev -- --help
```

构建：

```bash
pnpm build
```

测试：

```bash
pnpm test
pnpm test:unit
```

构建后运行：

```bash
node dist/cli.js --help
```

如果你已经把这个包链接到全局，也可以直接使用：

```bash
openmeego --help
```

## CLI 用法

## 命令总览

```bash
openmeego login [--domain <domain>]
openmeego user [selector]
openmeego command record <url> [--intent <text>]
openmeego command list
openmeego command delete <name>
openmeego command import <github-url> [--name <name>] [--force]

# 运行命令（命令名来自 command.save、远程导入或内置命令）
openmeego <commandName> [--var1 <value1> --var2 <value2> ...]
```

运行命令时，请先切换到目标域名下的登录用户；命令请求会发往该用户的项目域名。命令文件不保存项目域名。

## 登录

默认登录域名（示例，实际请替换为你的飞书项目域名）：

```text
https://project.example.com
```

直接登录默认域名：

```bash
openmeego login
```

登录指定域名，支持传 host：

```bash
openmeego login --domain project-alt.example.com
```

也支持传完整 URL：

```bash
openmeego login --domain https://project-alt.example.com
```

登录流程：

1. 打开飞书项目登录页
2. 自动切到扫码登录
3. 终端输出二维码
4. 如果有多个工作区，终端内选择工作区
5. 登录完成后保存当前账号

## 用户切换和管理

不带参数直接进入交互模式：

```bash
openmeego user
```

交互模式下会：

- 按域名分组显示已登录用户
- 标记当前正在使用的账号
- 支持切换和删除

快捷键：

- `↑` / `↓`：上下选择
- `Enter`：切换到选中用户
- `d`：删除选中用户
- `q`：退出
- `Ctrl+C`：取消

### 用 selector 直接切换

也可以不进交互列表，直接指定 selector：

```bash
openmeego user <selector>
```

支持的 selector 形式：

- `authId`
- `meegoUserKey`
- 最近登录顺序的数字下标

示例：

```bash
openmeego user project.example.com__meego-user-key
openmeego user meego-user-key
openmeego user 0
```

说明：

- `authId` 的格式是 `<domain-host>__<meegoUserKey>`
- 如果同一个 `meegoUserKey` 在多个域名下都存在，直接传 `meegoUserKey` 会报错，此时请使用 `authId`，或者直接执行 `openmeego user` 进入交互模式选择
- 数字下标按最近登录时间倒序排序，`0` 表示当前列表第一项

## 录制导出

录制命令会打开浏览器并捕获同项目域名下的接口请求。openmeego 只导出抓包结果，不在本地判断业务语义，也不生成命令。

```bash
openmeego command record https://project.example.com/mock/ai-nodes --intent 查询节点统计
```

浏览器关闭后，结果会写入 `~/.openmeego/recordings/<timestamp>.json`。外部 agent 读取该文件，生成 `RecordedCommand` 后再通过 SDK 保存。

## 命令来源

命令有两个来源：

- `builtin`：openmeego 包内置的只读命令，例如 `install-plugin`、`check-plugin-installed`、`list-manageable-projects`
- `local`：保存在 `~/.openmeego/commands/` 的本地命令

本地命令与内置命令同名时，本地命令优先。`openmeego command list` 会显示来源；`openmeego command delete <name>` 只删除本地命令，不能删除内置命令。

远程命令仓库应把命令放在 `.openmeego/commands/` 下：

```text
.openmeego/commands/<name>/command.json
```

`openmeego command import <github-url>` 不传 `--name` 时会导入仓库中发现的全部命令；传 `--name <name>` 时只导入指定命令。

## 本地存储

登录信息保存在：

```text
~/.openmeego/auth/
```

其中：

- `~/.openmeego/auth/.index.json`：账号索引和当前账号
- `~/.openmeego/auth/<authId>`：对应账号的 cookies 文件
- `~/.openmeego/recordings/`：录制抓包结果

因为存储是按 `authId` 隔离的，所以同一个 `meegoUserKey` 在不同飞书项目域名下可以同时存在，不会互相覆盖。

## 帮助

查看总帮助：

```bash
openmeego --help
```

查看登录帮助：

```bash
openmeego login --help
```

查看用户切换帮助：

```bash
openmeego user --help
```
