← 返回 Skills 市场
gangtao

Pulsebot App Builder

作者 Gang Tao · GitHub ↗ · v1.0.0 · MIT-0
cross-platform ✓ 安全检测通过
41
总下载
0
收藏
0
当前安装
1
版本数
在 OpenClaw 中安装
/install pulsebot-app-builder
功能描述
Build real-time Timeplus data processing and analysis applications in Pulsebot. Creates pure frontend HTML/JavaScript apps that connect directly to Timeplus...
使用说明 (SKILL.md)

Pulsebot App Builder

Use this skill whenever the user asks to build a data processing application, pipeline visualizer, real-time dashboard, streaming analytics app, or any frontend tool that queries or visualizes data from Timeplus Proton.

Overview

You will produce a single self-contained HTML file that:

  1. Queries Timeplus Proton directly via @timeplus/proton-javascript-driver loaded from unpkg CDN
  2. Visualizes streaming data using @timeplus/vistral loaded from unpkg CDN
  3. Follows the Timeplus App Style Guide (dark theme, brand colors, clean layout)
  4. Requires no npm install, no build step — open the HTML file directly in a browser

Key architecture: Both @timeplus/proton-javascript-driver and @timeplus/vistral ship UMD builds. Import them via \x3Cscript src="https://unpkg.com/..."> tags. The Proton driver connects directly to the agent proxy running at localhost:8001.


Step-by-Step Workflow

Step 1 — Clarify Requirements

Before writing any code, confirm:

  • What stream(s) or table(s) to query (name, schema if known)
  • What kind of visualization: time series, bar/column, table, single value, or multi-panel
  • Whether the query is streaming (SELECT ... FROM stream_name) or historical (SELECT ... FROM table(stream_name))
  • Any filters, aggregations, or window functions needed

If the user doesn't know the schema, suggest running DESCRIBE stream_name or SHOW STREAMS first.


Step 2 — Use the HTML Template

All Timeplus apps follow this single-file HTML template. Read references/STYLE_GUIDE.md for style rules and references/VISTRAL_API.md for chart configuration options.

\x3C!DOCTYPE html>
\x3Chtml lang="en">
\x3Chead>
  \x3Cmeta charset="UTF-8" />
  \x3Cmeta name="viewport" content="width=device-width, initial-scale=1.0" />
  \x3Ctitle>My Timeplus App\x3C/title>

  \x3C!-- 1. React (required by Vistral) -->
  \x3Cscript src="https://unpkg.com/react@18/umd/react.production.min.js">\x3C/script>
  \x3Cscript src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js">\x3C/script>

  \x3C!-- 2. Vistral peer dependencies — load BEFORE vistral -->
  \x3Cscript src="https://unpkg.com/lodash@4/lodash.min.js">\x3C/script>
  \x3Cscript src="https://unpkg.com/[email protected]/dist/ramda.min.js">\x3C/script>
  \x3Cscript src="https://unpkg.com/@antv/g2@5/dist/g2.min.js">\x3C/script>
  \x3Cscript src="https://unpkg.com/@antv/s2@2/dist/s2.min.js">\x3C/script>

  \x3Cscript>
    // Prevent jsx-runtime from crashing on process.env access
    window.process = window.process || {
      env: { NODE_ENV: "production" }
    };

    // Some builds also expect global
    window.global = window.global || window;
  \x3C/script>

  \x3C!-- 3. Vistral UMD — exposes window.Vistral -->
  \x3Cscript src="https://unpkg.com/@timeplus/vistral/dist/index.umd.min.js">\x3C/script>

  \x3C!-- 4. Proton JavaScript Driver UMD — exposes window.ProtonDriver -->
  \x3Cscript src="https://unpkg.com/@timeplus/proton-javascript-driver/dist/index.umd.js">\x3C/script>

  \x3Cstyle>
    /* Timeplus design tokens */
    :root {
      --tp-bg-primary: #0f1117;
      --tp-bg-secondary: #1a1d27;
      --tp-bg-card: #1e2235;
      --tp-bg-hover: #252a3a;
      --tp-accent-primary: #7c6af7;
      --tp-accent-secondary: #4fc3f7;
      --tp-accent-success: #4caf82;
      --tp-accent-warning: #f7a84f;
      --tp-accent-danger: #f76f6f;
      --tp-text-primary: #e8eaf6;
      --tp-text-secondary: #9ea3b8;
      --tp-text-muted: #5c6380;
      --tp-border: #2e3450;
      --tp-font-mono: 'JetBrains Mono', 'Fira Code', monospace;
      --tp-font-sans: 'Inter', system-ui, sans-serif;
      --tp-radius-lg: 12px;
      --tp-shadow: 0 2px 12px rgba(0,0,0,0.4);
    }
    * { box-sizing: border-box; margin: 0; padding: 0; }
    body { background: var(--tp-bg-primary); color: var(--tp-text-primary); font-family: var(--tp-font-sans); font-size: 14px; line-height: 1.5; }
    .tp-app { display: flex; flex-direction: column; height: 100vh; overflow: hidden; }
    .tp-header { display: flex; align-items: center; gap: 12px; padding: 0 24px; height: 56px; background: var(--tp-bg-secondary); border-bottom: 1px solid var(--tp-border); flex-shrink: 0; }
    .tp-header-title { font-size: 16px; font-weight: 600; }
    .tp-header-badge { font-size: 11px; padding: 2px 8px; background: var(--tp-accent-primary); color: white; border-radius: 99px; font-weight: 500; }
    .tp-status { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--tp-text-muted); margin-left: auto; }
    .tp-status-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--tp-text-muted); }
    .tp-status-dot.connected { background: var(--tp-accent-success); }
    .tp-status-dot.error { background: var(--tp-accent-danger); }
    .tp-main { flex: 1; overflow: auto; padding: 20px 24px; display: grid; gap: 16px; }
    .tp-card { background: var(--tp-bg-card); border: 1px solid var(--tp-border); border-radius: var(--tp-radius-lg); padding: 16px; box-shadow: var(--tp-shadow); }
    .tp-card-title { font-size: 13px; font-weight: 600; color: var(--tp-text-secondary); text-transform: uppercase; letter-spacing: 0.04em; margin-bottom: 12px; }
    .tp-error { background: rgba(247,111,111,0.1); border: 1px solid var(--tp-accent-danger); border-radius: 8px; padding: 12px 16px; color: var(--tp-accent-danger); font-size: 13px; display: none; }
    .chart-container { min-height: 300px; }
  \x3C/style>
\x3C/head>
\x3Cbody>
  \x3Cdiv class="tp-app">
    \x3Cheader class="tp-header">
      \x3Cspan class="tp-header-title">My Stream App\x3C/span>
      \x3Cspan class="tp-header-badge">LIVE\x3C/span>
      \x3Cspan class="tp-status">
        \x3Cspan class="tp-status-dot" id="status-dot">\x3C/span>
        \x3Cspan id="status-text">Connecting…\x3C/span>
      \x3C/span>
    \x3C/header>
    \x3Cmain class="tp-main">
      \x3Cdiv class="tp-error" id="error-panel">\x3C/div>
      \x3Cdiv class="tp-card">
        \x3Cdiv class="tp-card-title">Live Stream\x3C/div>
        \x3Cdiv class="chart-container" id="chart">\x3C/div>
      \x3C/div>
    \x3C/main>
  \x3C/div>

  \x3Cscript>
    // ---- Library globals ----
    // proton-javascript-driver UMD exposes window.ProtonDriver
    const { ProtonClient } = window.ProtonDriver;
    // vistral UMD exposes window.Vistral; React/ReactDOM are also on window
    const { Vistral, React, ReactDOM } = window;
    const { StreamChart } = Vistral;

    // ---- Configuration ----
    const SQL = 'SELECT * FROM my_stream';  // TODO: replace with your SQL

    // Connect to the Proton proxy running on the agent at localhost:8001
    const client = new ProtonClient({ host: 'localhost', port: 8001 });

    // ---- State ----
    let columns = [];
    let rows = [];
    let chartRoot = null;

    // ---- Helpers ----
    function setStatus(state, message) {
      document.getElementById('status-dot').className = 'tp-status-dot ' + (state || '');
      document.getElementById('status-text').textContent = message;
    }

    function showError(msg) {
      const panel = document.getElementById('error-panel');
      panel.style.display = msg ? 'block' : 'none';
      panel.textContent = msg || '';
      if (msg) setStatus('error', 'Error');
    }

    function inferColumns(row) {
      return Object.entries(row).map(([name, value]) => ({
        name,
        type: typeof value === 'number' ? 'float64'
            : String(value).match(/^\d{4}-\d{2}-\d{2}/) ? 'datetime64'
            : 'string',
      }));
    }

    // ---- Render chart ----
    function renderChart() {
      if (columns.length === 0) return;
      if (!chartRoot) chartRoot = ReactDOM.createRoot(document.getElementById('chart'));

      // TODO: adjust config for your data — see references/VISTRAL_API.md
      const config = {
        chartType: 'line',
        xAxis: columns[0].name,
        yAxis: columns[1]?.name ?? columns[0].name,
        temporal: { mode: 'axis', field: columns[0].name, range: 60 },
      };

      chartRoot.render(
        React.createElement(StreamChart, {
          config,
          data: { columns, data: rows, isStreaming: true },
          theme: 'dark',
        })
      );
    }

    // ---- Main query loop ----
    async function runQuery() {
      try {
        setStatus('', 'Connecting…');
        const { rows: stream, abort } = await client.query(SQL);
        setStatus('connected', 'Connected');

        // Expose abort so it can be called externally if needed
        window.stopQuery = abort;

        for await (const row of stream) {
          if (columns.length === 0) columns = inferColumns(row);
          rows = [...rows.slice(-999), row];  // keep last 1000 rows
          renderChart();
        }

        setStatus('', 'Stream ended');
      } catch (err) {
        showError(err.message);
      }
    }

    runQuery();
  \x3C/script>
\x3C/body>
\x3C/html>

Step 3 — Proton Connection

Read references/PROTON_DRIVER.md for the full driver API.

The driver connects directly to the Proton proxy at localhost:8001. UMD global: window.ProtonDriver.

const { ProtonClient } = window.ProtonDriver;

const client = new ProtonClient({ host: 'localhost', port: 8001 });

const { rows, abort } = await client.query('SELECT * FROM my_stream');

for await (const row of rows) {
  // row is a plain JavaScript object: { col1: val1, col2: val2, ... }
  console.log(row);
}

// To cancel a running streaming query:
abort();

Step 4 — Visualization with Vistral

Read references/VISTRAL_API.md for the complete component reference.

Vistral UMD global: window.Vistral. Key components: StreamChart, SingleValueChart, DataTable.

All charts are rendered via React (React.createElement). Always pass theme="dark".

Quick chart config reference:

Chart type chartType Best for temporal mode
Time series 'line' or 'area' Scrolling metrics over time 'axis'
Horizontal bars 'bar' Ranked categories, latest snapshot 'frame'
Vertical bars 'column' Categorical comparison 'frame'
KPI tile 'singleValue' One big number 'frame'
Live table 'table' Raw rows / mutable state 'key'
Geo points 'geo' Location data 'key'

Step 5 — Apply Timeplus Style Guide

Read references/STYLE_GUIDE.md for full rules. Core rules always applied:

  • Dark background #0f1117 for page, #1e2235 for cards
  • Purple #7c6af7 for primary accents
  • Inter font for UI, monospace for data values
  • Cards with border-radius: 12px and border #2e3450
  • Header 56px with LIVE badge and connection status indicator

Step 6 — Deliver the App

  1. Write the complete single-file HTML, filling in the correct SQL and chart config
  2. use workspace_create_app to create the app
  3. Present the file — it opens directly in a browser with no server or build step needed

For PulseBot deployment:

workspace_create_app(
  session_id=session_id,
  task_name="My Stream App",
  html=open("my-app.html").read()
)

SQL Patterns

Load the timeplus-sql-guide skill for all SQL questions:

  • Streaming vs historical queries
  • Window functions (tumble, hop, session)
  • Aggregations, joins, filters
  • Schema introspection (DESCRIBE, SHOW STREAMS)

Checklist Before Delivering

  • Single HTML file — no separate JS/CSS files, no package.json, no build step
  • Script load order: React → ReactDOM → lodash → ramda → @antv/g2 → @antv/s2 → vistral → proton-javascript-driver
  • window.ProtonDriver destructured for ProtonClient
  • window.Vistral destructured for StreamChart (and other components as needed)
  • ProtonClient configured with { host: 'localhost', port: 8001 }
  • SQL uses correct Proton streaming syntax
  • columns inferred from first received row using inferColumns()
  • Chart config.temporal uses correct mode for the query type
  • Status indicator updates on connect, stream end, and error
  • abort() stored on window.stopQuery or similar
  • CSS uses Timeplus design tokens (CSS variables) from the style template
安全使用建议
Install only if you intend to build Timeplus Proton/Pulsebot browser apps. Review generated HTML before opening it, especially the SQL query, localhost:8001 access, and third-party unpkg script tags; use trusted or pinned/local dependencies if your Proton data is sensitive.
能力评估
Purpose & Capability
The skill consistently describes creating single-file HTML/JavaScript Timeplus Proton dashboards and visualizations using Vistral and the Proton JavaScript driver.
Instruction Scope
The activation wording includes broad dashboard and data-processing phrases, but the artifacts repeatedly anchor the workflow to Timeplus Proton/Pulsebot and require clarifying streams, SQL, and chart needs before coding.
Install Mechanism
The package contains markdown instructions and references only; no executable installer, background worker, package script, or automatic local mutation was found.
Credentials
Generated apps are expected to load JavaScript from unpkg and connect to localhost:8001, which is proportionate to the single-file Timeplus app purpose but should be understood by users.
Persistence & Privilege
No persistence, privilege escalation, credential harvesting, deletion, or background execution is instructed; the generated app exposes an abort handle for stopping a stream.
如何使用
  1. 确保已安装 OpenClaw(本地或 Docker 部署)
  2. 在对话框中输入安装命令:/install pulsebot-app-builder
  3. 安装完成后,直接呼叫该 Skill 的名称或使用 /pulsebot-app-builder 触发
  4. 根据 Skill 的参数说明提供必要输入,即可获得结构化输出
版本历史
v1.0.0
pulsebot-app-builder 1.0.0 — initial release - Build Timeplus data processing apps via Pulsebot, outputting a single self-contained HTML/JavaScript file. - No npm install or bundler needed; all dependencies loaded as UMD modules via CDN. - Connects directly to Timeplus Proton using @timeplus/proton-javascript-driver. - Visualizes live and historical streaming data with @timeplus/vistral, following the official Timeplus UI style guide. - Designed for flexible frontend app creation: dashboards, visualizers, and streaming analytics.
元数据
Slug pulsebot-app-builder
版本 1.0.0
许可证 MIT-0
累计安装 0
当前安装数 0
历史版本数 1
常见问题

Pulsebot App Builder 是什么?

Build real-time Timeplus data processing and analysis applications in Pulsebot. Creates pure frontend HTML/JavaScript apps that connect directly to Timeplus... 它是一个面向 Claude Code / OpenClaw 的 AI Agent Skill 插件,目前累计下载 41 次。

如何安装 Pulsebot App Builder?

在 OpenClaw 或 Claude Code 对话框中运行命令「/install pulsebot-app-builder」即可一键安装,无需额外配置。

Pulsebot App Builder 是免费的吗?

是的,Pulsebot App Builder 完全免费,采用 MIT-0 许可证,可自由下载、安装和使用。

Pulsebot App Builder 支持哪些平台?

Pulsebot App Builder 跨平台运行,可在任意部署了 OpenClaw / Claude Code 的环境中使用(cross-platform)。

谁开发了 Pulsebot App Builder?

由 Gang Tao(@gangtao)开发并维护,当前版本 v1.0.0。

💬 留言讨论