SuperAPI AI Directory

qiaomu-opencli-oneshot

Coding & development

View repository

Updated 10-15 23:33

About this skill

CLI-ONESHOT — Single-point Quick CLI Generation

Given a URL + a one-sentence description, generate a CLI command in 4 steps. For full exploratory development, see opencli-explorer skill。


Input

Project Example
URL https://x.com/jakevin7/lists
Goal Get my Twitter Lists

Workflow

Step 1: Open the page + capture network traffic

1. browser_navigate → 打开目标 URL
2. 等待 3-5 秒(让页面加载完、API 请求触发)
3. browser_network_requests → 筛选 JSON API

Key: only pay attention to requests that return application/json , ignore static resources. If the API isn't triggered automatically, manually click the target button/tab and capture again.

Step 2: Lock onto a single endpoint

From the captured traffic, findthattarget API. Look at these fields:

Field What to look for
URL API path pattern (e.g. /i/api/graphql/xxx/ListsManagePinTimeline)
Method GET / POST
Headers Has Cookie? Bearer? CSRF? Custom signature?
Response Which path the data is in (e.g. data.list.lists)

Step 3: Verify the endpoint can be reproduced

In browser_evaluate , use fetch to reproduce the request:

// Tier 2 (Cookie): 大多数情况
fetch('/api/endpoint', { credentials: 'include' }).then(r => r.json())

// Tier 3 (Header): 如 Twitter 需要额外 header
const ct0 = document.cookie.match(/ct0=([^;]+)/)?.[1];
fetch('/api/endpoint', {
  headers: { 'Authorization': 'Bearer ...', 'X-Csrf-Token': ct0 },
  credentials: 'include'
}).then(r => r.json())

If fetch can get the data → use a TS adapter (cli() pipeline or func()). If fetch can't get it (signature/risk control) → use the intercept strategy (TS func() + installInterceptor)。

Step 4: Apply a template, generate the adapter

Based on the strategy determined in Step 3, pick a template to generate the file.


Auth quick reference

fetch(url) 直接能拿到?              → Tier 1: public   (TS pipeline, browser: false)
fetch(url, {credentials:'include'})? → Tier 2: cookie   (TS pipeline 或 func())
加 Bearer/CSRF header 后拿到?        → Tier 3: header   (TS func())
都不行,但页面自己能请求成功?          → Tier 4: intercept (TS func(), installInterceptor)

Templates

TS — Cookie/Public (simplest,func() mode)

// clis/<site>/<name>.ts
import { cli, Strategy } from '@jackwener/opencli/registry';

cli({
  site: 'mysite',
  name: 'mycommand',
  description: '一句话描述',
  domain: 'www.example.com',
  strategy: Strategy.COOKIE,   // 或 Strategy.PUBLIC (加 browser: false)
  browser: true,
  args: [
    { name: 'limit', type: 'int', default: 20 },
  ],
  columns: ['rank', 'title', 'value'],
  func: async (page, kwargs) => {
    await page.goto('https://www.example.com/target-page');
    const data = await page.evaluate(`(async () => {
      const res = await fetch('/api/target', { credentials: 'include' });
      const d = await res.json();
      return (d.data?.items || []).map(item => ({
        title: item.title,
        value: item.value,
      }));
    })()`);
    return (data as any[]).slice(0, kwargs.limit).map((item, i) => ({
      rank: i + 1,
      title: item.title || '',
      value: item.value || '',
    }));
  },
});

TS — Intercept (traffic capture mode)

// clis/<site>/<name>.ts
import { cli, Strategy } from '@jackwener/opencli/registry';

cli({
  site: 'mysite',
  name: 'mycommand',
  description: '一句话描述',
  domain: 'www.example.com',
  strategy: Strategy.INTERCEPT,
  browser: true,
  args: [
    { name: 'limit', type: 'int', default: 20 },
  ],
  columns: ['rank', 'title', 'value'],
  func: async (page, kwargs) => {
    // 1. 导航
    await page.goto('https://www.example.com/target-page');
    await page.wait(3);

    // 2. 注入拦截器(URL 子串匹配)
    await page.installInterceptor('target-api-keyword');

    // 3. 触发 API(滚动/点击)
    await page.autoScroll({ times: 2, delayMs: 2000 });

    // 4. 读取拦截的响应
    const requests = await page.getInterceptedRequests();
    if (!requests?.length) return [];

    let results: any[] = [];
    for (const req of requests) {
      const items = req.data?.data?.items || [];
      results.push(...items);
    }

    return results.slice(0, kwargs.limit).map((item, i) => ({
      rank: i + 1,
      title: item.title || '',
      value: item.value || '',
    }));
  },
});

TS — Header (e.g. Twitter GraphQL)

import { cli, Strategy } from '@jackwener/opencli/registry';

cli({
  site: 'twitter',
  name: 'mycommand',
  description: '一句话描述',
  domain: 'x.com',
  strategy: Strategy.HEADER,
  browser: true,
  args: [
    { name: 'limit', type: 'int', default: 20 },
  ],
  columns: ['rank', 'name', 'value'],
  func: async (page, kwargs) => {
    await page.goto('https://x.com');
    const data = await page.evaluate(`(async () => {
      const ct0 = document.cookie.match(/ct0=([^;]+)/)?.[1];
      if (!ct0) return { error: 'Not logged in' };
      const bearer = 'AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D...';
      const res = await fetch('/i/api/graphql/QUERY_ID/Endpoint', {
        headers: {
          'Authorization': 'Bearer ' + decodeURIComponent(bearer),
          'X-Csrf-Token': ct0,
          'X-Twitter-Auth-Type': 'OAuth2Session',
        },
        credentials: 'include',
      });
      return res.json();
    })()`);
    // 解析 data...
    return [];
  },
});

Testing (mandatory)

npm run build                              # 语法检查
opencli list | grep mysite                 # 确认注册
opencli mysite mycommand --limit 3 -v      # 实际运行

That's it, done

Write the file → build → run → submit. If there are issues, check opencli-explorer skill。