# Infinite Canvas Agent

本地 Canvas Agent 用来连接网站和用户自己电脑上的 Codex。它还负责持久化 Flow C 脚本队列、分段调用本机 Codex、自动回传草案，以及在用户明确点击“一键下载本批全部”后把完成视频校验并保存到所选磁盘目录。

## 启动

### FastMoss 视频搜索（0.4.103 起）

新建参考任务使用官方视频搜索 API。将自己的密钥写入 `~/.infinite-canvas/secrets/fastmoss.json` 的 `apiKey` 字段，或设置仅供 Agent 读取的 `FASTMOSS_API_KEY`；密钥不传给网页。接口为 `https://openapi.fastmoss.com/video/v1/search`，使用 Bearer 请求头。国家、日期和点赞筛选与任务一起保存，每个搜索词只提交一次；不确定请求须核对，不自动重复消耗额度。

旧任务按保存的数据来源接续。新 API 任务的原片沿用已配置 TikWM，失败明确暂停，不回退 Chrome 采集。API 视频指标仅用于找参考，不代表商品销量或转化。

### 可选：TikWM 原片直连（0.4.99 起）

在运行 Agent 的用户目录 `~/.infinite-canvas/secrets/tikwm.json` 配置 `{"apiKey":"你自己的密钥"}`，限制为当前用户可读写（Windows 使用用户/SYSTEM ACL）。密钥仅由本机读取，不放到网页、项目仓库、日志或客户包。官方接口合同见 https://tikwmapi.com/docs.html ，经 `x-tikwmapi-key` 请求头发送到 `https://api.tikwmapi.com/`；媒体下载不携带密钥。

完整 TikTok 作者/视频编号链接优先复用已匹配的本地原片，再走已配置 TikWM；未配置时保留原下载器与 Chrome 扩展路径。配置后的密钥、额度、限流或网络错误会明确暂停，不偷偷切换付费服务。旧 ID-only 与站内归档地址保持原路由。网页在当前已选参考集合内先保存全部原片，再逐条反推；自动主任务仍逐商品处理，不代表全批预下载。

成功缓存保留 48 小时，按精确 ID、作者、SHA-256 和实际视频流验证，复用不消耗新解析请求。同一本机解析串行，单片失败最多每小时 3 次且间隔至少 30 秒；额度和限流响应持久化，禁止超限自动升级。一次解析请求不保证成功下载一条视频，额度以供应商账户为准。进程异常留下无法验证的锁/孤立缓存文件时保守暂停，需要核对，不会覆盖、盲重取或宣布已完成。

```bash
npx -y @xiaohhhh1/canvas-agent
```

需要排查连接、线程、Codex app-server 或工具调用问题时，可开启 Debug 模式：

```bash
npx -y @xiaohhhh1/canvas-agent --debug
```

Debug 日志会以 `[DEBUG][HH:mm:ss]` 等传统格式输出到终端，并按启动日期保存到 `~/.infinite-canvas/logs/canvas-agent-YYYY-MM-DD.log`。终端日志带级别颜色，文件日志为纯文本；日志包含 HTTP、SSE、线程、turn、Codex app-server 和工具调用事件，token 与图片 Data URL 会自动隐藏。

本仓库开发时也可以直接运行：

```bash
cd canvas-agent
npm install
npm run build
node dist/index.js
```

启动后会输出本机地址和 token：

```txt
Local URL: http://127.0.0.1:17371
Connect token: xxxxxx
```

在画布右上角点击 `Agent`，填入地址和 token 后连接。

Codex app 插件会读取启动输出里的 Local URL 和 Connect token，并直接打开画布网页地址；Canvas Agent 不负责生成画布打开 URL。

Canvas Agent 默认只监听 `127.0.0.1`。网页第一次带正确 token 连接后，Canvas Agent 会记录该网页 Origin；之后其他 Origin 不能复用这个本地 Agent，除非用户清理 `~/.infinite-canvas/canvas-agent.json` 里的 `origins`。

## 发布

`canvas-agent` 使用自己的 `package.json` 版本号，不跟仓库根目录 `VERSION` 绑定。推送到 `main` 后，GitHub Actions 会检查 npm 上是否已经存在当前包版本；不存在时才发布 `@xiaohhhh1/canvas-agent`。

发布前需要在 GitHub 仓库 Secrets 中配置 `NPM_TOKEN`。

## Codex MCP

如果希望 Codex 终端能直接操作画布，需要先把 Canvas Agent 注册成 Codex MCP。

直接运行 `npx -y @xiaohhhh1/canvas-agent` 只启动本地 Agent 服务，不会安装 MCP，也不会增加 Codex 工具上下文。只有安装 Codex app 插件，或手动执行 `codex mcp add` 后，`infinite-canvas` 工具才会进入 Codex 上下文；由于工具较多，不使用时建议移除。

通过插件安装时移除插件：

```bash
codex plugin remove infinite-canvas
```

手动添加 MCP 时移除 MCP：

```bash
codex mcp remove infinite-canvas
```

### Codex app 插件

仓库内提供了 Codex app 插件：`plugins/infinite-canvas`。在 Codex app 中添加本仓库的 marketplace 后，可以安装 `Infinite Canvas` 插件；插件会注册同一个 `infinite-canvas` MCP，并带上画布操作说明。

添加本地 marketplace 时建议使用仓库绝对路径，避免 Codex 从其他工作目录解析失败：

```bash
cd /path/to/infinite-canvas
codex plugin marketplace add "$(pwd)"
codex plugin add infinite-canvas@infinite-canvas-local
```

插件默认通过 npm 启动 MCP。MCP 启动时会自动检查并拉起常驻本机 HTTP/中继服务，因此客户安装插件后不需要另开终端：

```bash
npx -y @xiaohhhh1/canvas-agent mcp
```

使用时可以直接打开 `https://canvas.xiaohhhh1.com/workflow-batches`。网站通过已认证的 Agent Relay 与本机助手通信，不把本机目录、Codex 登录信息或短期任务令牌显示给客户。

## Flow C 本机后台工作流

1. 客户在网站添加一个或多个产品，按顺序上传每个产品 1–5 张图片并填写数量。
2. 点击“交给本机 Codex 写全部脚本”。本机助手每次只处理 10 条并持久化进度，断网或重启后可继续；脚本完成会自动回传网站，不创建付费任务。
3. 客户审阅脚本并确认费用后，中心 `workflow-runner` 才执行故事板和视频生成。
4. 客户先选择一个本机目录，再对需要的批次点击“一键下载本批全部”。登录另一台电脑、选择文件夹或查看历史批次都不会触发下载。Agent 以最多四路并行写 `.part`，校验大小与 SHA-256 后原子改名；清单已记录且校验有效的批次序号不会重复下载。

本机持久状态默认保存在 `~/.infinite-canvas/workflow-state.json`，权限设为仅当前用户可读写。这里包含短期能力令牌和本机路径，不应上传、提交到 Git 或发到聊天中。

Canvas Agent 启动后，给 Codex 添加 MCP：

```bash
codex mcp add infinite-canvas -- npx -y @xiaohhhh1/canvas-agent mcp
```

本仓库开发时可以改成，实际使用建议替换为本机绝对路径：

```bash
codex mcp add infinite-canvas -- node /path/to/infinite-canvas/canvas-agent/dist/index.js mcp
```

Canvas Agent 源码使用 TypeScript 编写，MCP 协议层使用官方 `@modelcontextprotocol/sdk`，工具入参使用 `zod` 描述。

如果希望终端里的 Codex 不被 MCP 审批卡住，可以在 `~/.codex/config.toml` 里给这个 MCP 设置自动放行：

```toml
[mcp_servers.infinite-canvas]
command = "npx"
args = ["-y", "@xiaohhhh1/canvas-agent", "mcp"]
default_tools_approval_mode = "approve"
```

可用工具：

- `canvas_get_state`
- `canvas_get_selection`
- `canvas_export_snapshot`
- `canvas_apply_ops`
- `canvas_create_text_node`
- `canvas_create_image_prompt_flow`

`canvas_apply_ops` 示例：

```json
{
  "ops": [
    {
      "type": "add_node",
      "nodeType": "text",
      "title": "标题",
      "position": { "x": 0, "y": 0 },
      "metadata": { "content": "文本内容" }
    }
  ]
}
```

## 侧边栏 Codex

本地面板会把提示词发送给 Canvas Agent。Canvas Agent 使用官方 `@openai/codex` CLI 的 `codex app-server --stdio` 启动并复用同一个 Codex thread，启动时会注入 `infinite-canvas` MCP 配置并自动放行 MCP 审批，真正执行画布修改前仍由网页侧边栏二次确认。

侧边栏会展示 Codex 返回的 `thread.started`、`turn.started`、`item.*`、`turn.completed` 等结构化事件；Canvas Agent 会合并短时间内的回复、思考摘要和命令输出增量，网页使用同一条消息持续更新，并把任务进度、计划、搜索、文件修改与工具操作整理为中文过程时间线。

侧边栏上传或粘贴的图片会先发到本机 Canvas Agent，再由 Canvas Agent 临时写入本机文件并作为 app-server `localImage` 输入传给 Codex；前端会提示附件体积，单次请求体限制为 30MB。

## Claude Code

Claude Code Adapter 代码暂时保留，但当前网页侧边栏只开放 Codex。后续开放 Claude 入口时，Canvas Agent 会调用本机 `claude -p --output-format stream-json` 并把流式 JSON 事件转发到侧边栏。

如果希望 Claude Code 也能操作画布，需要给 Claude Code 添加同一个 MCP。建议用 user scope，避免 Canvas Agent 从不同目录启动时找不到配置：

```bash
claude mcp add --scope user --transport stdio infinite-canvas -- npx -y @xiaohhhh1/canvas-agent mcp
```

本仓库开发时可以改成：

```bash
claude mcp add --scope user --transport stdio infinite-canvas -- node /path/to/infinite-canvas/canvas-agent/dist/index.js mcp
```

Canvas Agent 调用 Claude Code 时会默认带上 `--allowedTools mcp__infinite-canvas__*`，画布写操作仍由网页侧边栏确认。
