OA0 = Omni AI 0
OA0 是一个探索 AI 的论坛
现在注册
已注册用户请  登录
OA0  ›  技能包  ›  glance:创建、更新并管理 Glance 仪表板小部件

glance:创建、更新并管理 Glance 仪表板小部件

 
  analytics ·  2026-02-08 09:37:02 · 3 次点击  · 0 条评论  

名称: glance
描述: "创建、更新和管理 Glance 仪表板小组件。当用户想要:向仪表板添加内容、创建小组件、可视化跟踪数据、显示指标/统计数据、展示 API 数据或监控使用情况时使用。"
元数据:
openclaw:
emoji: "🖥️"
homepage: "https://github.com/acfranzen/glance"
requires:
env: ["GLANCE_URL"]
bins: ["curl"]
primaryEnv: GLANCE_URL


Glance

AI 可扩展的个人仪表板。使用自然语言创建自定义小组件——AI 负责数据收集。

特性

  • 自定义小组件 — 通过 AI 创建小组件,自动生成 JSX 代码
  • 代理刷新 — AI 按计划收集数据并推送到缓存
  • 仪表板导出/导入 — 共享小组件配置
  • 凭证管理 — 安全的 API 密钥存储
  • 实时更新 — 通过 Webhook 触发的即时刷新

快速开始

# 导航到技能目录(如果通过 ClawHub 安装)
cd "$(clawhub list | grep glance | awk '{print $2}')"

# 或直接克隆
git clone https://github.com/acfranzen/glance ~/.glance
cd ~/.glance

# 安装依赖
npm install

# 配置环境
cp .env.example .env.local
# 使用你的设置编辑 .env.local 文件

# 启动开发服务器
npm run dev

# 或构建并启动生产环境
npm run build && npm start

仪表板运行在 http://localhost:3333

配置

编辑 .env.local 文件:

# 服务器
PORT=3333
AUTH_TOKEN=your-secret-token        # 可选:Bearer 令牌认证

# OpenClaw 集成(用于即时小组件刷新)
OPENCLAW_GATEWAY_URL=https://localhost:18789
OPENCLAW_TOKEN=your-gateway-token

# 数据库
DATABASE_PATH=./data/glance.db      # SQLite 数据库位置

服务安装 (macOS)

# 创建 launchd plist 文件
cat > ~/Library/LaunchAgents/com.glance.dashboard.plist << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.glance.dashboard</string>
    <key>ProgramArguments</key>
    <array>
        <string>/opt/homebrew/bin/npm</string>
        <string>run</string>
        <string>dev</string>
    </array>
    <key>WorkingDirectory</key>
    <string>~/.glance</string>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <true/>
    <key>StandardOutPath</key>
    <string>~/.glance/logs/stdout.log</string>
    <key>StandardErrorPath</key>
    <string>~/.glance/logs/stderr.log</string>
</dict>
</plist>
EOF

# 加载服务
mkdir -p ~/.glance/logs
launchctl load ~/Library/LaunchAgents/com.glance.dashboard.plist

# 服务命令
launchctl start com.glance.dashboard
launchctl stop com.glance.dashboard
launchctl unload ~/Library/LaunchAgents/com.glance.dashboard.plist

环境变量

变量 描述 默认值
PORT 服务器端口 3333
AUTH_TOKEN API 认证的 Bearer 令牌
DATABASE_PATH SQLite 数据库路径 ./data/glance.db
OPENCLAW_GATEWAY_URL 用于 Webhook 的 OpenClaw 网关
OPENCLAW_TOKEN OpenClaw 认证令牌

要求

  • Node.js 20+
  • npm 或 pnpm
  • SQLite(已捆绑)

小组件技能

创建和管理仪表板小组件。大多数小组件使用 agent_refresh——负责收集数据。

快速开始

# 检查 Glance 是否正在运行(列出小组件)
curl -s -H "Origin: $GLANCE_URL" "$GLANCE_URL/api/widgets" | jq '.custom_widgets[].slug'

# 认证说明:带有 Origin 头的本地请求绕过 Bearer 令牌认证
# 对于外部访问,请使用:-H "Authorization: Bearer $GLANCE_TOKEN"

# 刷新小组件(查找指令,收集数据,POST 到缓存)
sqlite3 $GLANCE_DATA/glance.db "SELECT json_extract(fetch, '$.instructions') FROM custom_widgets WHERE slug = 'my-widget'"
# 按照指令操作,然后:
curl -X POST "$GLANCE_URL/api/widgets/my-widget/cache" \
  -H "Content-Type: application/json" \
  -H "Origin: $GLANCE_URL" \
  -d '{"data": {"value": 42, "fetchedAt": "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'"}}'

# 在浏览器中验证
browser action:open targetUrl:"$GLANCE_URL"

AI 结构化输出生成(必需)

生成小组件定义时,请使用 JSON 模式 docs/schemas/widget-schema.json 配合你的 AI 模型的结构化输出模式:
- Anthropic:使用 tool_use 配合模式
- OpenAI:使用 response_format: { type: "json_schema", schema }

该模式在生成时强制执行所有必需字段——无法生成格式错误的小组件。

必需字段清单

每个小组件必须包含以下字段(模式会强制执行):

字段 类型 说明
name 字符串 非空,人类可读
slug 字符串 小写 kebab-case (my-widget)
source_code 字符串 包含 Widget 函数的有效 JSX
default_size { w: 1-12, h: 1-20 } 网格单位
min_size { w: 1-12, h: 1-20 } 无法调整到更小
fetch.type 枚举 "server_code" | "webhook" | "agent_refresh"
fetch.instructions 字符串 如果类型是 agent_refresh 则必需
fetch.schedule 字符串 如果类型是 agent_refresh 则必需 (cron 表达式)
data_schema.type "object" 始终为 object
data_schema.properties 对象 定义每个字段
data_schema.required 数组 必须包含 "fetchedAt"
credentials 数组 如果不需要则使用 []

示例:最小有效小组件

{
  "name": "我的小组件",
  "slug": "my-widget",
  "source_code": "function Widget({ serverData }) { return <div>{serverData?.value}</div>; }",
  "default_size": { "w": 2, "h": 2 },
  "min_size": { "w": 1, "h": 1 },
  "fetch": {
    "type": "agent_refresh",
    "schedule": "*/15 * * * *",
    "instructions": "## 数据收集\n收集数据...\n\n## 缓存更新\nPOST 到 /api/widgets/my-widget/cache"
  },
  "data_schema": {
    "type": "object",
    "properties": {
      "value": { "type": "number" },
      "fetchedAt": { "type": "string", "format": "date-time" }
    },
    "required": ["value", "fetchedAt"]
  },
  "credentials": []
}

⚠️ 小组件创建清单(强制)

每个小组件在完成前必须完成所有步骤:

□ 步骤 1:创建小组件定义 (POST /api/widgets)
    - 包含 Widget 函数的 source_code
    - data_schema(验证必需)
    - fetch 配置(agent_refresh 的类型 + 指令)

□ 步骤 2:添加到仪表板 (POST /api/widgets/instances)
    - custom_widget_id 与定义匹配
    - 设置 title 和 config

□ 步骤 3:填充缓存(针对 agent_refresh 小组件)
    - 数据与 data_schema 完全匹配
    - 包含 fetchedAt 时间戳

□ 步骤 4:设置 cron 任务(针对 agent_refresh 小组件)
    - 简单消息:"⚡ WIDGET REFRESH: {slug}"
    - 适当的计划(通常为 */15 或 */30)

□ 步骤 5:浏览器验证(强制)
    - 打开 http://localhost:3333
    - 小组件在仪表板上可见
    - 显示实际数据(非加载旋转器)
    - 数据值与缓存匹配
    - 无错误或布局损坏

⛔ 在步骤 5 通过之前,不要报告小组件已完成!

快速参考

小组件包结构

小组件包
├── meta (名称, slug, 描述, 作者, 版本)
├── widget (source_code, default_size, min_size)
├── fetch (server_code | webhook | agent_refresh)
├── dataSchema? (缓存数据的 JSON 模式 - POST 时验证)
├── cache (ttl, staleness, fallback)
├── credentials[] (API 密钥, 本地软件要求)
├── config_schema? (用户选项)
└── error? (重试, 回退, 超时)

获取类型决策树

数据是否可通过小组件调用的 API 获取?
├── 是 → 使用 server_code
└── 否 → 是否有外部服务推送数据?
    ├── 是 → 使用 webhook
    └── 否 → 使用 agent_refresh(你收集数据)
场景 获取类型 谁收集数据?
公共/认证 API server_code 小组件在渲染时调用 API
外部服务推送数据 webhook 外部服务 POST 到缓存
本地 CLI 工具 agent_refresh 你(代理)通过 PTY/exec
交互式终端 agent_refresh 你(代理)通过 PTY
计算/聚合数据 agent_refresh 你(代理)按计划

⚠️ agent_refresh 意味着你是数据源。 你设置一个 cron 来提醒自己,然后你使用你的工具(exec、PTY、浏览器等)收集数据并 POST 到缓存。

API 端点

小组件定义

方法 端点 描述
POST /api/widgets 创建小组件定义
GET /api/widgets 列出所有定义
GET /api/widgets/:slug 获取单个定义
PATCH /api/widgets/:slug 更新定义
DELETE /api/widgets/:slug 删除定义

小组件实例(仪表板)

方法 端点 描述
POST /api/widgets/instances 将小组件添加到仪表板
GET /api/widgets/instances 列出仪表板小组件
PATCH /api/widgets/instances/:id 更新实例(配置、位置)
DELETE /api/widgets/instances/:id 从仪表板移除

凭证

方法 端点 描述
GET /api/credentials 列出凭证 + 状态
POST /api/credentials 存储凭证
DELETE /api/credentials/:id 删除凭证

创建小组件

完整小组件包结构

{
  "name": "GitHub PRs",
  "slug": "github-prs",
  "description": "显示打开的拉取请求",

  "source_code": "function Widget({ serverData }) { ... }",
  "default_size": { "w": 2, "h": 2 },
  "min_size": { "w": 1, "h": 1 },
  "refresh_interval": 300,

  "credentials": [
    {
      "id": "github",
      "type": "api_key",
      "name": "GitHub 个人访问令牌",
      "description": "具有 repo 范围的令牌",
      "obtain_url": "https://github.com/settings/tokens"
    }
  ],

  "fetch": {
    "type": "agent_refresh",
    "schedule": "*/5 * * * *",
    "instructions": "从 GitHub API 获取打开的 PR 并 POST 到缓存端点",
    "expected_freshness_seconds": 300,
    "max_staleness_seconds": 900
  },

  "cache": {
    "ttl_seconds": 300,
    "max_staleness_seconds": 900,
    "storage": "sqlite",
    "on_error": "use_stale"
  },

  "setup": {
    "description": "配置 GitHub 令牌",
    "agent_skill": "通过 /api/credentials 存储 GitHub PAT",
    "verification": {
      "type": "cache_populated",
      "target": "github-prs"
    },
    "idempotent": true
  }
}

获取类型

类型 何时使用 数据流
server_code 小组件可以直接调用 API 小组件 → server_code → API
agent_refresh 代理必须获取/计算数据 代理 → POST /cache → 小组件读取
webhook 外部服务推送数据 外部 → POST /cache → 小组件读取

大多数小组件应使用 agent_refresh——代理按计划获取数据并推送到缓存端点。

步骤 1:创建小组件定义

POST /api/widgets
Content-Type: application/json

{
  "name": "GitHub PRs",
  "slug": "github-prs",
  "description": "显示打开的拉取请求",
  "source_code": "function Widget({ serverData }) { ... }",
  "default_size": { "w": 2, "h": 2 },
  "credentials": [...],
  "fetch": { "type": "agent_refresh", "schedule": "*/5 * * * *", ... },
  "data_schema": {
    "type": "object",
    "properties": {
      "prs": { "type": "array", "description": "PR 对象列表" },
      "fetchedAt": { "type": "string", "format": "date-time" }
    },
    "required": ["prs", "fetchedAt"]
  },
  "cache": { "ttl_seconds": 300, ... }
}

data_schema(必需) 定义了获取器与小组件之间的数据契约。缓存 POST 会针对它进行验证——格式错误的数据返回 400。

⚠️ 创建小组件时始终包含 data_schema。这确保:
1. 缓存 POST 时的数据验证(模式不匹配时返回 400)
2. 预期数据结构的清晰文档
3. AI 代理知道要生成的确切格式

步骤 2:添加到仪表板

POST /api/widgets/instances
Content-Type: application/json

{
  "type": "custom",
  "title": "GitHub PRs",
  "custom_widget_id": "cw_abc123",
  "config": { "owner": "acfranzen", "repo": "libra" }
}

步骤 3:填充缓存(针对 agent_refresh)

POST /api/widgets/github-prs/cache
Content-Type: application/json

{
  "data": {
    "prs": [...],
    "fetchedAt": "2026-02-03T14:00:00Z"
  }
}

⚠️ 如果小组件有 dataSchema,缓存端点会根据它验证你的数据。 错误数据返回 400 并附带详细信息。POST 前始终检查小组件的模式:

GET /api/widgets/github-prs
# 响应包含显示必需字段和类型的 dataSchema

步骤 4:浏览器验证(必需)

⚠️ 强制:每次小组件创建和刷新必须以浏览器验证结束。

在视觉上确认小组件在仪表板上正确渲染之前,永远不要认为小组件“已完成”。

```javascript
// 必需:打开仪表板并验证小组件渲染
browser({
action: 'open',
targetUrl: 'http://localhost:3333',
profile: 'openclaw'
});

// 截图并检查小组件
browser({ action: 'snapshot' });

// 检查:
// 1. 小组件

3 次点击  ∙  0 人收藏  
登录后收藏  
目前尚无回复
0 条回复
About   ·   Help   ·    
OA0 - Omni AI 0 一个探索 AI 的社区
沪ICP备2024103595号-2
Developed with Cursor