Google Workspace CLI (GWS)

ClawSkills 作者 cyrushuang1995-cmyk v2.1.2

Google Workspace CLI. Use when the user mentions Gmail, Google Drive, Calendar, Sheets, Docs, Tasks, People, Slides, Forms, Meet, Classroom, sending email, checking inbox, managing files, reading/writing spreadsheets, viewing schedules, standup reports, or any Google Workspace operation — even if they don't explicitly say 'gws'.

源码 ↗

安装 / 下载方式

TotalClaw CLI推荐
totalclaw install clawskills:cyrushuang1995-cmyk~gws-google-workspace
cURL直接下载,无需登录
curl -fsSL https://skills.taituai.com/api/skills/clawskills%3Acyrushuang1995-cmyk~gws-google-workspace/file -o gws-google-workspace.md
Git 仓库获取源码
git clone https://github.com/openclaw/skills/commit/3b9c2411abc441a7fbdb76bdc8ed6663e6565c4d
# GWS — Google Workspace CLI

Google's official Workspace CLI (`@googleworkspace/cli`). One tool for Gmail, Drive, Calendar, Sheets, Docs, Tasks, People, Slides, Forms, Meet, Classroom, and more.

GitHub: https://github.com/googleworkspace/cli

## Setup

Each session, set these before using `gws`:

```bash
export GOOGLE_WORKSPACE_PROJECT_ID=<your-project-id>
export GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE=~/.config/gws/credentials.json
export GOOGLE_WORKSPACE_CLI_KEYRING_BACKEND=file
```

First-time setup and authorization: see **Prerequisites** below.

## Prerequisites

### 1. 安装 gws

```bash
npm install -g @googleworkspace/cli
```

### 2. GCP Console 配置

前往 [Google Cloud Console → APIs & Services → Library](https://console.cloud.google.com/apis/library),启用以下 API:

| 服务 | API 名称 |
|------|----------|
| Gmail | Gmail API |
| Drive | Google Drive API |
| Calendar | Google Calendar API |
| Sheets | Google Sheets API |
| Docs | Google Docs API |
| Tasks | Tasks API |
| People | People API |
| Slides | Google Slides API |
| Forms | Forms API |
| Meet | Google Meet API |
| Classroom | Google Classroom API |

大部分 API 在 `gws auth login` 时会自动关联,但 Sheets/Docs/Slides 等可能需要手动启用后才能调用。

**重要:启用 API 和 OAuth scope 是两回事。** API 启用决定"能不能调这个服务",OAuth scope 决定"能做什么操作",两者都需要。

### 3. OAuth 授权

`gws` 是无头 CLI,授权流程需要用户在浏览器中完成:

```bash
gws auth login
```

1. CLI 输出 OAuth URL
2. **将链接发给用户**,让用户在浏览器中打开并授权
3. 用户将回调页面中的授权码复制回来
4. 在 CLI 中粘贴授权码,完成认证

凭证保存在 `GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE` 指定的路径。`gws auth login -s <service>` 支持分批授权特定服务,不会覆盖已有 scope。

如果遇到 `insufficient authentication scopes` 错误,重新运行 `gws auth login` 并勾选缺少的权限。

## Troubleshooting

- **`insufficient authentication scopes`** → 见 Prerequisites > Scope 说明,重新授权并勾选缺少的权限
- **`File not found`** → 检查是否使用了绝对路径,改用相对路径(见 Usage Philosophy)
- **上传后文件名为 "Untitled"** → 用 `files update` 重命名(见 Known API Quirks)
- **参数不确定** → `gws schema <api.method>` 查询任意 API 的完整参数结构
- **API 未启用** → 见 Prerequisites > GCP Console,启用对应 API

---

## Gmail

**Gmail** 是最常用的服务,支持完整的邮件 CRUD、搜索、标签、附件、线程、批量操作和设置管理。

每次 `gws` 调用有 ~2-3s 启动延迟,批量操作优先(`batchModify` 每批 ≤100 条)。逐条 get 邮件可用 `&` 并行 + `wait` 加速。

### 搜索与列表

Gmail 搜索语法通过 `q` 参数传递,功能强大:`newer_than:1d`、`is:starred`、`is:unread`、`from:xxx`、`subject:keyword`、`label:xxx`、`has:attachment`、`after:YYYY/MM/DD`、`before:YYYY/MM/DD`、`category:primary`(primary/promotions/social/updates/forums)等。

```bash
gws gmail users messages list --params '{"userId":"me","q":"is:unread","maxResults":20}'
gws gmail users messages list --params '{"userId":"me","q":"is:unread"}' --page-all
```

### 读取邮件

`messages list` 仅返回 ID,需逐条 `get`。只需要摘要用 `format=metadata`(更快省 token),需要正文用 `format=full`。

**注意**:API 返回的 header 顺序不固定(按内部存储顺序,非请求顺序),**必须按 header name 匹配,不能按数组 index 取值。**

邮件正文 parts 结构不固定——有些是单层 `.payload.parts[]`,有些是嵌套 `.payload.parts[].parts[]`,两种写法都要准备好。

```bash
# 提取 headers(按 name 匹配,不要按 index)
gws gmail users messages get --params '{"userId":"me","id":"MSG_ID","format":"metadata","metadataHeaders":["From","Subject","Date"]}'
# → jq '.payload.headers | map({(.name): .value}) | add'

# 纯文本正文(先试单层,为空再试嵌套)
gws gmail users messages get --params '{"userId":"me","id":"MSG_ID","format":"full"}' | jq -r '.payload.parts[] | select(.mimeType == "text/plain") | .body.data' | base64 -d
# 嵌套备选: jq -r '.payload.parts[].parts[]? | select(.mimeType == "text/plain") | .body.data' | base64 -d

# 快速预览(无需 base64,但有长度限制)
gws gmail users messages get --params '{"userId":"me","id":"MSG_ID","format":"metadata"}' | jq -r '.snippet'
```

### 并行批量读取

利用 `&` 后台并行将 N×3s 降到 ~3s:

```bash
IDS=$(gws gmail users messages list --params '{"userId":"me","q":"is:unread","maxResults":10}' 2>/dev/null | jq -r '.messages[].id')
for id in $IDS; do
  gws gmail users messages get --params "{\"userId\":\"me\",\"id\":\"$id\",\"format\":\"metadata\",\"metadataHeaders\":[\"From\",\"Subject\",\"Date\"]}" 2>/dev/null | jq -r '.payload.headers | map({(.name): .value}) | add | "\(.From[:30]) | \(.Subject) — \(.Date)"' &
done; wait
```

### 批量操作

`batchModify` 一次处理最多 100 条,避免逐条循环的延迟开销:

```bash
IDS=$(gws gmail users messages list --params '{"userId":"me","q":"is:unread","maxResults":100}' 2>/dev/null | jq -c '[.messages[].id]')
gws gmail users messages batchModify --params '{"userId":"me"}' --json "{\"ids\":$IDS,\"removeLabelIds\":[\"UNREAD\"]}"
gws gmail users messages batchModify --params '{"userId":"me"}' --json "{\"ids\":$IDS,\"addLabelIds\":[\"STARRED\"]}"
```

### 发送邮件

构造 RFC 2822 格式邮件,Base64 编码后发送:

```bash
# 纯文本
RAW=$(printf "To: recipient@example.com\r\nSubject: Hello\r\nFrom: me@gmail.com\r\nContent-Type: text/plain; charset=utf-8\r\n\r\nBody text here" | base64 -w0)
gws gmail users messages send --json "{\"raw\":\"$RAW\"}" --params '{"userId":"me"}'

# HTML(改 Content-Type 为 text/html)
RAW=$(printf "To: recipient@example.com\r\nSubject: Hello\r\nFrom: me@gmail.com\r\nContent-Type: text/html; charset=utf-8\r\n\r\n<h1>Title</h1><p>Body</p>" | base64 -w0)
gws gmail users messages send --json "{\"raw\":\"$RAW\"}" --params '{"userId":"me"}'
```

### 附件下载

先从 `format=full` 响应中提取 `attachmentId`,再用 `attachments get` 下载(同样受相对路径限制):

```bash
# 1. 获取附件列表
gws gmail users messages get --params '{"userId":"me","id":"MSG_ID","format":"full"}' | jq '[.payload.parts[] | select(.filename != "") | {filename, body: .body.attachmentId}]'

# 2. 下载(cd 到目标目录)
cd /path/to/target/dir
gws gmail users messages attachments get --params '{"userId":"me","messageId":"MSG_ID","id":"ATTACHMENT_ID"}' --output filename.pdf
```

### 线程 / 回复链

按对话线程查看邮件,避免重复同一封邮件的多个副本:

```bash
gws gmail users threads list --params '{"userId":"me","q":"is:unread","maxResults":10}'
gws gmail users threads get --params '{"userId":"me","id":"THREAD_ID","format":"metadata"}'
```

### 标签管理

```bash
gws gmail users labels list --params '{"userId":"me"}' | jq '.labels[] | {id, name, type}'
gws gmail users labels create --json '{"name":"Projects/AI","labelListVisibility":"labelShow","messageListVisibility":"show"}' --params '{"userId":"me"}'
gws gmail users messages batchModify --params '{"userId":"me"}' --json '{"ids":["MSG_ID"],"addLabelIds":["LABEL_ID"]}'
```

### Trash

```bash
gws gmail users messages trash --params '{"userId":"me","id":"MSG_ID"}'
gws gmail users messages untrash --params '{"userId":"me","id":"MSG_ID"}'
```

### 设置

```bash
gws gmail users settings getVacation --params '{"userId":"me"}'
gws gmail users settings sendAs list --params '{"userId":"me"}'
```

---

## Drive

**Drive** 支持文件和文件夹的完整生命周期管理。所有 `--upload` 和 `--output` 路径仅支持相对路径,必须先 `cd` 到目标目录。

### 浏览与搜索

```bash
gws drive files list --params '{"pageSize":10,"orderBy":"modifiedTime desc"}'
gws drive files list --params '{"q":"mimeType=\"application/vnd.google-apps.spreadsheet\""}'
gws drive files list --params '{"q":"'\''FOLDER_ID'\'' in parents"}'
```

### 上传(两步命名)

`files create` 的 name 参数无效(CLI 未传递给 API),上传后文件名始终为 "Untitled",必须先上传再 rename。注意:`files copy` 的 name 参数有效,不受此限制。

```bash
cd /path/to/target/dir
gws drive files create --params '{}' --upload file.txt --upload-content-type text/plain
gws drive files update --params '{"fileId":"FILE_ID"}' --json '{"name":"real_name.txt"}'
```

### 创建文件夹

```bash
gws drive files create --params '{}' --json '{"name":"Folder Name","mimeType":"application/vnd.google-apps.folder"}'
```

### 复制与移动

`files copy` 的 name 参数有效(与 upload 不同),可一步完成:

```bash
# 复制(可同时重命名)
gws drive files copy --params '{"fileId":"ID"}' --json '{"name":"Copy of file"}'

# 移动到文件夹
gws drive files update --params '{"fileId":"ID","addParents":"FOLDER_ID","removeParents":"root"}' --json '{}'
```

### 下载与导出

**决策原则**:原生文件(txt, pdf, docx 等)用 `get --alt media`;Google 原生格式(Sheets, Docs, Slides)用 `export` 转换。

```bash
gws drive files get --params '{"fileId":"ID","alt":"media"}' --output file.txt
gws drive files export --params '{"fileId":"ID","mimeType":"application/pdf"}' --output doc.pdf
gws drive files export --params '{"fileId":"ID","mimeType":"text/csv"}' --output data.csv
```

### 权限与存储

```bash
gws drive permissions list --params '{"fi