wkgeo-cli 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +129 -12
- package/SKILL.md +131 -4
- package/lib/args.mjs +5 -0
- package/lib/cli.mjs +5 -0
- package/lib/cms.mjs +317 -0
- package/lib/commands/auth.mjs +42 -11
- package/lib/commands/billing.mjs +641 -421
- package/lib/commands/cms.mjs +1265 -0
- package/lib/commands/import.mjs +164 -0
- package/lib/commands/index.mjs +83 -4
- package/lib/config.mjs +82 -22
- package/lib/device.mjs +22 -5
- package/lib/index.mjs +5 -0
- package/lib/local-import.mjs +185 -0
- package/lib/login.mjs +42 -22
- package/lib/oauth-urls.mjs +163 -0
- package/lib/runtime.mjs +81 -0
- package/lib/site-state.mjs +137 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -197,15 +197,20 @@ wkgeo login --device-continue # 用上次保存的设备码换票(配合 -
|
|
|
197
197
|
```
|
|
198
198
|
请在浏览器中完成授权(设备码模式,不需要任何回调地址):
|
|
199
199
|
|
|
200
|
-
1) 打开:https://
|
|
200
|
+
1) 打开:https://wkgeo.com/oauth/device/?user_code=ABCD-1234
|
|
201
201
|
2) 如果页面没有自动填好短码,请输入:ABCD-1234
|
|
202
202
|
|
|
203
|
-
📋 可以直接复制这段发给 AI 端或转给用户:请打开 https://
|
|
203
|
+
📋 可以直接复制这段发给 AI 端或转给用户:请打开 https://wkgeo.com/oauth/device/?user_code=ABCD-1234 并完成「同意授权」(短码:ABCD-1234)。
|
|
204
204
|
```
|
|
205
205
|
|
|
206
|
+
> ★ **2026-10-18 域名统一到路径**:授权站 canonical 从 `https://oauth.wkgeo.com/` 改成
|
|
207
|
+
> **`https://wkgeo.com/oauth/`**(老地址继续可用)。CLI 以 `WKONGAI_OAUTH_WEB_BASE` 为 canonical,
|
|
208
|
+
> 服务端 metadata 给的授权地址只当"路径来源"用(详见 `lib/oauth-urls.mjs`);
|
|
209
|
+
> 回滚只要一条环境变量:`WKONGAI_OAUTH_WEB_BASE=https://oauth.wkgeo.com`。
|
|
210
|
+
|
|
206
211
|
> ✅ 线上**已支持**这条路径(2026-10-02 实测:`metadata` 声明了 `device_authorization_endpoint`,
|
|
207
212
|
> `grant_types_supported` 含 device_code,确认页 `/admin/oauth/device/` 也在)。
|
|
208
|
-
> 端到端真跑记录见云函数测试目录的 `
|
|
213
|
+
> 端到端真跑记录见云函数测试目录的 `tencent/functions/_tests/oauth-device-live-e2e.js`(默认只读,`OAUTH_DEVICE_E2E_LIVE=1` 才实跑)。
|
|
209
214
|
|
|
210
215
|
#### `--no-wait` + `--device-continue`:给 **AI 端(Agent)** 用的"先给码、后领票"
|
|
211
216
|
|
|
@@ -216,7 +221,7 @@ AI 端是**一轮一轮**工作的:一次工具调用里挂着等 10 分钟会
|
|
|
216
221
|
# ① Agent 调用(立刻返回,进程随即退出)
|
|
217
222
|
wkgeo login --device --no-wait --json
|
|
218
223
|
# → {"ok":true,"command":"login","stage":"awaiting_user","user_code":"ABCD-1234",
|
|
219
|
-
# "verification_uri":"https://
|
|
224
|
+
# "verification_uri":"https://wkgeo.com/oauth/device/",
|
|
220
225
|
# "verification_uri_complete":"…/?user_code=ABCD-1234","paste_text":"…","expires_in":600,
|
|
221
226
|
# "interval":5,"resume_command":"wkgeo login --device-continue","pending_file":"…","next_step":"…",
|
|
222
227
|
# "user_action_required":"请让用户访问 … 并输入短码 ABCD-1234","no_wait":true}
|
|
@@ -255,7 +260,7 @@ wkgeo login --device-continue --json
|
|
|
255
260
|
// 本地回调模式:第一行就给出网址,AI 可以立刻转述给用户
|
|
256
261
|
// (注意 `authorize/` 的**尾斜杠**:托管侧对不带尾斜杠的目录路径会 302 且丢掉 query)
|
|
257
262
|
{"ok":true,"command":"login","mode":"callback","stage":"awaiting_callback",
|
|
258
|
-
"authorization_url":"https://
|
|
263
|
+
"authorization_url":"https://wkgeo.com/oauth/authorize/?client_id=…",
|
|
259
264
|
"redirect_uri":"http://127.0.0.1:53682/callback",
|
|
260
265
|
"user_action_required":"请让用户在浏览器中打开上面的 authorization_url,登录并点「同意」"}
|
|
261
266
|
// 结束(成功)
|
|
@@ -366,6 +371,25 @@ wkgeo login --device-continue --json
|
|
|
366
371
|
| `sites list` | 我的站点 | `--limit`、`--offset` |
|
|
367
372
|
| `sites create` | 建站(**建在令牌所属用户名下**) | `--name`(必填)、`--customer`、`--template`、`--domain` |
|
|
368
373
|
| `sites delete` | 删站(服务端是**软删除**,进回收站) | `<站点ID>` |
|
|
374
|
+
| `site use` | **选中要操作的站点**(本地记住,之后的 CMS 命令都带它;不给参数 = 看当前是哪个) | `<站点ID或域名>`、`--clear` |
|
|
375
|
+
| `categories list` | 栏目列表(树序) | — |
|
|
376
|
+
| `categories get` | 单个栏目详情(含栏目正文、父栏目字段) | `<栏目ID\|slug\|path\|栏目名>` |
|
|
377
|
+
| `categories create` | 新建栏目 | `--name`(必填)、`--parent`、`--kind channel\|list\|page`、`--slug`、`--status`、`--sort`、`--icon`、`--link-url`、`--seo-description`、`--seo-keywords`、`--sub-title`、`--no-in-menu`、`--body`/`--body-file` |
|
|
378
|
+
| `categories update` | 改栏目(只改给了的字段) | `<栏目>` + 上面任意字段 |
|
|
379
|
+
| `categories delete` | 删栏目(系统栏目/有子栏目或内容时被拒) | `<栏目>` |
|
|
380
|
+
| `categories bind-template` | 给栏目绑定模板 html(`--clear` = 解绑) | `<栏目>` `<模板文件>`、`--clear` |
|
|
381
|
+
| `contents list` | 内容列表(不含正文) | `--category`、`--status`、`--keyword`、`--page`、`--page-size`、`--sort views_desc`、`--include-children`、`--owner-page` |
|
|
382
|
+
| `contents get` | 单条内容详情(正文/附件/SEO/自定义字段) | `<内容ID>` |
|
|
383
|
+
| `contents create` | 新建内容(默认草稿) | `--title`(必填)、`--category`(必填)、`--status`、`--body`/`--body-file`、`--description`、`--keywords`、`--sub-title`、`--cover`、`--video`、`--usage`、`--attachments`、`--ext`、`--pinned`、`--sort` |
|
|
384
|
+
| `contents update` | 改内容(只改给了的字段) | `<内容ID>` + 上面任意字段(`--title` 也可) |
|
|
385
|
+
| `contents delete` | 删内容(「单页」那一页删不掉) | `<内容ID>` |
|
|
386
|
+
| `assets list` | 素材列表(默认只列图片;可看回收站) | `--kind`、`--keyword`、`--status normal\|deleted`、`--sort`、`--page`、`--page-size` |
|
|
387
|
+
| `assets upload` | 上传素材(**签名 → 直传 OSS → 登记**,CLI 不碰 AK) | `<本地文件>`、`--name` |
|
|
388
|
+
| `templates list` | 模板清单(默认模板 + 每个 html 的字符数) | — |
|
|
389
|
+
| `templates get` | 看模板源码(不给文件名 = 列清单;给了就直出源码) | `[模板文件名]` |
|
|
390
|
+
| `templates save` | 新建/覆盖模板 html(≤40 万字符) | `<文件名.html>` + `--file <本地文件>` 或 `--content <源码>` |
|
|
391
|
+
| `publish` | **看发布状态**(前台按需渲染:`published` 即上线,没有额外发布步骤) | — |
|
|
392
|
+
| `import` | 老站导入(**默认 dry-run**;走本机运维脚本,需运维权限) | `--url`(必填)、`--apply`、`--site`、`--status`、`--out`、`--max-pages`、`--delay`、`--include`、`--exclude`、`--overwrite`、`--no-probe` |
|
|
369
393
|
| `wallet` | 余额 + 最近流水 | `--limit`、`--entitlements` |
|
|
370
394
|
| `wallet txns` | 钱包流水(普通用户自己的那份) | `--limit` |
|
|
371
395
|
| `wallet recharge` | **充值下单**:返 `code_url` + **`pay_url`(自家收银台页面,带订单支付令牌 `token`;★ 默认会自动尝试用系统浏览器打开,`--no-browser` 可关;**支付成功后页面会自己关掉**)**(**不会自动扣款**) | `--amount-cents`(必填,单位分)、`--no-browser`、`--open-browser`、`--dry-run` |
|
|
@@ -379,6 +403,67 @@ wkgeo login --device-continue --json
|
|
|
379
403
|
| `apps revoke` | 一键吊销某应用的授权(**令牌立即失效**) | `<client_id>` |
|
|
380
404
|
| `skill` | **打印给 AI 端的操作手册**(`SKILL.md` 原文,随包分发) | `--json`(默认**纯文本原文**,不受"非终端自动 JSON"影响) |
|
|
381
405
|
|
|
406
|
+
### CMS 命令(栏目 / 内容 / 素材 / 模板)怎么用
|
|
407
|
+
|
|
408
|
+
**三步就够**(AI 端也是这三步):
|
|
409
|
+
|
|
410
|
+
```bash
|
|
411
|
+
wkgeo site use www.example.com # ① 选站(本地记住;也可每条命令加 --site <站点ID>)
|
|
412
|
+
wkgeo categories list # ② 看结构
|
|
413
|
+
wkgeo contents create --category 新闻 --title "标题" --status published --body "<p>正文</p>"
|
|
414
|
+
wkgeo assets upload ./banner.jpg # 传图 → 拿素材 ID → 再 --cover 挂到内容上
|
|
415
|
+
wkgeo templates list / get / save # 改版式(后端动作已就绪)
|
|
416
|
+
wkgeo publish # ③ 看状态(见下)
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
> 只属于**一个**站点的账号可以跳过 ①:不带 `x-cms-site` 时服务端会用那唯一一个成员站;
|
|
420
|
+
> 有多个成员站又不指定 → 报 `cms_site_required` 并教你选(不替你猜,免得改了 A 站以为改的是 B 站)。
|
|
421
|
+
|
|
422
|
+
**接口契约(写代码/排障时看这张表)**
|
|
423
|
+
|
|
424
|
+
| 项 | 值 |
|
|
425
|
+
| --- | --- |
|
|
426
|
+
| 地址 | `POST https://api.wkgeo.com/cms/<action>`(`--cms-base` / `WKONGAI_CMS_BASE` 可改;老写法 `/api/cms/<action>` 继续兼容) |
|
|
427
|
+
| 动作名 | 就是云函数动作表的键:`categoryList` / `categorySave` / `contentList` / `contentSave` / `assetSign` / `assetRegister` / `templateGet` / `templateFileSave` / `overview` … |
|
|
428
|
+
| 鉴权 | `Authorization: Bearer <OAuth 令牌>`(从本地凭据取;**不是** Cookie,也不存第二套账号) |
|
|
429
|
+
| 站点 | `x-cms-site: <站点ID>`(**必须是 id**;传域名会被后端当成"没指定")。**没选站时这个头不带** —— 服务端按你的成员关系判定(单站自动走、多站报 400)。body 里**不传** `site_id`(后端故意忽略) |
|
|
430
|
+
| 响应 | 统一信封 `{code, message, data}`,`code === 0` 才算成功(与 `/api/data` 同一个约定) |
|
|
431
|
+
|
|
432
|
+
> ✅ **认证桥已上线(2026-10-18 下午部署,已实测)**:CMS 云函数现在认
|
|
433
|
+
> `Authorization: Bearer <OAuth 令牌>` → 用户 → `cms_site_member`,
|
|
434
|
+
> **与浏览器同一套角色/权限**(额外受 OAuth scope 收紧)。
|
|
435
|
+
> 实测证据(只读命令、真实站点):
|
|
436
|
+
> * `wkgeo categories list --site <站点ID>` → `ok:true`(返回 17 个栏目);
|
|
437
|
+
> * `wkgeo contents list --site <站点ID> --page-size 3` → `ok:true`(`total: 6`);
|
|
438
|
+
> * `wkgeo publish --site <站点ID>` → `ok:true`(读到 6 条已发布);
|
|
439
|
+
> * 不带站点 → 服务端回 `400 这个账号有 N 个站点,请用 x-cms-site 头…` → CLI 译成 `cms_site_required`;
|
|
440
|
+
> * 站点 id 不存在 / 不是成员 → `403` → CLI 译成 `cms_not_member`。
|
|
441
|
+
>
|
|
442
|
+
> 桥上线后 **401 只剩一种含义:令牌无效**(过期/被吊销/客户端被停用)。此时 CLI 仍会给一段
|
|
443
|
+
> 两可的提示(也覆盖"旧部署没启用桥"那种情况),但正常环境下照它 ① 重新 `login` 即可:
|
|
444
|
+
>
|
|
445
|
+
> ```json
|
|
446
|
+
> {"ok":false,"command":"categories list","error":{
|
|
447
|
+
> "kind":"cms_auth","code":401,
|
|
448
|
+
> "message":"CMS 接口没有接受 CLI 的授权令牌(categoryList):…",
|
|
449
|
+
> "hint":"① 最常见的原因是令牌已过期 / 被吊销:运行 `wkgeo login` 重新授权即可;② 若刚授权仍报 401(且 `wkgeo whoami` 正常),说明服务端是**旧部署** —— 还没启用 CLI 认证桥…"},
|
|
450
|
+
> "meta":{"cms_base":"https://api.wkgeo.com/cms","site_file":"…\\.wkongai\\config.json"}}
|
|
451
|
+
> ```
|
|
452
|
+
>
|
|
453
|
+
> 退出码 **3**(与"需要授权"同一档),AI 端据此就能判断"该重新授权"。
|
|
454
|
+
>
|
|
455
|
+
> ⚠️ **升级前授权的旧令牌缺少 CMS 的 scope**(`template:read/write`、`attachment:read/write`):
|
|
456
|
+
> 表现是 `templates list` / `assets list` 报 `cms_scope`(403)。
|
|
457
|
+
> **重新 `wkgeo login` 一次即可** —— CLI 现在的默认 scope 已含这三组,客户端 `allowed_scopes` 也已放开。
|
|
458
|
+
|
|
459
|
+
**输出与安全**
|
|
460
|
+
|
|
461
|
+
* 默认人类可读表格;`--json`(非终端下自动)输出**一个** JSON 信封,`data` 里是原始字段(AI 直接用);
|
|
462
|
+
* `templates get <文件名>` 在人类模式下**直出模板源码**(可以 `> index.html` 存下来);
|
|
463
|
+
* **不打印令牌**;`assets upload` 也不打印 OSS 的 AccessKey(CLI 只拿票据,AK 只在云函数里);
|
|
464
|
+
* 服务端的所有约束**一条都不会被 CLI 放宽**:系统栏目只能隐藏不能删、单页内容只能改不能建、
|
|
465
|
+
绑定模板必须是本站已有的 html、内容 `published` 即上线(前台是服务端按需渲染)。
|
|
466
|
+
|
|
382
467
|
### 「钱包余额支付」到底发生在哪一步(**别被命令名骗了**)
|
|
383
468
|
|
|
384
469
|
服务端 `placeOrder()` 的行为是:**下单时就先用余额抵扣**,余额够就立刻 `moveWallet(-金额)` +
|
|
@@ -448,6 +533,14 @@ wkgeo login --device-continue --json
|
|
|
448
533
|
| `code≥500` | `server` | 1 | 服务端错误,保留原文;可稍后重试 |
|
|
449
534
|
| 连不上/超时 | `network` | 1 | 检查网络;原始 message 会原样保留(如 `getaddrinfo ENOTFOUND`) |
|
|
450
535
|
| 动作未登记(新功能没发版) | `not_deployed` | 1 | **服务端缺口**,不是命令用错(`apps list/revoke` 已实测可用) |
|
|
536
|
+
| CMS 命令:`code=401`(Bearer 令牌未被接受) | `cms_auth` | 3 | 先确认 `wkgeo whoami` 正常;**正常就说明服务端还没启用 CLI 认证桥**(令牌 → CMS 站点成员),找管理员,别反复 `login` |
|
|
537
|
+
| CMS 命令:网关 404 / 响应不是 JSON | `cms_unavailable` | 1 | 多半是 CMS 基址不对或云函数 `cms` 没部署;`wkgeo config` 里看 `cms_base`(`--cms-base` 可临时改) |
|
|
538
|
+
| CMS 命令:403「你不是该站点的成员」 | `cms_not_member` | 1 | 站点选错了 / 还没被邀请:`wkgeo site use <正确站点ID>`;协作站要 owner 先加你 |
|
|
539
|
+
| CMS 命令:403「只读账号不能修改…」 | `cms_readonly` | 1 | 你的站点角色是 viewer:让 owner 在后台「用户与角色」里升为 editor |
|
|
540
|
+
| CMS 命令:403「该令牌没有执行「X」的权限(需要 site:write)」 | `cms_scope` | 1 | 令牌 scope 不够:**重新 `wkgeo login`**(默认已含 site / template / attachment 三组)。升级前的旧令牌不会自动带上新能力 |
|
|
541
|
+
| CMS 命令:400「这个账号有 N 个站点,请用 x-cms-site…」 | `cms_site_required` | 1 | 多站账号必须指定站点:`wkgeo site use <站点ID>` 或本命令加 `--site <站点ID>` |
|
|
542
|
+
| `import`:找不到本机导入脚本 | `import_unavailable` | 1 | 只有本仓库机器上才有 `tencent/cloudbase/import-site.mjs`;或用 `WKONGAI_IMPORT_SCRIPT` 指定路径 |
|
|
543
|
+
| `import`:脚本非 0 退出 | `import_failed` | 1 | 看报错里的日志尾巴(url 打不开 / 目标站不存在 / 没有数据库凭证 / 触发 robots 限制);dry-run 失败不动库 |
|
|
451
544
|
|
|
452
545
|
**所有这些错误都不会打印令牌**:错误里只带 `code` / `message` / `hint`。
|
|
453
546
|
|
|
@@ -460,6 +553,7 @@ wkgeo login --device-continue --json
|
|
|
460
553
|
| 位置 | `~/.wkongai/credentials.json`(Windows:`%USERPROFILE%\.wkongai\credentials.json`);可用 `WKONGAI_CREDENTIALS` 或 `--credentials` 改 |
|
|
461
554
|
| 权限 | 目录 `0700`、文件 **`0600`**。⚠️ 这在 POSIX 上有效;**Windows 上 NTFS 的 `chmod` 基本是空操作**,实际靠用户目录 ACL 保护 —— 这点如实写明,不假装在 Windows 上也成立(`whoami --verbose` 会显示"无法判断(Windows)") |
|
|
462
555
|
| 内容 | `access_token` / `refresh_token` / `scope` / `expires_at` / 账号标识;写入用**原子写**(先写临时文件再 rename,避免半截 JSON) |
|
|
556
|
+
| 站点选择 | **另一个文件**:`<凭据目录>/config.json`(默认 `~/.wkongai/config.json`,`wkgeo site use` 写入)。它只是"操作上下文",**不含秘密**;`logout` 不会删它,重新 `login` 也不会丢 |
|
|
463
557
|
| 令牌 | 30 天有效(`expires_in=2592000`)。CLI **不会**自动刷新(老板口径:过期就重新授权,30 天已经够长) |
|
|
464
558
|
| 绝不出现明文令牌的地方 | 终端输出(含 `--verbose`,只给**掩码** `AbCdEf…(43 位)`)、错误信息、JSON 输出、日志 |
|
|
465
559
|
| 公共客户端 | 代码里**没有 client_secret**,只用 PKCE(`code_verifier` 只在内存里,换票后就丢) |
|
|
@@ -494,7 +588,7 @@ wkgeo login --device-continue --json
|
|
|
494
588
|
| --- | --- | --- |
|
|
495
589
|
| 1 | `wkgeo wallet`(记下当前余额,例如 ¥100.00) | 打印余额与流水 |
|
|
496
590
|
| 2 | `wkgeo wallet recharge --amount-cents 1000 --dry-run` | 只打印"将创建 ¥10.00 订单",**不产生任何订单** |
|
|
497
|
-
| 3 | `wkgeo wallet recharge --amount-cents 1000` | 返回 `order_id` / `code_url` / **`pay_url`**,并**自动在浏览器打开 `pay_url`** —— 也就是我们自己的收银台 `https://pay.wkgeo.com
|
|
591
|
+
| 3 | `wkgeo wallet recharge --amount-cents 1000` | 返回 `order_id` / `code_url` / **`pay_url`**,并**自动在浏览器打开 `pay_url`** —— 也就是我们自己的收银台 `https://pay.wkgeo.com/?order_id=…&token=…` |
|
|
498
592
|
| 4 | 在**收银台页面**用手机微信扫码支付 ¥10.00(人工) | 页面自动检测到支付成功;**支付成功后页面会自动尝试关闭**(关不掉就手动关掉即可);`pay_url` 里的订单号在任何设备/浏览器打开都能看到同一笔单 |
|
|
499
593
|
| 5 | `wkgeo orders check <order_id>` | `paid:true` + **最新余额 = 原余额 + 1000 分** |
|
|
500
594
|
| 6 | `wkgeo wallet txns` | 出现一条 `kind=recharge`、金额 `+¥10.00` 的流水 |
|
|
@@ -527,7 +621,8 @@ wkgeo login --device-continue --json
|
|
|
527
621
|
|
|
528
622
|
### 路径 ③ 网页端能看到账户信息
|
|
529
623
|
|
|
530
|
-
浏览器打开 `https://user.wkgeo.com/`
|
|
624
|
+
浏览器打开 `https://wkgeo.com/user/`(老地址 `https://user.wkgeo.com/` 同样可用)
|
|
625
|
+
→ 登录同一账号 → 依次核对:
|
|
531
626
|
|
|
532
627
|
- **个人中心/账号信息**:邮箱或手机号、昵称与 CLI 里 `whoami` 显示的一致;
|
|
533
628
|
- **钱包/账单**:余额 = `wkgeo wallet` 的余额;订单列表里能看到 CLI 下的单(同一个 `订单号`);
|
|
@@ -593,10 +688,10 @@ node scripts/live-sql.mjs --sql "select …" # 只读查库(只允许 SELECT
|
|
|
593
688
|
设备码这条路的**真环境**端到端验证在云函数测试目录(默认只读,实跑需显式开关):
|
|
594
689
|
|
|
595
690
|
```bash
|
|
596
|
-
node
|
|
691
|
+
node tencent/functions/_tests/oauth-device-live-e2e.js # 只读预检(零副作用)
|
|
597
692
|
$env:OAUTH_DEVICE_E2E_LIVE='1' # 实跑:造临时用户 + 真跑 CLI
|
|
598
693
|
$env:OAUTH_DEVICE_E2E_CONFIRM='yes-i-accept-creating-a-temp-user'
|
|
599
|
-
node
|
|
694
|
+
node tencent/functions/_tests/oauth-device-live-e2e.js # 结束按 sub 全量清理并回读复核
|
|
600
695
|
```
|
|
601
696
|
|
|
602
697
|
环境变量(都有默认值,通常不用设):
|
|
@@ -604,9 +699,9 @@ node cloudfunctions/_tests/oauth-device-live-e2e.js # 结束
|
|
|
604
699
|
| 变量 | 默认 | 说明 |
|
|
605
700
|
| --- | --- | --- |
|
|
606
701
|
| `WKONGAI_BASE` | 线上网关 | API 基址 |
|
|
607
|
-
| `WKONGAI_OAUTH_WEB_BASE` | `https://
|
|
608
|
-
| `WKONGAI_PAY_WEB_BASE` | `https://pay.wkgeo.com` | **收银台**基址(`pay_url`
|
|
609
|
-
| `WKONGAI_USER_WEB_BASE` | `https://
|
|
702
|
+
| `WKONGAI_OAUTH_WEB_BASE` | `https://wkgeo.com/oauth` | **授权站**基址(同意页 / 设备码页兜底地址)。2026-10-18 域名统一到路径后默认走新路径;老地址 `https://oauth.wkgeo.com` 仍可用,回滚就把它设成老地址 |
|
|
703
|
+
| `WKONGAI_PAY_WEB_BASE` | `https://pay.wkgeo.com` | **收银台**基址(`pay_url` 的域名;**支付独立,路径化没动**) |
|
|
704
|
+
| `WKONGAI_USER_WEB_BASE` | `https://wkgeo.com/user` | **会员站**基址(登录页 / 我的订单等)。老地址 `https://user.wkgeo.com` 仍可用 |
|
|
610
705
|
| `WKONGAI_WEB_BASE` | 未设置 | ⚠️ **总覆盖**:设了它上面三个基址**全部**用它(联调 / 回滚用)。它**不再**指向老站 |
|
|
611
706
|
| `WKONGAI_CLIENT_ID` | `wkgeo-cli` | OAuth 客户端 id |
|
|
612
707
|
| `WKONGAI_SCOPE` | `site:read site:write billing:self` | 申请的能力 |
|
|
@@ -636,6 +731,11 @@ node cloudfunctions/_tests/oauth-device-live-e2e.js # 结束
|
|
|
636
731
|
| 9 | **真实微信支付全流程** | 按红线**没有**跑真钱:`wallet recharge` 只用离线桩验证了请求体,真钱路径由老板手动测(§7 路径②) | 人工 |
|
|
637
732
|
| 10 | **exe 产物** | 只验证了 `--sea` 能生成 blob + 复制 node 壳(93MB),**没有**真装 postject 注入、也没在无 Node 机器上跑 | 需要时再做 |
|
|
638
733
|
| 11 | **`login` 的浏览器交互本身** | 真环境验证脚本扮演了"浏览器/同意页"的角色(调 authorize/consent),**HTML 页面本身的点击**没有被自动化覆盖(同意页由前端/另一个改动负责) | 人工(§7 路径①) |
|
|
734
|
+
| 12 | **CMS 认证桥(Bearer → 站点成员)** | ✅ **已上线并实测**(2026-10-18 下午):`categories list` / `contents list` / `publish` 用 Bearer + `x-cms-site` 真跑成功;多站未指定 → 400(CLI 译成 `cms_site_required`)。⚠️ 15:15 首次实测时线上还是旧函数(401 老文案),15:22 复测已通 —— 排障时先看 401 的**文案** | 已完成(后端 `resolveIdentity`) |
|
|
735
|
+
| 13 | **CMS 写操作 / 导入没有真接口验证** | 只读命令已真跑;**写操作**(建栏目/发内容/传素材/存模板)与**导入**没有真跑(会改数据/需数据库凭证)。它们由 66 条离线单测覆盖,**不声称已端到端验证** | 需要时人工验收(写库前先 `site use` 选对站) |
|
|
736
|
+
| 13b | **旧令牌缺 CMS scope** | 2026-10-18 之前授权的令牌只有 `site:read/site:write/billing:self` ⇒ `templates list` / `assets list` 报 `cms_scope`(403)。**重新 `wkgeo login` 即可**(默认 scope 与客户端 `allowed_scopes` 都已补齐) | 用户侧一次重新授权 |
|
|
737
|
+
| 14 | **`import` 走本机运维脚本** | 后端**没有**带鉴权的 HTTP 导入入口,CLI 调用本仓库的 `tencent/cloudbase/import-site.mjs`(`service_role` 直连库,需运维权限)。命令默认 dry-run、只增不毁;客户/AI 端不应当用它 | 后端补 HTTP 导入动作(`docs/规划-CLI与AI建站.md` §5.2) |
|
|
738
|
+
| 15 | **静态发布 / 客户自有域名** | `publish` 只报状态并解释"渲染即生效",**不做**静态化与 CDN 推送 —— 缺"按站点 ID 幂等发布"的后端动作 | 后端(`规划-Agent与开放接口.md` 第 4 条) |
|
|
639
739
|
|
|
640
740
|
### 9.1 ⚠️ 设备码页"没有完成态 / 不自动关"(**建议改法,本轮 CLI 侧未改动**)
|
|
641
741
|
|
|
@@ -679,3 +779,20 @@ A:服务端设计如此:下单时余额够就直接扣款并履约(返回
|
|
|
679
779
|
**Q:`sites create` 报「无法确定所属客户」?**
|
|
680
780
|
A:这是账号属性问题(`owner/admin` 这类 `data_scope != 'self'` 的账号必须显式指定客户):
|
|
681
781
|
加 `--customer <客户ID>` 重试(客户 ID 在网页后台的客户列表里)。
|
|
782
|
+
|
|
783
|
+
**Q:`categories list` 报 401 / `cms_auth`?**
|
|
784
|
+
A:认证桥**已上线**(2026-10-18 下午实测通过),所以 401 现在基本只有一种含义:**令牌无效**
|
|
785
|
+
(过期 / 被吊销 / 客户端被停用)→ `wkgeo login` 重新授权即可。
|
|
786
|
+
只有当服务端还是**旧部署**(没启用 Bearer 桥)时,才会出现"`whoami` 正常、CMS 却一律 401",
|
|
787
|
+
这时才需要找管理员确认部署(CLI 侧不用改,也不用反复登录)。
|
|
788
|
+
|
|
789
|
+
**Q:CMS 命令报 `cms_site_required`(账号有多个站点)?**
|
|
790
|
+
A:那就是"没指定站点、而你有多个成员站"——服务端不替你猜。
|
|
791
|
+
先选一次:`wkgeo site use <站点ID或域名>`(存进 `~/.wkongai/config.json`);
|
|
792
|
+
多站来回切时不必改本地记录:任意命令加 `--site <站点ID>` 只影响这一次。
|
|
793
|
+
⚠️ `--site` **只认站点 ID(uuid)**;域名请先用 `site use <域名>` 解析。
|
|
794
|
+
(只属于**一个**站点的账号不用选:不带站点头时服务端会直接用那唯一一个。)
|
|
795
|
+
|
|
796
|
+
**Q:`assets upload` 会让我填 OSS 的 AK 吗?**
|
|
797
|
+
A:**不会**。流程是"云函数签一张 10 分钟的直传票据 → CLI 按票据把文件 POST 到 OSS → 回云函数登记"。
|
|
798
|
+
CLI 侧既不保存也不打印 AccessKey(和"桌面/CLI 永远拿不到 AK"同一条边界)。
|
package/SKILL.md
CHANGED
|
@@ -23,6 +23,10 @@ version: 0.2.0
|
|
|
23
23
|
* 用户说"**帮我下单**"/"买加量包"/"扩容空间"/"买流量" → `products list` → `orders create`
|
|
24
24
|
* 用户说"**用钱包付**"/"余额支付"/"帮我付钱" → `orders create`(余额够会**当场付清**)+ `wallet` 复核
|
|
25
25
|
* 用户说"**充值**"/"充 100 块" → `wallet recharge`(下单后**自动打开我们网站的收银台页面**,用户在那里扫码支付)
|
|
26
|
+
* 用户说"**充值**"但**没说金额**、或说"**我自己选金额**"/"给我个充值链接" → `wallet recharge-link`
|
|
27
|
+
(生成**独立充值页**链接:`https://pay.wkgeo.com/recharge/?ticket=…`,用户在网页上自己选金额
|
|
28
|
+
—— ¥10 / ¥20 快捷,或自定义,**最低 ¥9.90、不设上限** —— 然后扫码支付;**不需要登录会员中心**。
|
|
29
|
+
默认**不**弹浏览器:把 `data.pay_url` 原样交给用户即可。⛔ 不要用它代替用户付款。)
|
|
26
30
|
* 用户说"**查余额**"/"我的钱包"/"账单流水" → `wallet` / `wallet txns`
|
|
27
31
|
* 用户说"**我的订单**"/"订单状态" → `orders list` / `orders get` / `orders check`
|
|
28
32
|
* 用户说"**我授权过哪些应用**"/"取消某个应用的授权" → `apps list` / `apps revoke`
|
|
@@ -113,6 +117,7 @@ npx -y wkgeo-cli@latest skill > SKILL.md # 直接落一份到本地,离线
|
|
|
113
117
|
| `wallet` | 余额 + 最近流水 | `--limit` `--entitlements` |
|
|
114
118
|
| `wallet txns` | 钱包流水 | `--limit` |
|
|
115
119
|
| `wallet recharge` | 充值下单,**并打开我们网站的收银台页面**扫码支付(**不扣款**) | `--amount-cents`(分,必填)、`--no-browser`、`--open-browser`、`--dry-run` |
|
|
120
|
+
| `wallet recharge-link` | 生成**独立充值页**链接(用户在网页上**自己选金额**并扫码支付;**不扣款**、不建单) | `--open-browser`(默认**不**弹)、`--no-browser` |
|
|
116
121
|
| `products list` | 能买什么 | — |
|
|
117
122
|
| `orders create` | 下单(余额够**当场付清**) | `--product <代码>` `--units <份数>`(或 `--quota <键>` `--amount <数量>`)`--allow-wechat` |
|
|
118
123
|
| `orders check` | 查支付结果 + 最新余额 | `<订单ID>` |
|
|
@@ -121,8 +126,21 @@ npx -y wkgeo-cli@latest skill > SKILL.md # 直接落一份到本地,离线
|
|
|
121
126
|
| `orders list` | 我的订单 | `--limit` `--offset` `--status` |
|
|
122
127
|
| `apps list` | 我授权过的应用 | — |
|
|
123
128
|
| `apps revoke` | 一键吊销某应用授权(令牌立即失效) | `<client_id>` |
|
|
129
|
+
| `site use` | **选中要操作的站点**(存本地,之后的 CMS 命令默认用它;不带参数 = 看当前) | `<站点ID或域名>`、`--clear` |
|
|
130
|
+
| `categories list/get/create/update/delete` | 栏目:列表 / 详情 / 新建 / 改 / 删 | 见 §7.5 |
|
|
131
|
+
| `categories bind-template` | 给栏目绑定模板 html(`--clear` 解绑) | `<栏目>` `<模板文件>`、`--clear` |
|
|
132
|
+
| `contents list/get/create/update/delete` | 内容:列表 / 详情 / 新建 / 改 / 删 | 见 §7.5 |
|
|
133
|
+
| `assets list` / `assets upload` | 素材:列表 / 上传(签名 → 直传 OSS → 登记) | `assets upload <文件>`、`--name` |
|
|
134
|
+
| `templates list/get/save` | 模板:清单 / 看源码(直出)/ 保存 | `templates get <文件>`、`templates save <文件> --file <本地>` |
|
|
135
|
+
| `publish` | **看发布状态**(前台按需渲染:`published` 即上线,没有额外发布步骤) | — |
|
|
136
|
+
| `import` | 老站导入(**默认 dry-run**;走本机运维脚本,**需运维权限**) | `--url`(必填)、`--apply`、`--site` |
|
|
124
137
|
| `skill` | **打印给 AI 端的操作手册**(本文件原文,随包分发) | `--json`(默认纯文本原文;不受"非终端自动 JSON"影响) |
|
|
125
138
|
|
|
139
|
+
> CMS 命令(`categories` / `contents` / `assets` / `templates` / `publish`)都要先确定站点:
|
|
140
|
+
> `--site <站点ID>` > 环境变量 `WKONGAI_SITE` > 本地 `wkgeo site use`
|
|
141
|
+
> > **都没有时不带站点头**(服务端用你唯一的成员站;多站会报 `cms_site_required` 让你指定)。
|
|
142
|
+
> ⚠️ `--site` **只认 uuid**;域名先 `wkgeo site use <域名>` 解析。
|
|
143
|
+
|
|
126
144
|
### 示例:成功
|
|
127
145
|
|
|
128
146
|
```bash
|
|
@@ -173,6 +191,13 @@ $ npx -y wkgeo-cli@latest orders create --product storage_gb --units 10
|
|
|
173
191
|
|
|
174
192
|
## 5. 授权流程(**必须让用户动手的那一步**)
|
|
175
193
|
|
|
194
|
+
> ★ **2026-10-18 域名统一到路径**:授权站 canonical 从 `https://oauth.wkgeo.com/` 改成
|
|
195
|
+
> **`https://wkgeo.com/oauth/`**(同意页 `/oauth/authorize/`、设备码页 `/oauth/device/`)。
|
|
196
|
+
> 老子域**继续可用**(老板要求并存);CLI 以 `WKONGAI_OAUTH_WEB_BASE` 为 canonical,
|
|
197
|
+
> 服务端 metadata 只提供路径 —— 所以**服务端还没部署新地址时,CLI 打印的也是新地址**。
|
|
198
|
+
> 回滚一条环境变量即可:`WKONGAI_OAUTH_WEB_BASE=https://oauth.wkgeo.com`(不用改代码)。
|
|
199
|
+
> ⚠️ 给用户看的地址**原样转述**,别自己把 `wkgeo.com/oauth` 改回 `oauth.wkgeo.com` 去"纠错"。
|
|
200
|
+
|
|
176
201
|
### 5.1 本地回调模式(默认)
|
|
177
202
|
|
|
178
203
|
```bash
|
|
@@ -188,7 +213,7 @@ npx -y wkgeo-cli@latest login --json --timeout 500ms # 也可以显式写毫
|
|
|
188
213
|
// 第一行 —— 拿到它就应该**立刻**把网址交给用户(不要等命令结束!)
|
|
189
214
|
// ⚠️ `authorize/` 的**尾斜杠不能丢**:它是托管侧 302(会丢掉全部 query)的分界线
|
|
190
215
|
{"ok":true,"command":"login","mode":"callback","stage":"awaiting_callback",
|
|
191
|
-
"authorization_url":"https://
|
|
216
|
+
"authorization_url":"https://wkgeo.com/oauth/authorize/?client_id=wkgeo-cli&…",
|
|
192
217
|
"redirect_uri":"http://127.0.0.1:53682/callback","scope":"site:read site:write billing:self",
|
|
193
218
|
"timeout_ms":300000,
|
|
194
219
|
"user_action_required":"请让用户在浏览器中打开上面的 authorization_url,登录并点「同意」"}
|
|
@@ -254,7 +279,7 @@ npx -y wkgeo-cli@latest login --json --timeout 500ms # 也可以显式写毫
|
|
|
254
279
|
# ① 交互式终端 / 你有长超时能力:一口气跑完(阻塞,最多 expires_in 秒)
|
|
255
280
|
npx -y wkgeo-cli@latest login --device --json
|
|
256
281
|
# → {"stage":"awaiting_user","user_code":"ABCD-1234",
|
|
257
|
-
# "verification_uri":"https://
|
|
282
|
+
# "verification_uri":"https://wkgeo.com/oauth/device/",
|
|
258
283
|
# "verification_uri_complete":"…/?user_code=ABCD-1234","open_url":"…",
|
|
259
284
|
# "expires_in":600,"interval":5,"paste_text":"请打开 … 并完成「同意授权」(短码:ABCD-1234)。",
|
|
260
285
|
# "user_action_required":"请让用户访问 … 并输入短码 ABCD-1234"}
|
|
@@ -450,6 +475,14 @@ Set-Content -LiteralPath "$env:USERPROFILE\.dsh\browser-open.txt" -Value "<完
|
|
|
450
475
|
| `not_found` / `404` | 订单/站点/产品不存在 | 用 `orders list` / `products list` 重新确认 ID |
|
|
451
476
|
| `bad_request` / `400` | 参数不对 | 按 `message` 修正参数;别硬改着重试 |
|
|
452
477
|
| `not_deployed` | 该接口服务端还没发布 | 告诉用户"这是服务端缺口",不要反复重试 |
|
|
478
|
+
| `cms_auth` / `401`(CMS 命令) | CMS 没接受 Bearer 令牌:通常是**令牌无效**(过期/吊销/客户端停用);只有旧部署才会是"没启用 CLI 认证" | 先 `wkgeo login` 重新授权一次(正常环境一定能解决);仍不行再用 `whoami` 判断是否服务端旧部署,让管理员确认(**不要**反复登录十几次) |
|
|
479
|
+
| `cms_site_required` / `400` | 账号有多个站点,没指定 | 先问用户是哪个站,再 `site use <站点ID>` 或 `--site <站点ID>` |
|
|
480
|
+
| `cms_not_member` / `403` | 不是该站成员 / 站点 id 不对 | 让用户确认站点(`site use` 重选);协作站要 owner 先加成员 |
|
|
481
|
+
| `cms_readonly` / `403` | 站点角色是 viewer(只读) | 让 owner 在后台「用户与角色」里升为 editor;**不要**换令牌硬试 |
|
|
482
|
+
| `cms_scope` / `403` | 令牌 scope 不够(如 `template:write`) | 需要更高授权:`login --scope "<原有 + 缺的>"`;已知官方 CLI 客户端没放开 `template:write` / `attachment:delete` |
|
|
483
|
+
| `cms_unavailable` | CMS 地址不通 / 云函数没部署 / 返回不是 JSON | 检查 `wkgeo config` 的 `cms_base`;多半是服务端没部署,告诉用户"后台暂时连不上" |
|
|
484
|
+
| `import_unavailable` | 本机没有 `tencent/cloudbase/import-site.mjs` | 告诉用户"老站导入需要运维权限/本仓库环境",**不要**承诺普通客户能用 |
|
|
485
|
+
| `import_failed` | 导入脚本非 0 退出 | 念 `hint` 与日志尾巴;dry-run 失败不动库,可安全重试 |
|
|
453
486
|
| `missing_skill` | `skill` 在本包里找不到 `SKILL.md`(包被裁剪/只拷了 `lib/`) | 换官方包 `npx -y wkgeo-cli@latest skill`;**不是**命令用错了,别让用户去排查 |
|
|
454
487
|
| `server` / `5xx` | 服务端错误 | 保留原文告知用户,可稍后重试 |
|
|
455
488
|
| `network` | 连不上/超时 | 检查网络后重试;`message` 里是原始错误(如 `getaddrinfo ENOTFOUND`) |
|
|
@@ -493,7 +526,7 @@ npx -y wkgeo-cli@latest wallet txns --limit 3
|
|
|
493
526
|
```bash
|
|
494
527
|
npx -y wkgeo-cli@latest wallet recharge --dry-run --amount-cents 10000 # 先彩排,确认金额
|
|
495
528
|
npx -y wkgeo-cli@latest wallet recharge --amount-cents 10000 # 生成待支付订单,并把收银台地址交出来(不扣款)
|
|
496
|
-
# ★ 读 data.pay_url —— 这是**我们网站的收银台页面**(https://pay.wkgeo.com
|
|
529
|
+
# ★ 读 data.pay_url —— 这是**我们网站的收银台页面**(https://pay.wkgeo.com/?order_id=…&token=…)。
|
|
497
530
|
# ⚠️ **不要把 data.code_url 当成主流程丢给用户自己想办法**(那是微信内部支付链接,
|
|
498
531
|
# 手机直接扫不了;终端二维码只是"网页打不开"时的兜底)。
|
|
499
532
|
# ★ `token=` 是服务端在下单那一刻签发的**订单支付令牌**(只对这一单有效):
|
|
@@ -527,6 +560,29 @@ npx -y wkgeo-cli@latest orders check <order_id> # 用
|
|
|
527
560
|
⚠️ 打开 `pay_url` 的方式见 **§5.5**:CLI **默认就会尝试弹系统浏览器**(老板最终拍板走传统路线);
|
|
528
561
|
只有它**没打开成功**时,才考虑可选地在客户端**内置浏览器 / 侧边面板**里打开。
|
|
529
562
|
|
|
563
|
+
#### 7.2.1 另一种:**让用户自己选金额**(`wallet recharge-link`,独立充值页)
|
|
564
|
+
|
|
565
|
+
用户**没给金额**、或说"我自己选"/"给我个充值链接"时用它。它**不建单、不定金额**,
|
|
566
|
+
只换一张**一次性 ticket** 并给出链接:
|
|
567
|
+
|
|
568
|
+
```bash
|
|
569
|
+
npx -y wkgeo-cli@latest wallet recharge-link # 默认不弹浏览器:交接物就是链接本身
|
|
570
|
+
# ★ 读 data.pay_url —— 形如 https://pay.wkgeo.com/recharge/?ticket=…
|
|
571
|
+
# 把它**原样**发给用户(或做成可点的链接)。他在那一页上:
|
|
572
|
+
# 选金额(¥10 / ¥20 快捷,或自定义;最低 ¥9.90、**不设上限**)→ 提交 → 微信扫码支付。
|
|
573
|
+
# ⚠️ **不需要登录会员中心** —— 凭证就是地址里的 ticket,整条链路与登录态无关。
|
|
574
|
+
# ★ data.paste_text 是"照着念"的一句话(含完整地址),直接转述,别自己组织语言。
|
|
575
|
+
# ★ 有效期只有 10 分钟、且**用掉即失效**(一次性):过期/已用过时页面会明确提示"请重新获取",
|
|
576
|
+
# 这时**重新跑一次本命令**拿一条新链接即可(不要反复让用户刷新旧链接)。
|
|
577
|
+
# ★ 默认**不**打开浏览器(这条命令通常跑在服务器/容器里,且交接物是链接);
|
|
578
|
+
# 确实要在本机弹出时加 --open-browser;--no-browser 优先级最高。
|
|
579
|
+
# ★ ticket 只是"建一笔充值单"的窄凭证:⛔ 不要把它当登录凭据、不要拿它去调别的 action。
|
|
580
|
+
npx -y wkgeo-cli@latest orders check <order_id> # 用户说付完了再查(order_id 从他那句"付完了"对应的单拿)
|
|
581
|
+
```
|
|
582
|
+
|
|
583
|
+
⚠️ **AI 永远不要替用户"确认支付成功"**:只能查。查不到就是没付。
|
|
584
|
+
⚠️ 别把 `ticket` 单独展示成"验证码"念出来:它是**链接的一部分**,原样交付整条链接即可。
|
|
585
|
+
|
|
530
586
|
### 7.3 用户说"查一下我的余额和订单"
|
|
531
587
|
|
|
532
588
|
```bash
|
|
@@ -559,6 +615,61 @@ npx -y wkgeo-cli@latest apps revoke <client_id> # 该应用所有令牌立
|
|
|
559
615
|
|
|
560
616
|
---
|
|
561
617
|
|
|
618
|
+
### 7.5 用户说"帮我在站上发一篇文章 / 换个模板 / 传张图"
|
|
619
|
+
|
|
620
|
+
**这是 CMS 面**(客户站后台的同一批接口)。⛔ 不要用 `orders` / `sites` 那套平台接口去做内容。
|
|
621
|
+
|
|
622
|
+
```bash
|
|
623
|
+
# ① 先定站点(只属于一个站的账号可以跳过;多站必须先选,否则会报 cms_site_required)
|
|
624
|
+
npx -y wkgeo-cli@latest site use 8f3c1a2e-4b5d-4f6a-8b7c-9d0e1f2a3b4c # 或 www.example.com
|
|
625
|
+
npx -y wkgeo-cli@latest site use --json # 看当前选中的是哪个站
|
|
626
|
+
|
|
627
|
+
# ② 看结构(栏目 = 导航;内容挂在栏目下)
|
|
628
|
+
npx -y wkgeo-cli@latest categories list --json # 读 data.rows[].id / name / path / kind / template_path
|
|
629
|
+
|
|
630
|
+
# ③ 写内容(默认草稿;--status published 就立刻在前台可见)
|
|
631
|
+
npx -y wkgeo-cli@latest contents create --category 新闻 --title "公司参展 2026" \
|
|
632
|
+
--body "<p>正文…</p>" --status draft --json
|
|
633
|
+
# 读 data.content.id / status
|
|
634
|
+
# 正文较长时用 --body-file ./article.html(避免命令行转义地狱)
|
|
635
|
+
# 自定义字段用 --ext '{"型号":"X1"}'(键就是后台「字段管理」里的键)
|
|
636
|
+
|
|
637
|
+
# ④ 传图(三步:签名 → 直传 OSS → 登记;CLI 不碰 AK)
|
|
638
|
+
npx -y wkgeo-cli@latest assets upload ./banner.jpg --json # 读 data.asset.id
|
|
639
|
+
npx -y wkgeo-cli@latest contents update <内容ID> --cover <素材ID> --json
|
|
640
|
+
|
|
641
|
+
# ⑤ 改版式(模板是整段 html;改了先备份)
|
|
642
|
+
npx -y wkgeo-cli@latest templates list --json # 读 data.files[].path
|
|
643
|
+
npx -y wkgeo-cli@latest templates get index.html > index.html # 人类模式直出源码(备份)
|
|
644
|
+
npx -y wkgeo-cli@latest templates save index.html --file ./index.html --json
|
|
645
|
+
npx -y wkgeo-cli@latest categories bind-template /about/ about.html --json
|
|
646
|
+
|
|
647
|
+
# ⑥ 看发布状态(前台按需渲染:published 即上线,**没有**"发布"这一步)
|
|
648
|
+
npx -y wkgeo-cli@latest publish --json
|
|
649
|
+
```
|
|
650
|
+
|
|
651
|
+
**怎么把这些命令的失败讲给用户**(`--json` 的 `error.kind`):
|
|
652
|
+
|
|
653
|
+
| kind | 真实含义 | 对用户怎么说 |
|
|
654
|
+
|---|---|---|
|
|
655
|
+
| `cms_site_required` | 他有多个站点,得说清是哪个 | "你的账号有多个站,这次要改哪一个?" |
|
|
656
|
+
| `cms_auth` | 令牌没被 CMS 接受(多半过期/吊销;旧部署才可能是"没启用 CLI 认证") | "内容后台说我的登录失效了,我帮你重新授权一次"(跑 `login`) |
|
|
657
|
+
| `cms_not_member` | 不是这个站的成员 / 站点 id 不对 | "这个站我没有权限,帮我确认一下是哪个站?" |
|
|
658
|
+
| `cms_readonly` | 他的站点角色是只读 | "你在这个站是只读权限,要改成能编辑得找站长加一下" |
|
|
659
|
+
| `cms_scope` | 令牌能力不够(如模板保存要 `template:write`) | "这个操作需要更高的授权范围,得重新授权一次(或让管理员放开)" |
|
|
660
|
+
| `cms_unavailable` | CMS 地址不通 / 云函数没部署 | "内容后台暂时连不上,可能要等运维部署" |
|
|
661
|
+
| `not_deployed` | 服务端版本落后(没有这个动作) | "后台那边还没更新到这个功能,稍后再试" |
|
|
662
|
+
|
|
663
|
+
**铁律(CMS 面)**:
|
|
664
|
+
|
|
665
|
+
1. **先 `site use` 或 `--site`** —— 改错站的代价比多问一句高得多;
|
|
666
|
+
2. **写内容默认草稿**(`--status draft`),用户明确说"发出去"才用 `published`;
|
|
667
|
+
3. **不要顺手删**:`contents delete` / `categories delete` 前必须让用户确认对象(标题 + 栏目);
|
|
668
|
+
4. **单页栏目**(`kind=page`)的内容只能改不能建;用户要"加一页"= 加子栏目,不是建内容;
|
|
669
|
+
5. `import`(老站导入)**默认 dry-run**、且需要运维权限 —— 不要对普通客户承诺"我能直接导"。
|
|
670
|
+
|
|
671
|
+
---
|
|
672
|
+
|
|
562
673
|
## 8. 安全(**必须遵守**)
|
|
563
674
|
|
|
564
675
|
1. **绝不打印/转述令牌**:不要 `cat ~/.wkongai/credentials.json`,不要把它放进任何请求体或日志。
|
|
@@ -570,7 +681,7 @@ npx -y wkgeo-cli@latest apps revoke <client_id> # 该应用所有令牌立
|
|
|
570
681
|
5. **不要发起真实扣款**:`login`/`wallet recharge` 只创建订单/链接;
|
|
571
682
|
所有"付款"都必须由用户在**我们网站的收银台页面**用微信完成。自动化测试里**绝不**走真钱路径。
|
|
572
683
|
6. **收银台是我们自己的页面**:`wallet recharge` 的正确交接物是 `pay_url`
|
|
573
|
-
(`https://pay.wkgeo.com
|
|
684
|
+
(`https://pay.wkgeo.com/?order_id=…`),不是 `code_url`。
|
|
574
685
|
不要在本地自己画一个二维码页面让用户扫 —— 那是被明确否掉的做法。
|
|
575
686
|
7. **限流是保护,不是故障**:429 时按 `retry_after` 退避;**不要**用重新登录或换令牌来"绕过"限流。
|
|
576
687
|
8. 遇到 `client_secret`、`authorization_code`、`access_token` 之类的字段:
|
|
@@ -592,7 +703,23 @@ npx -y wkgeo-cli@latest apps revoke <client_id> # 该应用所有令牌立
|
|
|
592
703
|
| `login --device-continue` 报 `kind:"expired"` | 短码过期(默认 10 分钟)或已被换过票 | 重新 `login --device --no-wait` 申请新短码;**别**反复续跑 |
|
|
593
704
|
| 下单直接返回 `paid:true` | 服务端设计:下单时余额足够就直接扣款并履约 | 这是正常的"钱包支付";用 `wallet` 复核余额 |
|
|
594
705
|
| `sites create` 报 400「无法确定所属客户」 | `owner/admin` 这类账号必须显式指定客户 | 加 `--customer <客户ID>` |
|
|
706
|
+
| CMS 命令报 `cms_auth`(401) | 令牌失效(过期/吊销/客户端停用);旧部署才可能是"没启用 CLI 认证桥" | 先 `wkgeo login` 重新授权一次;仍 401 再让管理员确认服务是否为新版(**别**反复 login) |
|
|
707
|
+
| CMS 命令报 `cms_site_required` | 账号有多个站点、没指定 | `wkgeo site use <站点ID>` 或加 `--site <站点ID>` |
|
|
708
|
+
| `--site` 写了域名没生效 | 后端只按**站点 id** 查,域名会被当成"没指定" | 先 `wkgeo site use <域名>` 解析成 id(CLI 已在本地挡住这种写法) |
|
|
709
|
+
| `templates save` / `assets list` 报 403 `cms_scope` | 令牌是**升级前签的**,缺 `template:*` / `attachment:*`(客户端与默认 scope 现已放开) | 让用户重新授权一次:`login`(默认就带全部所需能力);**不是** bug,也别改用别的通道 |
|
|
710
|
+
| `assets upload` 报 403 | 令牌缺 `attachment:write`(或站点角色只读) | 看 `error.kind`:`cms_scope` → 重新授权;`cms_readonly` → 找 owner 提权 |
|
|
711
|
+
| `import` 报 `import_unavailable` | 本机没有 `tencent/cloudbase/import-site.mjs`(npx 装的包里没有它) | 只能在本仓库机器上跑;**不要**对客户承诺"我能直接导" |
|
|
595
712
|
| 429 | 调用过于频繁 | 等 `retry_after` 秒;**不要**重新授权 |
|
|
596
713
|
| `apps list` 报"未部署" | 该环境的 data 云函数还没发版(**线上已发版并实测过**,见 README §9) | 告诉用户"这是服务端缺口",不要反复重试;`logout` 仍可清理本地登录态 |
|
|
597
714
|
| `skill` 报「当前安装包里没有手册文件(SKILL.md)」 | 跑的是**被裁剪的包**或只拷了 `lib/` 的开发目录(正常 npm 包一定有) | 换 `npx -y wkgeo-cli@latest skill`;这不是命令用错了(`error.kind="missing_skill"`,退出码 1) |
|
|
598
715
|
| 想升级 CLI | 全局安装不会自动升级 | 用 `npx -y wkgeo-cli@latest`,或 `npm i -g wkgeo-cli@latest` |
|
|
716
|
+
|
|
717
|
+
## 云端能力(阿里云侧由云函数执行,CLI 不持有 AK)
|
|
718
|
+
|
|
719
|
+
绑域名 / 新建 ESA 站点 / 传 OSS / 发布边缘函数 / 查配额这些**阿里云侧操作**,
|
|
720
|
+
一律通过云端管理接口(FC 函数 `wkgeo-admin`)完成 —— **CLI 与桌面都不持有阿里云 AK**。
|
|
721
|
+
|
|
722
|
+
- 能力清单、权限范围(scope)、请求头要求、curl 示例、已知坑:`aliyun/fc/wkgeo-admin/README.md`
|
|
723
|
+
- 背景与验证记录:`docs/建站-云端管理接口.md`
|
|
724
|
+
- 地址 `https://wkgeo-admin-nyvdudigpb.cn-shanghai.fcapp.run`;必带 `Authorization: Bearer <平台签发的 JWT>` 与 `Date`(RFC1123)
|
|
725
|
+
- scope:`read` / `domain:bind` / `site:create` / `kv:write` / `oss:write` / `routine:deploy`
|
package/lib/args.mjs
CHANGED
|
@@ -20,6 +20,11 @@ import { UsageError } from './errors.mjs';
|
|
|
20
20
|
/** 全局标志:任何命令都接受(写在 spec 之外,避免每个命令重复声明) */
|
|
21
21
|
export const GLOBAL_FLAGS = {
|
|
22
22
|
base: { type: 'string', desc: 'API 基址(默认线上网关,可用 WKONGAI_BASE 覆盖)' },
|
|
23
|
+
/**
|
|
24
|
+
* CMS 面是**另一个云函数 / 另一个域名**(新写法 `https://api.wkgeo.com/cms`),
|
|
25
|
+
* 所以单独给一个基址开关:联调 / 换环境时不用去改平台面的 `--base`。
|
|
26
|
+
*/
|
|
27
|
+
'cms-base': { type: 'string', desc: 'CMS 接口基址(默认 https://api.wkgeo.com/cms,可用 WKONGAI_CMS_BASE 覆盖)' },
|
|
23
28
|
'web-base': { type: 'string', desc: '前端基址(授权页兜底地址)' },
|
|
24
29
|
'client-id': { type: 'string', desc: 'OAuth 客户端 id(默认 wkgeo-cli)' },
|
|
25
30
|
scope: { type: 'string', desc: '申请的能力范围(空格分隔)' },
|
package/lib/cli.mjs
CHANGED
|
@@ -98,6 +98,11 @@ export async function run(argv = [], io = {}) {
|
|
|
98
98
|
*/
|
|
99
99
|
platform: io.platform,
|
|
100
100
|
exec: io.exec,
|
|
101
|
+
/**
|
|
102
|
+
* `wkgeo import` 起子进程的注入点(同步;生产默认 `spawnSync`)。
|
|
103
|
+
* 单测注入它就能验证"脚本参数怎么拼、退出码怎么转述",不真的去起子进程抓网站。
|
|
104
|
+
*/
|
|
105
|
+
runScript: io.runScript,
|
|
101
106
|
/** 同上:`skill` 手册位置的注入点(单测验证"包里没有手册"分支时用,见 lib/commands/skill.mjs) */
|
|
102
107
|
skillUrl: io.skillUrl,
|
|
103
108
|
});
|