Skip to content

Repository files navigation

cd extension pnpm --filter openapi-qoder-webview build # 先确保 webview 产物在(漏了面板会空白) npx vsce package --no-dependencies

openapi-qoder

从 Torna(toena)接口文档生成高质量 TypeScript 类型 + 请求函数的工具。

两段式流水线:Stage-1 确定性代码生成Stage-2 AI 润色(Qoder Agent SDK), AI 的命名决策落盘到命名账本,保证二次运行可复现、增量、不漂移。

产物对标 battery-asset-management-web,但解决其两大痛点:类型冗余、分页类型不可复用。


环境要求

  • Node.js ≥ 18(本仓库用 24 测试)
  • 依赖已随仓库声明,安装即可:
npm install

鉴权

用途 变量 说明
拉取 Torna 文档 TORNA_TOKEN Torna 请求头里的 token 值(见 接口/*.ts
Torna 地址(可选) TORNA_BASE_URL 默认 https://doc-dev.qijiswap.com
Stage-2 AI 润色 QODER_PERSONAL_ACCESS_TOKEN 未设置时回退到本地 qodercli login 登录态
export TORNA_TOKEN="xxx:eyJhbGci..."
# 可选:export QODER_PERSONAL_ACCESS_TOKEN="qoder_..."

快速开始

# 1) 列出所有空间 / 项目,拿到 projectId
npx tsx src/cli.ts list

# 2) 生成某个项目(Stage-1 确定性 + 复用已有账本 Stage-1.5)
npx tsx src/cli.ts gen <projectId>

# 3) AI 润色(Stage-2:语义命名 + 标量数组元素推断 + tsc 校验闭环)
npx tsx src/polish-run.ts <projectId>

# 4) 把本次 AI 决策记入账本,并纳入 git(下次可复用)
npx tsx src/cli.ts harvest <projectId>
git add .openapi-qoder/naming.lock.json && git commit -m "chore: update naming ledger"

或交互式选择空间 → 项目 → 直接生成:

npx tsx src/cli.ts pick

产物在 generated/<projectId>/(Stage-1)与 generated/<projectId>-polished/(最终)。 generated/ 已被 gitignore;需要提交的只有账本 .openapi-qoder/naming.lock.json


CLI 命令

命令 作用
list 列出空间 / 项目
pick 交互式:空间 → 项目 → 生成
gen <projectId> 拉取接口 + Stage-1 生成 + 复用账本(Stage-1.5,无 AI)
harvest <projectId> 把 Stage-2 结果反推为决策写入账本
status <projectId> 查看:已入账本 / 结构变更需重润色 / 未解析 unknown[]

Stage-2 润色单独运行:

npx tsx src/polish-run.ts <projectId>
# 可调参数:
POLISH_BATCH=4 POLISH_MAX_TURNS=60 npx tsx src/polish-run.ts <projectId>

npm scripts 快捷方式:npm run qgen -- <命令>npm run polish -- <projectId>


产物长什么样

每个接口一个文件,自包含类型 + 请求函数:

// AUTO-GENERATED by openapi-qoder (Stage-1 codegen + Stage-2 AI polish).
// Names are pinned in .openapi-qoder/naming.lock.json — edit there, not here.
import request from '@/utils/request';
import type { PageResult } from './common.js';

export interface HostingVehicleQueryParam { /* ... */ }
export interface HostingVehicleVO { /* ... */ }
export type HostingVehiclePageData = PageResult<HostingVehicleVO>;

/** 托管运营车辆分页列表 */
export const getHostingVehiclePage = (data: HostingVehicleQueryParam) =>
  request.post<HostingVehiclePageData, HostingVehicleQueryParam>('/v1.0/hostingVehicle/page', data);

枚举会被提炼为常量 + 联合类型(common.ts 提供公共 PageResult<T>):

export const USER_TYPE = {
  /** 个人 */ PERSONAL: 'CUSTOMER_TYPE_C',
  /** 公司 */ COMPANY: 'CUSTOMER_TYPE_B',
} as const;
export type UserType = typeof USER_TYPE[keyof typeof USER_TYPE];

要点:

  • 响应壳(code/msg/traceId/...)被剥离,只保留 data
  • 分页结构自动识别为公共 PageResult<T>
  • 请求 URL 去掉网关前缀 /2m /2b /2c(代理会自动补)。
  • @/utils/request 为默认请求模块,可在生成选项中替换。

命名账本(可重入的关键)

.openapi-qoder/naming.lock.json 以 Torna docId 为稳定 key,记录 AI/人工的命名决策:

{
  "version": 1,
  "apis": {
    "nzDyBg12": {
      "shape": "ebd35438c83b",              // 结构指纹
      "fn": "getHostingVehiclePage", "locked": true,
      "types": { "HostingVehiclePageItem": "HostingVehicleVO" },
      "fieldTypes": { "HostingVehiclePageParam.operatorNames": "string[]" },
      "source": "ai"                          // "manual" = 人工命名,AI 永不覆盖
    }
  }
}

再次运行 gen 时:

  • shape 未变 → 纯代码复用旧命名,完全跳过 AI(零成本、零漂移)。
  • 文档更新导致 shape 变化 → 仅新增/变化部分交给 Stage-2 润色。
  • locked: true 的函数名冻结;source: "manual" 的条目 harvest 不覆盖。

典型工作流:

gen → polish-run → harvest → 提交 naming.lock.json
# 文档更新后再次 gen:多数接口直接复用账本,只剩少量需要 polish

校验

npm run check:src        # 工具源码类型检查
npm run check:out        # 校验 generated/ 产物可编译
npm run check:polished   # 校验 Stage-2 润色结果可编译

Stage-2 内置 tsc 校验门:某文件润色后编译不过,会回滚该文件到 Stage-1 版本, 保证产物「永不比确定性生成更差」。


基于 mock 离线跑

无需 Torna 网络,用仓库内 mock/*.json 生成到 generated/

npm run gen              # = tsx src/generate.ts

更详细的设计说明见 ARCHITECTURE.md

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages